先学习,后改造,标准码农,哈哈
原文地址: 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
);
}