1、最新8位灰度图像BMP的保存汇总8位灰度图像BMP的保存8位灰度图像BMP的保存zz2012-04-07 21:01在图像处理中,我们经常需要将真彩色图像转换为黑白图像。严格的讲应该是灰度图,因为真正的黑白图像是二色,即只有纯黑,纯白二色。开始之前,我们先简单补充一下计算机中图像的表示原理。计算机中的图像大致可以分成两类:位图(Bitmap)和矢量图(Metafile)。位图可以视为一个二维的网格,整个图像就是由很多个点组成的,点的个数等于位图的宽乘以高。每个点被称为一个像素点,每个像素点有确定的颜色,当很多个像素合在一起时就形成了一幅完整的图像。我们通常使用的图像大部分都是位图,如数码相机拍
2、摄的照片,都是位图。因为位图可以完美的表示图像的细节,能较好的还原图像的原景。但位图也有缺点:第一是体积比较大,所以人们开发了很多压缩图像格式来储存位图图像,目前应用最广的是JPEG格式,在WEB上得到了广泛应用,另外还有GIF,PNG等等。第二是位图在放大时,不可避免的会出现“锯齿”现象,这也由位图的本质特点决定的。所以在现实中,我们还需要使用到另一种图像格式:矢量图。同位图不同,矢量图同位图的原理不同,矢量图是利用数学公式通过圆,线段等绘制出来的,所以不管如何放大都不会出现变形,但矢量图不能描述非常复杂的图像。所以矢量图都是用来描述图形图案,各种CAD软件等等都是使用矢量格式来保存文件的。
3、在讲解颜色转换之前,我们要先对位图的颜色表示方式做一了解。位图中通常是用RGB三色方式来表示颜色的(位数很少时要使用调色板)。所以每个像素采用不同的位数,就可以表示出不同数量的颜色。如下图所示:每像素的位数 一个像素可分配到的颜色数量 1 21 = 2 2 22 = 4 4 24 = 16 8 28 = 256 16 216 = 65,536 24 224 = 16,777,216 从中我们可以看出,当使用24位色(3个字节)时,我们可以得到1600多万种颜色,这已经非常丰富了,应该已接近人眼所能分辨的颜色了。现在计算机中使用最多的就是24位色,别外在GDI+中还有一种32位色,多出来的一个通
4、道用来描述Alpha,即透明分量。24位色中3个字节分别用来描述R,G,B三种颜色分量,我们看到这其中是没有亮度分量的,这是因为在RGB表示方式中,亮度也是直接可以从颜色分量中得到的,每一颜色分量值的范围都是从0到255, 某一颜色分量的值越大,就表示这一分量的亮度值越高,所以255表示最亮,0表示最暗。那么一个真彩色像素点转换为灰度图时它的亮度值应该是多少呢,首先我们想到的平均值,即将R+G+B/3。但现实中我们使用的却是如下的公式:Y = 0.299R+0.587G+0.114B这个公式通常都被称为心理学灰度公式。这里面我们看到绿色分量所占比重最大。因为科学家发现使用上述公式进行转换时所得
5、到的灰度图最接近人眼对灰度图的感觉。因为灰度图中颜色数量一共只有256种(1个字节),所以转换后的图像我们通常保存为8位格式而不是24位格式,这样比较节省空间。而8位图像是使用调色板方式来保存颜色的。而不是直接保存颜色值。调色板中可以保存256颜色,所以可以正好可以将256种灰度颜色保存到调色版中。下面是个私人例子:BITMAPFILEHEADER targetfileheader; BITMAPINFOHEADER targetinfoheader; memset(&targetfileheader,0,sizeof(BITMAPFILEHEADER); memset(&targetinfo
6、header,0,sizeof(BITMAPINFOHEADER); /构造灰度图的文件头 targetfileheader.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256; targetfileheader.bfSize=192*192+sizeof(RGBQUAD)*256 +sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); targetfileheader.bfReserved1=0; target
7、fileheader.bfReserved2=0; targetfileheader.bfType=0x4d42; /构造灰度图的信息头 targetinfoheader.biBitCount=8; targetinfoheader.biSize=sizeof(BITMAPINFOHEADER); targetinfoheader.biHeight=192; targetinfoheader.biWidth=192; targetinfoheader.biPlanes=1; targetinfoheader.biCompression=BI_RGB; targetinfoheader.biSi
8、zeImage=0; targetinfoheader.biXPelsPerMeter=0; targetinfoheader.biYPelsPerMeter=0; targetinfoheader.biClrImportant=0; targetinfoheader.biClrUsed=0; /构造灰度图的调色版 RGBQUAD rgbquad256; int i; for(i=0;i=0;i-) for(long j=0;jbiWidth)*(DWORD)lpBI-biBitCount) *lpBI-biHeight;/ 存储时位图所有像素所占的总字节数dwDIBSize += dwBmB
9、itsSize;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);f
10、ile:/位图数据距问件头的偏移量file.Write(LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER);/写文件头file.WriteHuge(lpBI, dwDIBSize);file:/将位图信息(信息头结构、颜色表、像素数据)写入文件:GlobalUnlock(HGLOBAL) m_hDIB);EndWaitCursor();SetModifiedFlag(FALSE); / back to unmodifiedreturn TRUE;二、 调色板的操作灰度图像要正确显示,必须实现逻辑调色板和系统调色板 ,通过在主框架类中处理Windows定义的消息WM_
11、QUERYNEWPALETTE 、WM_PALETTECHANGED及视图类中处理自定义消息WM_DOREALIZE(该消息在主框架窗口定义如下:#define WM_REALIZEPAL (WM_USER+100))来实现调色板的操作。void CMainFrame:OnPaletteChanged(CWnd* pFocusWnd) file:/总实现活动视的调色板CMDIFrameWnd:OnPaletteChanged(pFocusWnd);CMDIChildWnd* pMDIChildWnd = MDIGetActive();if (pMDIChildWnd = NULL)return
12、CView* pView = pMDIChildWnd-GetActiveView();ASSERT(pView != NULL);SendMessageToDescendants(WM_DOREALIZE, (WPARAM)pView-m_hWnd);file:/通知所有子窗口系统调色板已改变BOOL CMainFrame:OnQueryNewPalette()/提供实现系统调色板的机会/ 实现活动视的调色板CMDIChildWnd* pMDIChildWnd = MDIGetActive();if (pMDIChildWnd = NULL)return FALSE; / no active
13、 MDI child frame (no new palette)CView* pView = pMDIChildWnd-GetActiveView();ASSERT(pView != NULL);file:/通知活动视图实现系统调色板pView-SendMessage(WM_DOREALIZE, (WPARAM)pView-m_hWnd);return TRUE;LRESULT CDibView:OnDoRealize(WPARAM wParam, LPARAM)/实现系统调色板ASSERT(wParam != NULL);CDibDoc* pDoc = GetDocument();if (
14、pDoc-m_hDIB = NULL)return 0L; / must be a new documentCPalette* pPal = pDoc-m_palDIB;file:/调色板的颜色表数据在InitDIBData()函数中实现if (pPal != NULL)CMainFrame* pAppFrame = (CMainFrame*) AfxGetApp()-m_pMainWnd;ASSERT_KINDOF(CMainFrame, pAppFrame);CClientDC appDC(pAppFrame);CPalette* oldPalette = appDC.SelectPale
15、tte(pPal, (HWND)wParam) != m_hWnd);file:/只有活动视才可以设为FALSE,/ 即根据活动视的调色板设为前景调色板if (oldPalette != NULL)UINT nColorsChanged = appDC.RealizePalette();/实现系统调色板if (nColorsChanged 0)pDoc-UpdateAllViews(NULL);/更新视图appDC.SelectPalette(oldPalette, TRUE);file:/将原系统调色板置为逻辑调色板elseTRACE0(tSelectPalette failed inCDi
16、bView:OnPaletteChangedn);注:在调用API函数显示位图时,不要忘记设置逻辑调色板,即背景调色板,否则位图将无法正确显示。三、图像的数字化处理通过以上读文件的操作,已经得到图像数据,由于得到的数据包括多余信息,所以在进行数字图像处理时要进一步删除多余信息,只对位图的像素进行操作,以基于模板的高通滤波为例来讲述数字图像处理的实现:void CDibView:OnMENUHighPass() HANDLE data1handle;LPBITMAPINFOHEADER lpBi;CDibDoc *pDoc=GetDocument();HDIB hdib; unsigned ch
17、ar *hData; unsigned char *data;hdib=pDoc-GetHDIB();BeginWaitCursor();lpBi=(LPBITMAPINFOHEADER)GlobalLock(HGLOBAL)hdib);hData=(unsigned char*)FindDIBBits(LPSTR)lpBi);pDoc-SetModifiedFlag(TRUE);data1handle=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi-biWidth*8)*lpBi-biHeight);data=(unsigned char*)GlobalLock
18、(HGLOBAL)data1handle);AfxGetApp()-BeginWaitCursor();int i,j,s,t,ms=1;int sum=0,sumw=0;int mask33=-1,-1,-1,-1,9,-1,-1,-1,-1;for(i=0; ibiHeight; i+)for(j=0; jbiWidth; j+)sumw=0; sum=0;for(s=(-ms); s=ms; s+)for(t=(-ms); t=0) & (j+t)=0) & (i+s)biHeight) & (j+t)biWidth)sumw += mask1+s1+t;sum+=*(hData+(i+
19、s)*WIDTHBYTES(lpBi-biWidth*8)+(j+t)*mask1+s1+t;if(sumw=0) sumw=1; sum/=sumw;if(sum255)sum=255;if(sumbiWidth*8)+j)=sum;for( j=0; jbiHeight; j+)for( i=0; ibiWidth; i+)*(hData+i*WIDTHBYTES(lpBi-biWidth*8)+j)=*(data+i*WIDTHBYTES(lpBi-biWidth*8)+j);AfxGetApp()-EndWaitCursor();GlobalUnlock(HGLOBAL)hdib);GlobalUnlock(data1handle);EndWaitCursor();Invalidate(TRUE);四、图像的基本操作处理1、图像平移图像平移只是改变图像在屏幕上的位置,图像本身并不发生变化。假设原图像区域左上角坐标为(x0, y0),右下角坐标为(x1, y1),将图像分别沿x和y轴平移dx和dy,则新图像的左上角坐标为(x0+dx, y0+dy),右下角坐标为(x1+dx, y1+dy)。坐标平移变换公式为:x1 = x + dxy1 = y + dy在屏幕上实现图像的移动分为四个步骤: 读原图像到缓冲区; 擦除视图上原图像; 计算平移后的新坐标。 利用API函数:
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1