打开BMP格式图像文件
BMP文件分为BITMAPFILEHEADER、BITMAPINFORHEADER、RGBQUAD三部分文件头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; }
灰度处理(黑白效果):
图像灰度化就是使色彩的三种颜色分量R、G、B的值相同,由于颜色值的取值范围是[0,255],所以灰度的级别只有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*B,wr、wg、wb分别为R、G、B的权值。当其权值取不同的值时,能够形成不同灰度的灰度图象,由于人眼对绿色的敏感度最高,红色次之,蓝色最低,因此当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,然后将本来在a和b之间的像素调整到0-255。
即设灰度值为gray,则: 0 gray < a
gray = (*lpSrc-low_value)*rate+c a<gray<b
255 gray>b
其中low_value、high_value、rate、c由自己设定,若由low_value~high_value变为0~255,c取0.5用来进行四舍五入, rate = (255-0+1)/(high_value-low_value+1)
例程:该例程将灰度值靠近0的10%设为0,将靠近255的10%设为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; } } } }
原图:
灰度处理后:
灰度拉伸后:
腐蚀后:
相减后:
二值化后:
版权声明:本文为博主原创文章,未经博主允许不得转载。