现在的位置: 首页 > 综合 > 正文

在MFC中显示OpenCV的Mat图像矩阵 ShowMatImgToWnd(GetDlgItem(IDC_ShowImg) , matFrame);

2012年12月25日 ⁄ 综合 ⁄ 共 5217字 ⁄ 字号 评论关闭

先学习,后改造,标准码农,哈哈

 

原文地址:

http://www.cnblogs.com/yuanzfy/archive/2012/06/21/2557957.html 

 

使用GDI+可以方便的把OpenCV的图像矩阵类型数据显示在MFC的窗口中

 

void BitMatToWnd(CWnd* wnd, cv::Mat img, CRect *Roi)
{
    if(img.empty())
        return;
    CDC *cdc = wnd->GetDC(); 
    CDC MemDC;//首先定义一个显示设备对象
    CBitmap MemBitmap;//定义一个位图对象
    CRect rect, drect;
    
    wnd->GetClientRect(rect);
    Gdiplus::Bitmap bitmap(img.cols, img.rows, img.cols * img.channels(),  PixelFormat24bppRGB, (BYTE*)img.data);//根据Mat矩阵创建一个GDI+中的Bitmap位图
    
    if(Roi == NULL)
        drect = rect;
    else
        drect = *Roi;
    //随后建立与屏幕显示兼容的内存显示设备
    MemDC.CreateCompatibleDC(cdc);
    //下面建立一个与屏幕显示兼容的位图,至于位图的大小,可以用窗口的大小
    MemBitmap.CreateCompatibleBitmap(cdc, rect.Width(), rect.Height());
    
    //将位图选入到内存显示设备中
    //只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上
    CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);
    
    //先用背景色将位图清除干净,可以用自己应该用的颜色
    MemDC.FillSolidRect(0,0, rect.Width(), rect.Height(),RGB(255,255,255));
    
    //绘图
    Gdiplus::Graphics g(MemDC.m_hDC);
    Gdiplus::Image *ii = &bitmap; 
    g.DrawImage(ii, Gdiplus::Rect(0,0,drect.Width(),drect.Height()));
    g.ReleaseHDC(MemDC.m_hDC);
    
    //将内存中的图拷贝到屏幕上进行显示
    cdc->BitBlt(0,0,drect.Width(),drect.Height(),&MemDC,0, 0,SRCCOPY);
    //绘图完成后的清理
    MemBitmap.DeleteObject();
    MemDC.DeleteDC();
    //ReleaseDC(cdc);  这里需要做如下修改
    wnd->ReleaseDC(cdc);
    }

 

另一个:

http://www.cnblogs.com/yuanzfy/archive/2012/06/21/2557908.html

MFC双缓冲绘图与GDI+绘图方法

MFC双缓冲绘图:

CDC *cdc = this->GetDC();
 
CDC MemDC; //首先定义一个显示设备对象
CBitmap MemBitmap;//定义一个位图对象
 
CRect rect;
this->GetClientRect(rect);
 
MemDC.CreateCompatibleDC(NULL);//随后建立与屏幕显示兼容的内存显示设备
//下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小
MemBitmap.CreateCompatibleBitmap(cdc, gdirect.Width(), gdirect.Height());
 
//将位图选入到内存显示设备中
//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上
CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);
 
//先用背景色将位图清除干净,颜色自选
MemDC.FillSolidRect(0,0, gdirect.Width(), gdirect.Height(),RGB(255,255,255));
//这里加入自己的画图代码,此时画图都是在内存中完成,操作对象是MemDC
//然后将内存中的图拷贝到屏幕上进行显示
cdc->BitBlt(0,0, rect.Width()-20, rect.Height(),&MemDC,0, scrollpos*140,SRCCOPY);
//绘图完成后清理临时对象
MemBitmap.DeleteObject();
MemDC.DeleteDC();
ReleaseDC(cdc);

 

GDI+绘图方法

将双缓冲方法和GDI+绘图方法结合起来可以方便高效的把图片显示在控件中。

 

#include <GdiPlus.h>//首先要包含此头文件
Gdiplus::GdiplusStartupInput m_GdiplusStartupInput;
ULONG_PTR m_GdiplusToken;
Gdiplus::GdiplusStartup(&m_GdiplusToken,&m_GdiplusStartupInput,NULL);//调用此函数启用GDI+功能
 
Gdiplus::Graphics g(MemDC.m_hDC);//绘图
//使用gdi+加载其他类型的资源文件,jpg png都行
Gdiplus::Image *ii;
ii = Gdiplus::Image::FromFile("c:\\img.jpg");
g.DrawImage(ii, Gdiplus::Rect());
delete ii;
}
g.ReleaseHDC(MemDC.m_hDC);
 
Gdiplus::GdiplusShutdown(m_GdiplusToken);//使用完成调用此函数关闭GDI+库

 

由于回复栏中不能粘贴过长的代码,俺只好再行编辑啦,嘿嘿....

在OpenCV中以Mat方式读取的1或3通道 8-bits图像现在可以方便地显示至指示窗口啦,例如显示图像到ID为IDC_ShowImg的Picture控件中,您只需要ShowMatImgToWnd(GetDlgItem(IDC_ShowImg) , matFrame);  够方便够舒爽吧,而且显示稳定性要好于 CvvImage类里面的DrawToHDC()方法!!!

 

void ShowMatImgToWnd(CWnd* pWnd, cv::Mat img)
{	
    if(img.empty())  
        return;  

    CRect drect;       
    pWnd->GetClientRect(drect);    //(drect);  (&drect);  两种方式均可,竟然	
	
	CClientDC dc(pWnd);
	HDC hDC =dc.GetSafeHdc();
	
	//内存中的图像数据拷贝到屏幕上
	BYTE *bitBuffer		   = NULL;
	BITMAPINFO *bitMapinfo = NULL;
	
	int ichannels =img.channels();
	if( ichannels == 1)
	{
		bitBuffer  = new BYTE[40+4*256]; 
	}
	else if( ichannels == 3)
	{
		bitBuffer  = new BYTE[sizeof(BITMAPINFO)]; 
	}
	else
	{
		return;
	}


	if(bitBuffer == NULL)
	{	
		return;
	}


	bitMapinfo = (BITMAPINFO *)bitBuffer;
	bitMapinfo->bmiHeader.biSize			= sizeof(BITMAPINFOHEADER);
	bitMapinfo->bmiHeader.biHeight		    = -img.rows;  //如果高度为正的,位图的起始位置在左下角。如果高度为负,起始位置在左上角。
	bitMapinfo->bmiHeader.biWidth		    = img.cols;
	bitMapinfo->bmiHeader.biPlanes			= 1;      // 目标设备的级别,必须为1	
	bitMapinfo->bmiHeader.biBitCount		= ichannels *8;     // 每个像素所需的位数,必须是1(双色), 4(16色),8(256色)或24(真彩色)之一
	bitMapinfo->bmiHeader.biCompression	    = BI_RGB; //位图压缩类型,必须是 0(不压缩), 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
	bitMapinfo->bmiHeader.biSizeImage		= 0;      // 位图的大小,以字节为单位
	bitMapinfo->bmiHeader.biXPelsPerMeter	= 0;	  // 位图水平分辨率,每米像素数
	bitMapinfo->bmiHeader.biYPelsPerMeter	= 0;	  // 位图垂直分辨率,每米像素数
	bitMapinfo->bmiHeader.biClrUsed			= 0;	  // 位图实际使用的颜色表中的颜色数
	bitMapinfo->bmiHeader.biClrImportant	= 0;	  // 位图显示过程中重要的颜色数

	if(ichannels == 1)
	{
		for(int i=0; i<256; i++)
		{	//颜色的取值范围 (0-255)
			bitMapinfo->bmiColors[i].rgbBlue  =bitMapinfo->bmiColors[i].rgbGreen =bitMapinfo->bmiColors[i].rgbRed   =(BYTE) i;
		}

		bitMapinfo->bmiHeader.biClrUsed			= 256;	  // 位图实际使用的颜色表中的颜色数
	}
	SetStretchBltMode(hDC, COLORONCOLOR);


	StretchDIBits(hDC,
					0,
					0,
					drect.right,		//显示窗口宽度
					drect.bottom,		//显示窗口高度
					0,
					0,
					img.cols,		   //图像宽度
					img.rows,		   //图像高度
					img.data,			
					bitMapinfo,			
					DIB_RGB_COLORS, 
					SRCCOPY
				  );
	
	delete []bitBuffer;

}

 

 

以下是它的一个兄弟版本:一直占据着一片内存, 直到应用程序结束时被收回,但它可以提供更好的显示速度,真是有舍有得呀,呵呵...

 

void ShowMatImgToWnd(CWnd* pWnd, cv::Mat img)
{	
    if(img.empty())  
        return;  


	static BITMAPINFO *bitMapinfo = NULL;
	static bool First=TRUE;
	if(First)
	{		
		BYTE *bitBuffer	= new BYTE[40+4*256];
		if(bitBuffer == NULL)
		{	
			return;
		}
		First=FALSE;
		memset(bitBuffer, 0, 40+4*256);
		bitMapinfo = (BITMAPINFO *)bitBuffer;
		bitMapinfo->bmiHeader.biSize			= sizeof(BITMAPINFOHEADER);
		bitMapinfo->bmiHeader.biPlanes			= 1;      // 目标设备的级别,必须为1
		for(int i=0; i<256; i++)
		{	//颜色的取值范围 (0-255)
			bitMapinfo->bmiColors[i].rgbBlue  =bitMapinfo->bmiColors[i].rgbGreen =bitMapinfo->bmiColors[i].rgbRed   =(BYTE) i;
		}	
	
	}
	
	bitMapinfo->bmiHeader.biHeight		    = -img.rows;  //如果高度为正的,位图的起始位置在左下角。如果高度为负,起始位置在左上角。
	bitMapinfo->bmiHeader.biWidth		    = img.cols;
	bitMapinfo->bmiHeader.biBitCount		= img.channels() *8;     // 每个像素所需的位数,必须是1(双色), 4(16色),8(256色)或24(真彩色)之一

    CRect drect;       
    pWnd->GetClientRect(drect);    //(drect);  (&drect);  两种方式均可,竟然	
	
	CClientDC dc(pWnd);
	HDC hDC =dc.GetSafeHdc();
	SetStretchBltMode(hDC, COLORONCOLOR);  //此句不能少哦
	//内存中的图像数据拷贝到屏幕上
	StretchDIBits(hDC,
					0,
					0,
					drect.right,		//显示窗口宽度
					drect.bottom,		//显示窗口高度
					0,
					0,
					img.cols,		   //图像宽度
					img.rows,		   //图像高度
					img.data,			
					bitMapinfo,			
					DIB_RGB_COLORS, 
					SRCCOPY
				  );
	
	
}

 

抱歉!评论已关闭.