码迷,mamicode.com
首页 > 其他好文 > 详细

图像基础操作(含代码)

时间:2015-08-02 18:20:42      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:c++   图像处理   

打开BMP格式图像文件

BMP文件分为BITMAPFILEHEADERBITMAPINFORHEADERRGBQUAD三部分文件头BF包含文件的类型,文件的大小,位图数据距文件头的偏移量等,BI是说明位图的信息,有位图的颜色位数biBitCount,位图的高度宽度,以及位图数据的大小,通过读取BMP格式文件的这些信息,就能对其进行解码,打开BMP文件。

例程:

//选取文件
LPCTSTR lpszFilter = "BMP Files(*.bmp)|*.bmp|任何文件|*.*||";
CFileDialog dlg1(TRUE,lpszFilter,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,lpszFilter,NULL);
CString filename;
CFile file;
if(dlg1.DoModal()==IDOK)
{
//读入文件
filename = dlg1.GetPathName();
if(file.Open(filename,CFile::modeRead|CFile::shareDenyNone,NULL)==0)
{
AfxMessageBox("无法打开文件",MB_OK,0);
    return;
}
 
//读取文件头,将大小为sizeof(bf)的数据传入缓冲区bf
file.Read(&bf,sizeof(bf));
        //判断是否是BMP文件
if(bf.bfType!=0x4d42)
{
AfxMessageBox("非BMP文件!",MB_OK,0);
    return;
}
        //判断文件是否损坏
if(file.GetLength()!=bf.bfSize)
{
AfxMessageBox("文件已损坏,请检查!");
    return;
}
 
//读取信息头
file.Read(&bi,sizeof(bi));
//计算调色板数目
numQuad = 0;
if(bi.biBitCount < 24)
{
//如果为1,4,8,则1向左移动对应的位数,对应的调色板数目为2,16,256
numQuad = 1<<bi.biBitCount;
} 
    //为图像信息pbi申请空间
pbi = (BITMAPINFO*)HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+numQuad*sizeof(RGBQUAD));
        memcpy(pbi,&bi,sizeof(bi));
quad = (RGBQUAD*)((BYTE*)pbi+sizeof(BITMAPINFOHEADER));
        //读取调色板
        if(numQuad!=0)
{
file.Read(quad,sizeof(RGBQUAD)*numQuad);
}
//为图像数据申请空间 
bi.biSizeImage = bf.bfSize - bf.bfOffBits;
lpBuf = (BYTE*)HeapAlloc(GetProcessHeap(),0,bi.biSizeImage);
hTempBuf=LocalAlloc(LHND,bi.biSizeImage);
lpTempBuf=(BYTE*)LocalLock(hTempBuf);
//      LONG lLineBytes;
//	    lLineBytes =WIDTHBYTES(3*lWidth*8); //计算每行的字节数
//	 bi.biHeight*lLineBytes
//读取图像数据
file.Read(lpBuf,bi.biSizeImage);
//图像读取完毕,关闭文件,设置标志
memcpy(lpTempBuf,lpBuf,bi.biSizeImage);
file.Close();
flag = 1;
 
}

灰度处理(黑白效果):

图像灰度化就是使色彩的三种颜色分量RGB的值相同,由于颜色值的取值范围是[0255],所以灰度的级别只有256种,即灰度图象仅能表现256种灰度颜色,常用有3种处理方法:
*最大值法(Maximum)R=G=B=Max(R,G,B),这种方法处理后灰度图象的亮度会偏高。
*平均值法(Average)R=G=B=(R+G+B)/3,这种方法处理后灰度图象的亮度较柔和。
*加权平均值法(Weighted Average)
    R=G=B=wr*R+wg*G+wb*Bwrwgwb分别为RGB的权值。当其权值取不同的值时,能够形成不同灰度的灰度图象,由于人眼对绿色的敏感度最高,红色次之,蓝色最低,因此当wg > wr > wb时,所产生的灰度图像更符合人眼的视觉感受。通常wr=30%wg=59%wb=11%,图像的灰度最合理。

例程:

CPictureDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//将lpBuf的指针复制给lpDIBBits
LPSTR lpDIBBits =(LPSTR)GlobalLock(pDoc->lpBuf);     //图像数据起始位置的指针
LONG lWidth = pDoc->bi.biWidth;     //源图像宽度,像素数
LONG lHeight = pDoc->bi.biHeight;   //源图像宽度,像素数
  
unsigned char* lpSrc;           //某个像素对应的指针
int gray;            //灰色对应的指针
LONG i,j,lLineBytes;
lLineBytes =WIDTHBYTES(3*lWidth*8); //计算每行的字节数
 
for(i=0;i<lHeight;i++)
{
for(j=0;j<lWidth;j++)
{
lpSrc = (unsigned char*)lpDIBBits+lLineBytes*(lHeight-1-i)+3*j;
gray = ((*lpSrc)*11+(*(lpSrc+1))*59+(*(lpSrc+2))*30)/100;
*lpSrc = gray;
*(lpSrc+1)= gray;
*(lpSrc+2) = gray;
}
}
bGray = 1;

CPictureDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//将lpBuf的指针复制给lpDIBBits
LPSTR lpDIBBits =(LPSTR)GlobalLock(pDoc->lpBuf);     //图像数据起始位置的指针
LONG lWidth = pDoc->bi.biWidth;     //源图像宽度,像素数
LONG lHeight = pDoc->bi.biHeight;   //源图像宽度,像素数
  
unsigned char* lpSrc;           //某个像素对应的指针
int gray;            //灰色对应的指针
LONG i,j,lLineBytes;
lLineBytes =WIDTHBYTES(3*lWidth*8); //计算每行的字节数
 
for(i=0;i<lHeight;i++)
{
for(j=0;j<lWidth;j++)
{
lpSrc = (unsigned char*)lpDIBBits+lLineBytes*(lHeight-1-i)+3*j;
gray = ((*lpSrc)*11+(*(lpSrc+1))*59+(*(lpSrc+2))*30)/100;
*lpSrc = gray;
*(lpSrc+1)= gray;
*(lpSrc+2) = gray;
}
}
bGray = 1;

灰度拉伸:

属于图像增强技术,如果一幅图像的灰度集中在较暗的区域而导致图像偏暗,可以用灰度拉伸功能来拉伸物体灰度区间以改善图像;同样如果图像灰度集中在较亮的区域而导致图像偏亮,也可以用灰度拉伸功能来压缩物体灰度区间以改善图像质量

我以拉伸物体灰度区间为例,将灰度在a以下的像素灰度变为0,灰度在b以上的像素变为255,然后将本来在ab之间的像素调整到0-255

即设灰度值为gray,则:            0                              gray < a

                        gray  =   (*lpSrc-low_value)*rate+c         a<gray<b

                                  255                             gray>b

其中low_valuehigh_valueratec由自己设定,若由low_value~high_value变为0~255c0.5用来进行四舍五入, rate = (255-0+1)/(high_value-low_value+1)

例程:该例程将灰度值靠近010%设为0,将靠近25510%设为255,其他进行灰度拉伸

CPictureDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//将lpBuf的指针复制给lpDIBBits
LPSTR lpDIBBits =(LPSTR)GlobalLock(pDoc->lpBuf);     //图像数据起始位置的指针
LONG lWidth = (pDoc->bi.biWidth)*3;     //源图像宽度,像素数
LONG lHeight = pDoc->bi.biHeight;   //源图像宽度,像素数
    
unsigned char* lpSrc;           //某个像素对应的指针
LONG i,j,lLineBytes;
lLineBytes =WIDTHBYTES(lWidth*8); //计算每行的字节数
    
 
BYTE bMap[256];            //存放灰度拉伸后的灰度值
    float rate=0;               
 
int temp;
float stretch_num[256];    //存放各个灰度级出现的次数
    float stretch_p[256];      //各个灰度级出现的比率
    float stretch_sum[256];    //求存放各个灰度级之前的概率和
//清空三个数组
memset(stretch_p,0,sizeof(stretch_p));
memset(stretch_sum,0,sizeof(stretch_sum));
memset(stretch_num,0,sizeof(stretch_num));
int low_value,high_value; 
//求存放图象各个灰度级出现的次数
for(i=0;i<lHeight;i++)
{  
for(j=0;j<lWidth;j++)
{
lpSrc = (unsigned char*)lpDIBBits+lLineBytes*(lHeight-1-i)+j;     
stretch_num[*lpSrc]++;
}
}
//求存放图像各个灰度级的出现概率
for(i=0;i<256;i++)
{
stretch_p[i]=stretch_num[i]/(lWidth*lHeight);
}
//求存放各个灰度级之前的概率和
for(i=0;i<256;i++)
{
for(j=0;j<=i;j++)
{
            stretch_sum[i]+=stretch_p[j];
}
}
//统计出两个阈值点的值
for(i=0;i<256;i++)
{
if(stretch_sum[i]<0.1) //low_value 取接近10%的总像素的灰度值
{
        low_value=i;
}
if(stretch_sum[i]>0.9) //high_value取接近90%的总像素的灰度值
{
high_value=i;
break;
}
}
 
rate=(float)256/(high_value-low_value+1);
    //进行灰度拉伸
for(i=0;i<lHeight;i++)
{  
for(j=0;j<lWidth;j++)
{
lpSrc = (unsigned char*)lpDIBBits+lLineBytes*(lHeight-1-i)+j;
if(*lpSrc<low_value)
{
*lpSrc = 0;
}
else if(*lpSrc>high_value)
{
                *lpSrc = 255;
}
else 
{
                temp=((*lpSrc-low_value)*rate)+0.5;
if(temp<=255)
{
                    *lpSrc = temp;
}
else
{
                    *lpSrc = 255;
}
 
}
}
}

 

图像腐蚀:

对形态学结构元素B进行z平移后,如果结构元素全部包含于集合A中,则z属于腐蚀后的集合。这个定义的意思就是从图像的第一个像素点开始依行遍历全部像素,在每个像素点上,判断是否结构元素全部位于集合A内,如果是则该点属于腐蚀后的集合,需要保留这个点,否则对改点取反(按照下面的符号约定,即将改点灰度值设置为0)。

若对黑纸上的白字进行图像腐蚀,则只针对白色的范围内,若左边或右边是黑色,则将其设置为黑色,否则不变。

例程:

CPictureDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//将lpBuf的指针复制给lpDIBBits
LPSTR lpDIBBits =(LPSTR)GlobalLock(pDoc->lpBuf);     //图像数据起始位置的指针
    LPSTR lpTempDIB =(LPSTR)GlobalLock(pDoc->lpTempBuf);
LONG lWidth = (pDoc->bi.biWidth)*3;     //源图像宽度,像素数
LONG lHeight = pDoc->bi.biHeight;   //源图像宽度,像素数
    
BYTE *lpSrc,*lpTempSrc;           //某个像素对应的指针
LONG i,j,lLineBytes;
lLineBytes =WIDTHBYTES(lWidth*8); //计算每行的字节数
 
memcpy(pDoc->lpTempBuf,pDoc->lpBuf,pDoc->bi.biSizeImage);
    //在水平方向进行腐蚀运算
    for(i=0;i<lHeight;i++)
{
        for(j=3;j<lWidth-7;j=j+3)//注意为防止越界,j的范围从1到(宽度-2)
{      
//lpSrc指向原图数据
            lpSrc = (unsigned char*)lpDIBBits+lLineBytes*(lHeight-1-i)+j;
lpTempSrc = (unsigned char*)lpTempDIB+lLineBytes*(lHeight-1-i)+j;
            if (*lpTempSrc==255)
{  
                for(int x=0;x<7;x=x+3)
{
                    if((*(lpTempSrc+x-3))!=255)
{ 
                        //自身及左右邻居中若有一个不是白点,则将该点腐蚀
                        *lpSrc=*(lpTempSrc+x-3);
                        *(lpSrc+1)=*(lpTempSrc+x-3);
                        *(lpSrc+2)=*(lpTempSrc+x-3);
                        break;
}
}
}
}
}

 

图像相减:

在图像处理中,图像相减也是比较常用的一个概念,比如把图像和背景图像相减就可以得到物体的图像;把图像和腐蚀后的图像相减就可以得到物体的轮廓。。图像相减即对应像素的挨个相减,比较简单。

例程:

CPictureDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//将lpBuf的指针复制给lpDIBBits
LPSTR lpDIBBits =(LPSTR)GlobalLock(pDoc->lpBuf);     //图像数据起始位置的指针
LPSTR lpTempDIB =(LPSTR)GlobalLock(pDoc->lpTempBuf);
LONG lWidth = (pDoc->bi.biWidth)*3;     //源图像宽度,像素数
LONG lHeight = pDoc->bi.biHeight;   //源图像宽度,像素数
    
unsigned char* lpSrc,*lpTempSrc;           //某个像素对应的指针
LONG i,j,lLineBytes;
lLineBytes =WIDTHBYTES(lWidth*8); //计算每行的字节数
 
for(i=0;i<lHeight;i++)
{
for(j=0;j<lWidth;j++)
{
lpSrc = (unsigned char*)lpDIBBits+lLineBytes*(lHeight-1-i)+j;
lpTempSrc = (unsigned char*)lpTempDIB+lLineBytes*(lHeight-1-i)+j;
*lpSrc = *lpSrc - *lpTempSrc;
}
}

 

中值滤波:

在图像处理中,经常会遇到各种噪声(即不需要的像素点),中值滤波就是舍去不需要的像素点,保留需要像素点的一种方法。它将待处理像素点上下的五个像素点保存到一个数组中(y-2,y-1,y,y+1,y+2),比较其大小,将其排序,并取中值为该点的像素值,通过该方法能去掉突出的像素点。

例程:

CPictureDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//将lpBuf的指针复制给lpDIBBits
LPSTR lpDIBBits =(LPSTR)GlobalLock(pDoc->lpBuf);     //图像数据起始位置的指针
LPSTR lpTempDIB = (LPSTR)GlobalLock(pDoc->lpTempBuf);
LONG lWidth = (pDoc->bi.biWidth)*3;     //源图像宽度,像素数
LONG lHeight = pDoc->bi.biHeight;   //源图像宽度,像素数
    
unsigned char *lpSrc,*lpTempSrc;           //某个像素对应的指针
LONG i,j,lLineBytes;
lLineBytes =WIDTHBYTES(lWidth*8); //计算每行的字节数
 
int pFilter_Image_Pixel[5];//窗口像素值
    int mid_pixel_value=0;  // 中值
int flag;
int temp=0;// 中间变量
//中值滤波
memcpy(pDoc->lpTempBuf,pDoc->lpBuf,pDoc->bi.biSizeImage);
for(i=2;i<lHeight-2;i++)
{  
for(j=0;j<lWidth;j++)
{
lpSrc = (unsigned char*)lpDIBBits+lLineBytes*(lHeight-1-i)+j;
            lpTempSrc = (unsigned char*)lpTempDIB+lLineBytes*(lHeight-1-i)+j;
//把5*1屏蔽窗口的所有像素值放入pFilter_Image_Pixel[m]
int m=0;
for(int y=-2;y<=2;y++)
{
pFilter_Image_Pixel[m]=*(lpTempSrc-lLineBytes*y);
m++;
}
//把pFilter_Image_Pixel[m]中的值按降序排列
do{
flag=0;
for(int m=0;m<4;m++)
{
if(pFilter_Image_Pixel[m]<pFilter_Image_Pixel[m+1])
{
temp=pFilter_Image_Pixel[m];
pFilter_Image_Pixel[m]=pFilter_Image_Pixel[m+1];
pFilter_Image_Pixel[m+1]=temp;
flag=1;
}
     }
   }while(flag==1);
   
mid_pixel_value=pFilter_Image_Pixel[2];//求中值mid_pixel_value
*lpSrc=mid_pixel_value;//将中值赋给目标图像的当前点
}
}

 

二值化:

二值化是阈值变换的一种方法,即设定一个阈值,该点像素大于该阈值则设其为255,小于该阈值设为0,通过二值化使图像更加方便被提取特征。

例程:

if(bGray == 0)
{
AfxMessageBox("请先进行灰度处理",MB_OK);
}
else{
        CPictureDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    LPSTR lpDIBBits =(LPSTR)GlobalLock(pDoc->lpBuf);     //图像数据起始位置的指针
    LONG lWidth = (pDoc->bi.biWidth)*3;;     //源图像宽度
    LONG lHeight = pDoc->bi.biHeight;   //源图像宽度
        BYTE bThre = 125;  //阈值
 
        unsigned char* lpSrc;           //某个像素对应的指针
    LONG i,j,lLineBytes;
    lLineBytes =WIDTHBYTES(lWidth*8); //计算每行的字节数
        for(i=0;i<lHeight;i++)
{
    for(j=0;j<lWidth;j++)
{
    lpSrc = (unsigned char*)lpDIBBits+lLineBytes*(lHeight-1-i)+j;
    	if((*lpSrc)<bThre)
{
        *lpSrc = 0;
}else
{
    	*lpSrc = 255;
}
}
}
}
原图:


技术分享

灰度处理后:

 技术分享

灰度拉伸后:

技术分享

腐蚀后:

技术分享

相减后:


技术分享


二值化后:

技术分享

版权声明:本文为博主原创文章,未经博主允许不得转载。

图像基础操作(含代码)

标签:c++   图像处理   

原文地址:http://blog.csdn.net/qq_20777367/article/details/47208653

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!