您的位置:首页 > 其它

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

2011-04-25 16:04 471 查看
之前一直使用第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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: