OpenCV在MFC的Picture控件中显示图像的若干可行方式

注:本文整合于网络多处资源,仅供个人学习记录之用!如果无意中侵犯了您的版权请联系本人:tangyibiao520@163.com,.本人会及时编辑掉

方式一,

使用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);
}

 
 方式二, 
 

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

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图像现在可以方便地显示至指示图片控件

<span style="font-size:12px;">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;
}</span>


方式五

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

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
				  );
}

方式六,

CvvImage类(网上可找到)

void DrawPicToHDC(IplImage *img, UINT ID)
{
	CDC *pDC = GetDlgItem(ID)->GetDC();
	HDC hDC=  pDC->GetSafeHdc();
	CRect rect;
	GetDlgItem(ID)->GetClientRect(&rect);
	CvvImage cimg; 
	cimg.CopyOf(img,img->nChannels);//这个很重要!!在控件中显示图像时一定要是这句。而不是上面那句,要不然不能显示!会出错。
	cimg.DrawToHDC(hDC,&rect);
	ReleaseDC(pDC);
}

你可能感兴趣的:(图片,mfc,opencv,控件)