各种像素的图像的数据 结构分析

 之前一直使用第3方控件来处理图像,所以很少去接触与分析图像数据,以前一直使用dib来做接口,也没有深入的去分析Dib.

个人觉得要分析图像数据,首先从DIB开始说起.

1.首先讲下Dib, 什么是Dib,window编程里面有章专门讲DIB的内容. DIB是设备无关的位图(DIB),适用于交换的图像文件格式(保存图像等).

首先包含一格位图头.

typedef struct tagBITMAPINFOHEADER  // bmih       
{        
           DWORD biSize ;              // size of the structure = 40        
          LONG  biWidth ;             // width of the image in pixels        
           LONG  biHeight ;            // height of the image in pixels        
           WORD  biPlanes ;            // = 1        
           WORD  biBitCount ;          // bits per pixel (1, 4, 8, 16, 24, or 32)        
           DWORD biCompression ;       // compression code        
           DWORD biSizeImage ;         // number of bytes in image      
           LONG  biXPelsPerMeter ;     // horizontal resolution        
           LONG  biYPelsPerMeter ;     // vertical resolution        
           DWORD biClrUsed ;           // number of colors used        
           DWORD biClrImportant ;      // number of important colors       
}       
BITMAPINFOHEADER, * PBITMAPINFOHEADER ;

主要参数的意义:

biWidth :实际的图像宽度

biHeight :高度

biBitCount :图像的位数,一般1表示黑白图,8表示灰度图,24代表全彩图.

 

位图头后面有个颜色表结构体

typedef struct tagRGBQUAD  // rgb       
{
           BYTE rgbBlue ;     // blue level
           BYTE rgbGreen ;    // green level
           BYTE rgbRed ;      // red level
           BYTE rgbReserved ; // = 0
}RGBQUAD ;

如果黑白图则下面就只有2个颜色表.灰度8为的有255个颜色表.24的没有颜色表. 


然后就是图像数据. 

DIB中图像数据是 由下而上排列的.

像大多数位图格式一样,DIB中的图素位是以水平行组织的,行数等于BITMAPINFOHEADER结构的bcHeight字段。然而,与大多数位图格式不同的是,DIB从图像的底行开始,往上表示图像。

 

注意:为了安排磁盘的排列,每行图像的都是

以字节为单位的每行长度始终是4的倍数。行的长度可以计算为:

RowLength = 4 * ((bmch.bcWidth * bmch.biBitCount + 31) / 32) ;

也就是说实际上RowLength大于bcWidth一点点,

下面分别讲下 1,8,24图像的排列

 

对于每图素1位的DIB,每字节对应为8图素。最左边的图素是第一个字节的最高位:0代表黑, 1代表白. 不足8个的,后面补0.

注意: 黑白图是 字节高位代表左边的图素.

可使用下面的方法取得像素

#define GET_BYTE_BIT(b, bit) ((b>>bit) & 1)
 for (int i =0; i<nHeight; i++)
 {
  int iSrcRow = (nHeight-1-i)*nWStride;//nWStride为对齐的字节个数,图素是倒着排列的
  int iDesRow = i*nWidth;
  for (int j=0; j< nWidth; j++)
  {
   int n = j/8;
   int nBit = 7 - j%8;   //最左边的图素是第一个字节的最高位:
   if (GET_BYTE_BIT(pGdiBWData[iSrcRow+n],nBit) == 0)
   {
    //找到黑点
    pData[iDesRow+j] = 0x00;
   }
  }
 }

 

对于8位灰度的图像数据来说,就比较方便, 因为他是一个字节一个像素.

24位图像数据,是一个像素3个字节,分别代表BGR.

注意: 24位图像数据的第一个字节是BLUE,第二个GREEN,第3个是RED.

 

2.实际项目中可以使用GDI+来获取图像的数据,可以调用GDI+中的LockBits来获取.

 Gdiplus::Bitmap bt(L"F://rgb.bmp");
 Gdiplus::BitmapData bitdata;
 int w = bt.GetWidth();
 int h = bt.GetHeight();
 int wStep = (w*1+31)/32*4;
 Gdiplus::Rect rect(0,0,w, h);

 //http://blog.csdn.net/maozefa/archive/2009/09/09/4533770.aspx
 bt.LockBits(&rect, ImageLockModeWrite, bt.GetPixelFormat(), &bitdata);
 BYTE* pData = (BYTE*)bitdata.Scan0;
 for (int i =0; i<h; i++)
 {
  for (int j=0; j<bitdata.Stride; j++)
  {
   pData[i*bitdata.Stride+j] = 0x80;
  }
 }
 bt.UnlockBits(&bitdata);

 

注意:GDI+获取图像数据与DIB唯一的区别就是 DIB是倒着的,从下往上的,而GDI+中 不是倒着.

 

3. 通常项目中需要的二值化图像数据是一个字节一个像素,所以在GDI+或者DIB的黑白数据中, 要把1个字节8个像素拆开成1个字节一个像素.

可以使用下面代码.

BYTE* GetImageDataFromGDIBWData(BYTE* pGdiBWData, int nWStride, int nWidth,int nHeight) { //GDI+黑白数据 是一个字节8个象素排列的,并且是对齐的, 跟DIB唯一的区别就是 不是倒行排列 //GDI+ 灰度和24彩色 也都是对齐的 BYTE * pData = new BYTE[nWidth*nHeight]; memset(pData, 0xFF, nWidth*nHeight); #define GET_BYTE_BIT(b, bit) ((b>>bit) & 1) for (int i =0; i<nHeight; i++) { int iSrcRow = i*nWStride; int iDesRow = i*nWidth; for (int j=0; j< nWidth; j++) { int n = j/8; int nBit = 7 - j%8; //最左边的图素是第一个字节的最高位: if (GET_BYTE_BIT(pGdiBWData[iSrcRow+n],nBit) == 0) { //找到黑点 pData[iDesRow+j] = 0x00; } } } return pData; }

你可能感兴趣的:(各种像素的图像的数据 结构分析)