用DIB位图显示图像

一、DIB位图结构及注意点:

1.DIB结构:

一个完整的DIB由两部分组成:一个BITMAPINFO结构和一个存储像素阵列的数组:

  1. typedef struct tagBITMAPINFO {   
  2.             BITMAPINFOHEADER bmiHeader;   
  3.             RGBQUAD bmiColors[1]; //颜色表  
  4.             } BITMAPINFO;  

由此可见BITMAPINFO结构包含两个部分,BITMAPINFOHEADER结构和RGBQUAD结构,其中两个结构定义如下:

  1. typedef struct tagBITMAPINFOHEADER{   
  2.             DWORD biSize; //该结构的大小  
  3.             LONG biWidth; //位图的宽度(以像素为单位)  
  4.             LONG biHeight; //位图的高度(以像素为单位)  
  5.             WORD biPlanes; //必须为1  
  6.             WORD biBitCount //每个像素的位数(1、4、8、16、24或32)  
  7.             DWORD biCompression; //压缩方式,一般为0或BI_RGB (未压缩)  
  8.             DWORD biSizeImage; //以字节为单位的图象大小(仅用于压缩位图)  
  9.             LONG biXPelsPerMeter; //以目标设备每米的像素数来说明位图的水平分辨率  
  10.             LONG biYPelsPerMeter; //以目标设备每米的像素数来说明位图的垂直分辨率  
  11.             DWORD biClrUsed; /*颜色表的颜色数,若为0则位图使用由biBitCount指定的最大颜色数*/  
  12.             DWORD biClrImportant; //重要颜色的数目,若该值为0则所有颜色都重要  
  13.             } BITMAPINFOHEADER;  
  1. typedef struct tagRGBQUAD {  
  2.             BYTE rgbBlue; //蓝色的强度  
  3.             BYTE rgbGreen; //绿色的强度  
  4.             BYTE rgbRed; //红色的强度  
  5.             BYTE rgbReserved; //保留字节,为0  
  6.             } RGBQUAD;  
  7. //注意,RGBQUAD结构中的颜色顺序是BGR,而不是平常的RGB。  
由此可知,BITMAPINFO结构是由图像的基本信息和调色板组成,对于彩色图,没有调色板,所以BITMAPINFO只包含图像的基本信息结构BITMAPINFOHEADER:

                                                          灰度图                                                            彩色图

BITMAPINFO包含:         BITMAPINFOHEADER   + RGBQUAD         BITMAPINFOHEADER 
2.DIB注意点:

<1>DIB位图每行数据必须是32bit(4个字节)的整数倍,如果图像数据为Byte型(0~255),即每个像素为一个字节(8bit),这样图像每行的宽必须是4的整数倍,不足4的整数倍的部分,以0补充。

<2>DIB数据存储顺序是:自左到右,自下到上,逆序存储。即:图像的第一行数据,存在DIB数据部分最后一行,最后一行存在第一行,因为显示的时候,DIB位图是,自下而上显示的,即读取的第一行数据,会显示在界面的最后一行,然后,第二行显示在界面倒数第二行。

<3>调色板顺序为BGR而不是RGB

二、DIB结构赋值及显示:

1.先看一下显示函数:

  1. int StretchDIBits(HDC hdc, int XDest , int YDest , int nDestWidth, int nDestHeight,   
  2. int XSrc, int Ysrc, int nSrcWidth, int nSrcHeight,   
  3. CONST VOID *lpBits, CONST BITMAPINFO * lpBitsInfo,   
  4.   
  5. hdc:指向目标设备环境的句柄。  
  6. XDest:指定目标矩形左上角位置的X轴坐标,按逻辑单位来表示坐标。  
  7. YDest:指定目标矩形左上角的Y轴坐标,按逻辑单位表示坐标。  
  8. nDestWidth:指定目标矩形的宽度。  
  9. nDestHeight:指定目标矩形的高度。  
  10. XSrc:指定DIB中源矩形(左上角)的X轴坐标,坐标以像素点表示。  
  11. YSrc:指定DIB中源矩形(左上角)的Y轴坐标,坐标以像素点表示。  
  12. nSrcWidth:按像素点指定DIB中源矩形的宽度。  
  13. nSrcHeight:按像素点指定DIB中源矩形的高度。  
  14. lpBits:指向DIB位的指针,这些位的值按字节类型数组存储,有关更多的信息,参考下面的备注一节。  
  15. lpBitsInfo:指向BITMAPINFO结构的指针,该结构包含有关DIB方面的信息。  
  16. iUsage:表示是否提供了BITMAPINFO结构中的成员bmiColors,如果提供了,那么该bmiColors是否包含了明确的RGB值或索引。参数iUsage必须取下列值,这些值的含义如下:  
  17. DIB_PAL_COLORS:表示该数组包含对源设备环境的逻辑调色板进行索引的16位索引值。  
  18. DIB_RGB_COLORS:表示该颜色表包含原义的RGB值,若想了解更多的信息,请参考下面备注一节。  
  19. dwRop:指定源像素点、目标设备环境的当前刷子和目标像素点是如何组合形成新的图像。若想了解更多信息,请参考下面的备注一节。  
  20. 返回值:如果函数执行成功,那么返回值是拷贝的扫描线数目,如果函数执行失败,那么返回值是GDI_ERROR。UINT iUsage, DWORD dwRop);
由此可知:只要对BITMAPINFO结构和像素阵列的数组赋值即可:

2.DIB赋值:

<1>在 ***Doc.h中定义BITMAPINFO结构和像素阵列的数组变量:

  1. public:  
  2.     BITMAPINFO *m_pBmInfo; //位图信息头  
  3.     unsigned char *m_pImageData; //位图数据  
  4.     void InitialDIB(unsigned char **InData8); //初始化位图信息头与数据  

<2>在***Doc.cpp中对变量赋值:

  1. void C***Doc::InitialDIB(unsigned char **InData8) //InData8 包含图像数据数组  
  2. {  
  3.     int i,row,col,tIND,ImgIdx;  
  4.     if(m_nAllBandNum == 1) //如果图像只有一个波段,按灰度图显示  
  5.     {  
  6.         m_pBmInfo = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*255];  
  7.                                       //开辟BITMAPINFO结构大小  
  8.         for (i=0; i<256; i++)  
  9.         {  
  10.             m_pBmInfo->bmiColors[i].rgbRed = i;  
  11.             m_pBmInfo->bmiColors[i].rgbGreen = i;  
  12.             m_pBmInfo->bmiColors[i].rgbBlue = i;           
  13.         }         
  14.         m_pBmInfo->bmiHeader.biBitCount = 8;   
  15.     }  
  16.     else //如果大于一个波段,按彩色图显示  
  17.     {  
  18.         m_pBmInfo = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFOHEADER)];  
  19.         m_pBmInfo->bmiHeader.biBitCount = 24; //也可以是32,如果是32下面对彩色图赋值将不同,下面再说  
  20.     }  
  21.       
  22.     //设置图像基本信息  
  23.     m_pBmInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);    
  24.     m_pBmInfo->bmiHeader.biWidth = m_nImageWidth;  
  25.     m_pBmInfo->bmiHeader.biHeight =m_nImageHeight;  
  26.   
  27.     m_pBmInfo->bmiHeader.biCompression = BI_RGB;  
  28.     m_pBmInfo->bmiHeader.biPlanes = 1;  
  29.     m_pBmInfo->bmiHeader.biClrUsed = 0;  
  30.     m_pBmInfo->bmiHeader.biClrImportant = 0;  
  31.     m_pBmInfo->bmiHeader.biSizeImage = 4*((m_nImageWidth*m_pBmInfo->bmiHeader.biBitCount+31)/32)*m_nImageHeight;  
  32.     int nWideBytes = 4*((m_pBmInfo->bmiHeader.biWidth*m_pBmInfo->bmiHeader.biBitCount+31)/32);  
  33.     m_pImageData = new BYTE[nWideBytes * m_nImageHeight];   //开辟数据缓存      
  34.   
  35.     if(m_nAllBandNum == 1)  //灰度图:对图像数据数组赋值  
  36.     {  
  37.         for(row = 0;row<m_nImageHeight; row++)  
  38.         {  
  39.             for(col=0; col<m_nImageWidth; col++)  
  40.             {  
  41.                 ImgIdx = m_nImageWidth * row + col;  
  42.                 tIND = nWideBytes * (m_nImageHeight - row - 1) + col;  
  43.                 m_pImageData[tIND] = InData8[0][ImgIdx];  
  44.             }  
  45.         }  
  46.     }  
  47.     else //彩色图:  
  48.     {  
  49.         for(row = 0;row<m_nImageHeight; row++)  
  50.         {  
  51.             for(col=0; col<m_nImageWidth; col++)  
  52.             {  
  53.                 ImgIdx =m_nImageWidth * row + col;  
  54.   
  55.                 tIND = nWideBytes * (m_nImageHeight - row - 1) + 3*col;  
  56.   
  57.                 m_pImageData[tIND] = InData8[2][ImgIdx]; //B  
  58.                 tIND += 1;  
  59.                 m_pImageData[tIND] = InData8[1][ImgIdx]; //G  
  60.                 tIND += 1;  
  61.                 m_pImageData[tIND] = InData8[0][ImgIdx]; //R  
  62.   
  63.             }  
  64.         }  
  65.       
  66.     }  
  67. }  
如果 设置m_pBmInfo->bmiHeader.biBitCount = 32,则彩色图对数据赋值部分要改为:

[cpp]  view plain  copy
  1. else //彩色图:  
  2. {  
  3.     for(row = 0;row<m_nImageHeight; row++)  
  4.     {  
  5.         for(col=0; col<m_nImageWidth; col++)  
  6.         {  
  7.             ImgIdx =m_nImageWidth * row + col;  
  8.   
  9.             tIND = nWideBytes * (m_nImageHeight - row - 1) + 4*col;  
  10.   
  11.             m_pImageData[tIND] = InData8[2][ImgIdx]; //B  
  12.             tIND += 1;  
  13.             m_pImageData[tIND] = InData8[1][ImgIdx]; //G  
  14.             tIND += 1;  
  15.             m_pImageData[tIND] = InData8[0][ImgIdx]; //R  
  16.             tIND +=1;  
  17.             m_pImageData[tIND] = 0; //保留字节 rgbReserved  
  18.               
  19.         }  
  20.     }  
  21. }  

<3>显示图像:

在***View的OnDraw()函数中调用显示函数:

[cpp]  view plain  copy
  1. ::SetStretchBltMode(pDC->m_hDC,STRETCH_HALFTONE); //设置拉伸方式,避免缩小时图像失真  
  2. ::StretchDIBits(pDC->m_hDC,  0, 0, nImgWidth ,  
  3.                 nImgHeight ,0, 0, nImgWidth, nImgHeight,  
  4.                 pDoc->m_pImageData, pDoc->m_pBmInfo, DIB_RGB_COLORS, SRCCOPY) ;  
可以调整显示区域大小,图像会发生相应的拉伸,具体见StretchDIBits参数。

注:

1.如果是对话框,可以OnPaint()中调用。

2.至于DIB对象的定义、赋值和显示调用位置,根据需要而定。

3.图像数据的获取,可以参看GDAL类,该类可直接获取图像的基本信息。


猜你喜欢

转载自blog.csdn.net/yaowang107/article/details/79315739