VC编程实现灰度图像与彩色图像的相互转换PhotoShop的图像处理功能很强,其中有一个功能是将灰度图像转换为彩色图像,数字图像处理中,也经常要遇到灰度图像与彩色图像相互转换的问题,如何自己解决这个问题,值得大家探讨,现将我解决这类问题的方法陈述如下:工程应用中经常要遇到需要把彩色图像到灰度图像的变换的问题,采集卡过来的图像为彩色图像,为加快处理速度,要把彩色图像转换为黑白图象,这个问题比较好解决,一般情况下彩色图像每个像素用三个字节表示,每个字节对应着R、G、B分量的亮度(红、绿、蓝),转换后的黑白图像的一个像素用一个字节表示该点的灰度值,它的值在0~255之间,数值越大,该点越白,既越亮,越小则越黑。
转换公式为Gray(i,j)=0.11*R(i,j)+0.59*G(i,j)+0.3*B(i,j),其中Gray(i,j)为转换后的黑白图像在(i,j)点处的灰度值,我们可以观察该式,其中绿色所占的比重最大,所以转换时可以直接使用G值作为转换后的灰度。
至于灰度图像转换为彩色图像,技术上称为灰度图像的伪彩色处理,这是一种视觉效果明显而技术又不是很复杂的图像增强技术。
灰度图像中,如果相邻像素点的灰度相差不大,但包含了丰富的信息的话,人眼则无法从图像中提取相应的信息,因为人眼分辨灰度的能力很差,一般只有几十个数量级,但是人眼对彩色信号的分辨率却很强,这样将黑白图像转换为彩色图像人眼可以提取更多的信息量。
在转换过程中,经常采用的技术是灰度级-彩色变换,意思就是对黑白图像上的每一个像素点,取得该点的灰度值并送入三个通道经过实施不同的变换,产生相应的R、G、B的亮度值,即所求彩色图像对应像素点的彩色值,具体变换公式很多,我采用的是最常用的一种,变换曲线图如下:上图中,三个图分别代表了三个变换通道,R、G、B指的是变换后对应点的R、G、B分量值,L指的是各个分量的最大值为255,G(x,y)为相应点的灰度值。
理论上就这些,下面是我用VC实现的源代码,图一为我的灰度位图,图二为伪彩色处理后的结果图。
我这个实现函数中是如何得到灰度位图的数据的就不多讲了,有兴趣的朋友可参考我在天极网上九月十号发表的《VC灰度位图处理》一文,那里应该讲的很清楚了。
需要读者注意的是彩色图像中每个象素中的三个字节分别代表的分量,第一个字节为B,第二个为G值、最后一个为R值,这个顺序不要搞错了。
代码实现如下:void CDibView::OnMenuchange() file://图像转换实现函数{// TODO: Add your command handler code hereHANDLE data1handle;LPBITMAPINFOHEADER lpBi;BITMAPINFO *m_pBMI;CDibDoc *pDoc=GetDocument();HDIB hdib;unsigned char *hData;unsigned char *data;hdib=pDoc->GetHDIB();//得到位图数据的句柄,其中包含图像信息头BeginWaitCursor();lpBi=(LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)hdib);hData=(unsigned char*)FindDIBBits((LPSTR)lpBi);m_pBMI=new BITMAPINFO;//生成彩色图像的信息头m_pBMI->bmiHeader.biBitCount=24;m_pBMI->bmiHeader.biClrImportant=0;m_pBMI->bmiHeader.biClrUsed=0;m_pBMI->bmiHeader.biCompression=BI_RGB;m_pBMI->bmiHeader.biHeight=lpBi->biHeight;m_pBMI->bmiHeader.biWidth=lpBi->biWidth;m_pBMI->bmiHeader.biPlanes=1;m_pBMI->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);m_pBMI->bmiHeader.biXPelsPerMeter=0;m_pBMI->bmiHeader.biYPelsPerMeter=0;m_pBMI->bmiHeader.biSizeImage=WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight*3;file://data=hData;int R,G,B,i,j;data1handle=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight*3);file://生成存储彩色图象数据的缓冲区data=(unsigned char*)GlobalLock((HGLOBAL)data1handle);for(i=0;i biHeight;i++)//实现灰度到彩色变换for(j=0;jbiWidth*8);j++){if(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)<=64){R=0;G=(int)4*(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j));B=255;}if(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)>64&& *(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)<=128){R=0;G=255;B=(int)4*(128-*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j));}if(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)>128&& *(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)<=192){R=(int)4*(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)-128);G=255;B=0;}if(*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)>192&& *(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)<=255){R=255;G=(int)4*(255-*(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j));B=0;}file://将生成的R、G、B分量存入目标缓冲区*(data+i*WIDTHBYTES(lpBi->biWidth*8)*3+j*3)=B;*(data+i*WIDTHBYTES(lpBi->biWidth*8)*3+j*3+1)=G;*(data+i*WIDTHBYTES(lpBi->biWidth*8)*3+j*3+2)=R;}GlobalUnlock((HGLOBAL)hdib);GlobalUnlock(data1handle);EndWaitCursor();CClientDC pDC(this);file://显示真彩色图像StretchDIBits(pDC.GetSafeHdc(),0,0,lpBi->biWidth,lpBi->biHeight,0,0,lpBi->biWidth, lpBi->biHeight,data,m_pBMI,DIB_RGB_COLORS,SRCCOPY);delete m_pBMI;}VC++ 灰度位图处理图像处理技术已经渗透到人类生活的各个领域并得到越来越多的应用,图像处理所涉及的图像格式有很多种,如TIF、JEMP、BMP等等,工程应用中经常要处理256级的灰度BMP图像,如通过黑白采集卡采集得到的图像。
BMP灰度图像作为Windows环境下主要的图像格式之一,以其格式简单,适应性强而倍受欢迎。
在进行图像处理时,操作图像中的像素值就要得到图像阵列;经过处理后的图像的像素值存储起来;显示图像时要正确实现调色板,结合这些问题,文章针对性的给出了操作灰度BMP图像时的部分函数实现代码及注释。
一、BMP位图操作BMP位图包括位图文件头结构BITMAPFILEHEADER、位图信息头结构BITMAPINFOHEADER、位图颜色表RGBQUAD和位图像素数据四部分。
处理位图时要根据文件的这些结构得到位图文件大小、位图的宽、高、实现调色板、得到位图像素值等等。
对于256级灰度图像每个像素用8bit表示颜色的索引值,这里要注意的一点是在BMP位图中,位图的每行像素值要填充到一个四字节边界,即位图每行所占的存储长度为四字节的倍数,不足时将多余位用0填充。
在处理图像应用程序的文档类(CdibDoc.h)中声明如下宏及公有变量:#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)//计算图像每行象素所占的字节数目HANDLE m_hDIB;//存放位图数据的句柄CPalette* m_palDIB;//指向调色板Cpalette类的指针CSize m_sizeDoc; file://初始化视图的尺寸1、读取灰度BMP位图根据BMP位图文件的结构,操作BMP位图文件读入数据,重载了文挡类的OnOpenDocument函数如下:BOOL CDibDoc::OnOpenDocument(LPCTSTR lpszPathName){CFile file;CFileException fe;if (!file.Open(lpszPathName, CFile::modeRead | CFile::shareDenyWrite, &fe)){AfxMessageBox("文件打不开");return FALSE;}//打开文件DeleteContents();//删除文挡BeginWaitCursor();BITMAPFILEHEADER bmfHeader;//定义位图文件头结构DWORD dwBitsSize;HANDLE hDIB;LPSTR pDIB;BITMAPINFOHEADER *bmhdr;//指向位图信息头结构的指针dwBitsSize = file.GetLength();//得到文件长度if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) !=sizeof(bmfHeader))return FALSE;if (bmfHeader.bfType != 0x4d42) file://检查是否为BMP文件return FALSE;hDIB=(HANDLE) ::GlobalAlloc(GMEM_MOVEABLE |GMEM_ZEROINIT, dwBitsSize);file://申请缓冲区if (hDIB == 0){return FALSE;}pDIB = (LPSTR) ::GlobalLock((HGLOBAL)hDIB);file://得到申请的缓冲区的指针if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) !=dwBitsSize - sizeof(BITMAPFILEHEADER) ){::GlobalUnlock((HGLOBAL)hDIB);hDIB=NULL;return FALSE;}//读数据,包括位图信息、位图颜色表、图像像素的灰度值bmhdr=(BITMAPINFOHEADER*)pDIB;//为指向位图信息头结构的指针付值::GlobalUnlock((HGLOBAL)hDIB);if ((*bmhdr).biBitCount!=8) file://验证是否为8bit位图return FALSE;m_hDIB=hDIB;InitDIBData();file://自定义函数,根据读入的数据得到位图的宽、高、颜色表file:// 来得到初始化视的尺寸、生成调色板EndWaitCursor();SetPathName(lpszPathName);//设置存储路径SetModifiedFlag(FALSE); // 设置文件修改标志为FALSEreturn TRUE;}2、灰度位图数据的存储为了将图像处理后所得到的像素值保存起来,重载了文档类的OnSaveDocument函数,其具体实现如下:BOOL CDibDoc::OnSaveDocument(LPCTSTR lpszPathName){CFile file;CFileException fe;BITMAPFILEHEADER bmfHdr; // 位图文件头结构LPBITMAPINFOHEADER lpBI; file://指向位图信息结构的指针DWORD dwDIBSize;if (!file.Open(lpszPathName, CFile::modeCreate |CFile::modeReadWrite | CFile::shareExclusive, &fe)){AfxMessageBox("文件打不开");}//打开文件BOOL bSuccess = FALSE;BeginWaitCursor();lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) m_hDIB);if (lpBI == NULL)return FALSE;dwDIBSize = *(LPDWORD)lpBI + 256*sizeof(RGBQUAD);// Partial CalculationDWORD dwBmBitsSize;//BMP文件信息结构所占的字节数dwBmBitsSize=WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) *lpBI->biHei ght;// 存储时位图所有像素所占的总字节数dwDIBSize += dwBmBitsSize;lpBI->biSizeImage = dwBmBitsSize; // 位图所有像素所占的总字节数file://以下五句为文件头结构填充值bmfHdr.bfType =0x4d42; // 文件为"BMP"类型bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);//文件总长度bmfHdr.bfReserved1 = 0;bmfHdr.bfReserved2 = 0;bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize+ 256*sizeof(RGBQUAD);file://位图数据距问件头的偏移量file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));//写文件头file.WriteHuge(lpBI, dwDIBSize);file://将位图信息(信息头结构、颜色表、像素数据)写入文件::GlobalUnlock((HGLOBAL) m_hDIB);EndWaitCursor();SetModifiedFlag(FALSE); // back to unmodifiedreturn TRUE;}二、调色板的操作灰度图像要正确显示,必须实现逻辑调色板和系统调色板,通过在主框架类中处理Windows定义的消息WM_QUERYNEWPALETTE 、WM_PALETTECHANGED及视图类中处理自定义消息WM_DOREA LIZE(该消息在主框架窗口定义如下:#define WM_REALIZEPAL (WM_USER+100))来实现调色板的操作。