您的位置:首页 > 其它

MFC基础知识(三)——用DIB位图显示图像

2015-03-11 15:35 204 查看
本文主要介绍:DIB位图的一些基础知识和在MFC中如何利用DIB位图显示图像。

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

1.DIB结构:

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

typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1]; //颜色表
} BITMAPINFO;
由此可见BITMAPINFO结构包含两个部分,BITMAPINFOHEADER结构和RGBQUAD结构,其中两个结构定义如下:

typedef struct tagBITMAPINFOHEADER{
DWORD biSize; //该结构的大小
LONG biWidth; //位图的宽度(以像素为单位)
LONG biHeight; //位图的高度(以像素为单位)
WORD biPlanes; //必须为1
WORD biBitCount //每个像素的位数(1、4、8、16、24或32)
DWORD biCompression; //压缩方式,一般为0或BI_RGB (未压缩)
DWORD biSizeImage; //以字节为单位的图象大小(仅用于压缩位图)
LONG biXPelsPerMeter; //以目标设备每米的像素数来说明位图的水平分辨率
LONG biYPelsPerMeter; //以目标设备每米的像素数来说明位图的垂直分辨率
DWORD biClrUsed; /*颜色表的颜色数,若为0则位图使用由biBitCount指定的最大颜色数*/
DWORD biClrImportant; //重要颜色的数目,若该值为0则所有颜色都重要
} BITMAPINFOHEADER;


typedef struct tagRGBQUAD {
BYTE rgbBlue; //蓝色的强度
BYTE rgbGreen; //绿色的强度
BYTE rgbRed; //红色的强度
BYTE rgbReserved; //保留字节,为0
} RGBQUAD;
//注意,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.先看一下显示函数:

int StretchDIBits(HDC hdc, int XDest , int YDest , int nDestWidth, int nDestHeight,
int XSrc, int Ysrc, int nSrcWidth, int nSrcHeight,
CONST VOID *lpBits, CONST BITMAPINFO * lpBitsInfo,

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

2.DIB赋值:

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

public:
BITMAPINFO *m_pBmInfo; //位图信息头
unsigned char *m_pImageData; //位图数据
void InitialDIB(unsigned char **InData8); //初始化位图信息头与数据
<2>在***Doc.cpp中对变量赋值:

void C***Doc::InitialDIB(unsigned char **InData8) //InData8 包含图像数据数组
{
int i,row,col,tIND,ImgIdx;
if(m_nAllBandNum == 1) //如果图像只有一个波段,按灰度图显示
{
m_pBmInfo = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*255];
//开辟BITMAPINFO结构大小
for (i=0; i<256; i++)
{
m_pBmInfo->bmiColors[i].rgbRed = i;
m_pBmInfo->bmiColors[i].rgbGreen = i;
m_pBmInfo->bmiColors[i].rgbBlue = i;
}
m_pBmInfo->bmiHeader.biBitCount = 8;
}
else //如果大于一个波段,按彩色图显示
{
m_pBmInfo = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFOHEADER)];
m_pBmInfo->bmiHeader.biBitCount = 24; //也可以是32,如果是32下面对彩色图赋值将不同,下面再说
}

//设置图像基本信息
m_pBmInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_pBmInfo->bmiHeader.biWidth = m_nImageWidth;
m_pBmInfo->bmiHeader.biHeight =m_nImageHeight;

m_pBmInfo->bmiHeader.biCompression = BI_RGB;
m_pBmInfo->bmiHeader.biPlanes = 1;
m_pBmInfo->bmiHeader.biClrUsed = 0;
m_pBmInfo->bmiHeader.biClrImportant = 0;
m_pBmInfo->bmiHeader.biSizeImage = 4*((m_nImageWidth*m_pBmInfo->bmiHeader.biBitCount+31)/32)*m_nImageHeight;
int nWideBytes = 4*((m_pBmInfo->bmiHeader.biWidth*m_pBmInfo->bmiHeader.biBitCount+31)/32);
m_pImageData = new BYTE[nWideBytes * m_nImageHeight];	//开辟数据缓存

if(m_nAllBandNum == 1)  //灰度图:对图像数据数组赋值
{
for(row = 0;row<m_nImageHeight; row++)
{
for(col=0; col<m_nImageWidth; col++)
{
ImgIdx = m_nImageWidth * row + col;
tIND = nWideBytes * (m_nImageHeight - row - 1) + col;
m_pImageData[tIND] = InData8[0][ImgIdx];
}
}
}
else //彩色图:
{
for(row = 0;row<m_nImageHeight; row++)
{
for(col=0; col<m_nImageWidth; col++)
{
ImgIdx =m_nImageWidth * row + col;

tIND = nWideBytes * (m_nImageHeight - row - 1) + 3*col;

m_pImageData[tIND] = InData8[2][ImgIdx]; //B
tIND += 1;
m_pImageData[tIND] = InData8[1][ImgIdx]; //G
tIND += 1;
m_pImageData[tIND] = InData8[0][ImgIdx]; //R

}
}

}
}
如果 设置m_pBmInfo->bmiHeader.biBitCount = 32,则彩色图对数据赋值部分要改为:

else //彩色图:
{
for(row = 0;row<m_nImageHeight; row++)
{
for(col=0; col<m_nImageWidth; col++)
{
ImgIdx =m_nImageWidth * row + col;

tIND = nWideBytes * (m_nImageHeight - row - 1) + 4*col;

m_pImageData[tIND] = InData8[2][ImgIdx]; //B
tIND += 1;
m_pImageData[tIND] = InData8[1][ImgIdx]; //G
tIND += 1;
m_pImageData[tIND] = InData8[0][ImgIdx]; //R
tIND +=1;
m_pImageData[tIND] = 0; //保留字节 rgbReserved

}
}
}


<3>显示图像:

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

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

注:

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

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

3.图像数据的获取,可以参看GDAL类,该类可直接获取图像的基本信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: