MFC中实现简单的位图显示、处理

 

最近在做图像采集的工作,需要处理图像数据,所以学习了一下位图显示,而且只看了设备相关位图DDB。基本上实现了位图的显示、位图数据的处理等功能。这里就记录一下我自己的理解,不一定全都对,仅供参考而已。

 

要显示位图,需要做如下工作:

 

CStatic* pStatic=(CStatic*)GetDlgItem(IDC_DISPLAY2);

CDC* pDC=pStatic->GetDC();

CBitmap bitmap;

bitmap.LoadBitmap(IDB_BITMAP2);

BITMAP bmp;

bitmap.GetBitmap(&bmp);

CDC dcCompatible;

dcCompatible.CreateCompatibleDC(pDC);

 

dcCompatible.SelectObject(&bitmap);

CRect rect;

pStatic->GetClientRect(&rect);

 

pDC->StretchBlt(0,0,rect.Width(),rect.Height(), &dcCompatible,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);

 

程序中,创建了一个位图对象bitmap,bitmap.LoadBitmap(IDB_BITMAP2);将一幅位图加载到了bitmap这个对象中,按我的理解,这个对象是存在在内存中的,所以我们对这个对象的操作并不会对原来那幅位图有什么影响。另外,还定义了一个BITMAP结构:bmp。之所以定义这个结构,是为了获得位图的宽度、高度等图像信息,如果我们知道加载的位图的高度、宽度、一个像素占多少字节等信息,那么我们无需定义这个bmp结构,不过为了方便,还是定义一个的好。要显示位图,还要创建与当前DC兼容的DC,当前DC怎么获得?就是下面这两句:

 

CStatic* pStatic=(CStatic*)GetDlgItem(IDC_DISPLAY2);

CDC* pDC=pStatic->GetDC();

 

我要将位图在对话框中的静态文本控件中显示,因此定义了一个指向静态CStatic对象的指针,这样,当前DC就需要使用pStatic->GetDC();来获取。然后创建一个与当前DC兼容的DC: dcCompatible.CreateCompatibleDC(pDC);。这个DC创建了之后,就把内存中的位图对象bitmap选入这个DC:dcCompatible.SelectObject(&bitmap);,从而确定这个兼容DC的显示表面的大小。这里要搞清楚一个关系。做了以上各步骤之后,其实与那个位图对象已经没多少关系了,bitmap这个位图对象的相关信息已经在dcCompatible这个保存着了,而要显示的目标区域则由当前DC:pDC所指示出来,这也就是为什么要创建兼容DC,只有两个DC兼容,才能顺利的把图像从dcCompatible复制到pDC中进行显示。我们看到最后的那句

 

pDC->StretchBlt(0,0,rect.Width(),rect.Height(), &dcCompatible,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);

 

实际上就是起到将dcCompatible中的图像在pDC的区域上显示的作用。这句话中还有有一个参数rect,它是一个CRect对象,用来得到客户区的大小,也就是我们所要显示的区域的大小,在这里也就是静态文本框,一个矩形的区域,所以调用pStatic的成员函数GetClientRect()来获取客户区域。

 

这样,一幅位图就显示了出来。上述这段程序是对话框中的一个按钮的响应函数。我之前看到有人说,要把画图程序放在OnDraw或者OnPaint之类的函数中去。我觉得其实放在哪里都无所谓,只要知道了要显示位图需要计算机做什么工作,就能顺利将位图显示出来。

 

 

学会显示位图之后,就得准备处理位图。做图像采集的时候,获得的是一个指向内存中一块区域的指针pData,这块区域中存储着图像的灰度值。而如果要处理加载的位图,也需要获取其位图数据的指针。因此两者的处理方法是差不多的。这里就以处理加载的位图为例进行说明。

 

要获取位图数据的指针,可以使用GetBitmapBits(),而要将处理后的数据COPY到位图对象中,则使用SetBitmapBits(),具体的用法可以查阅MSDN。我加载的位图是256色的,它的一个像素数据占4个字节,前三个字节分别表示RGB,第四个字节为保留字节。因此,如果这幅位图宽度是1000个像素,那么其字节宽度就是4000个字节。一般的图像处理都是针对灰度图像,也就是说一个像素的RGB值是相等的,从黑色(0,0,0)到白色(255,255,255)变化。因此,我处理图像的时候,只需要处理它的像素数据的代表R的字节,然后代表G和B的字节就都等于R的值就可以了。下面是代码:

 

BYTE *pmydata;    //定义一个指针用来指向位图图像数据在内存中的存储区域

pmydata=new BYTE[bmp.bmWidthBytes*bmp.bmHeight];   //根据位图的高度宽度初始化一下

bitmap.GetBitmapBits(bmp.bmWidthBytes*bmp.bmHeight,pmydata); //将位图对象的数据COPY到pmydata指向的区域,bitmap是位图对象,bmp是位图结构,可参考上一篇文章的定义

for(int i=0;i<bmp.bmWidthBytes*bmp.bmHeight;i+=4) //这里只是将RGB三个字节的值取平均值,再取个反

{                                                                    //因为一个像素有4个字节,故i+=4

   BYTE temp=0;

   temp=(pmydata[i]+pmydata[i+1]+pmydata[i+2])/3;

   pmydata[i]=255-temp;//R值

   pmydata[i+1]=255-temp;//G值

   pmydata[i+2]=255-temp;//B值

}

 

这样就实现了图像数据的简单处理,然后将处理的数据COPY回位图对象:

 

bitmap.SetBitmapBits(bmp.bmWidthBytes*bmp.bmHeight,pmydata); //将处理后的数据COPY进位图对象

 

随后按照上一篇文章的步骤显示位图即可。

 

另外要说一下,对于图像采集上来的灰度值数据,一个像素只有一个字节,而上面显示的图像的像素数据则是4个字节,这应该怎么来转换一下呢?我用的方法是定义一个COLORREF数组:

 

COLORREF* m_ColorData=new COLORREF[width*height];

 

这个COLORREF实际上就是DWORD,上面这句话定义了一个指向一块存放DWORD类型的数据的指针,也就是说,m_ColorData[i]与m_ColorData[i+1]之间有4个字节的距离,这正好与256色图像的像素数据存放方式相对应。将灰度值数据处理好之后,转化成RGB值:

 

//将灰度值转换为RGB值进行显示

   for(i=0;i<width*height;i++)  

    m_ColorData[i]=RGB( m_bytes[i], m_bytes[i], m_bytes[i]);

 

其中的m_bytes[i]就是灰度值,上面这句话的意思是将m_ColorData[i]的四个字节中的前三个字节赋值为:m_bytes[i], m_bytes[i], m_bytes[i]。然后建立一个位图对象bitmap,使用SetBitmapBits()函数设置它的图像数据的值。

 

bitmap.SetBitmapBits(width*height*sizeof(COLORREF),m_ColorData);。然后按照前面说的步骤将这个位图对象显示处理即可。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值