图像基础操作(含代码)

打开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;
            }
        }
    }
}
原图:


灰度处理后:

 

灰度拉伸后:


腐蚀后:


相减后:




二值化后:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值