早上小师妹遇到mfc显示opencv图像的问题,过来请教我,趁机总结下以前用过的几种方法好了。
(1)使用opencv的CvvImage类
该方法比较简单,但是opencv2.x以上版本已经不支持CvvImage类,不过可以在网上下载该类的头文件和源文件,添加到工程里就可以使用了。
void CXXXDlg::DrawIplImage2MFC(IplImage* img, unsigned int id)
{
CDC* pDC = GetDlgItem(id)->GetDC();
HDC hDC = pDC->GetSafeHdc();
CvvImage cimg;
cimg.CopyOf( img );
CRect rect;
GetDlgItem(id)->GetClientRect(&rect);
cimg.DrawToHDC(hDC, &rect);
ReleaseDC( pDC );
}
函数参数中id是控件ID,比如IDC_STATIC(下同)。
(2)使用MFC的绘图函数
该方法利用MFC的绘图函数,将opencv图像数据先copy到缓冲去然后在控件上显示出来。
void CXXXDlg::DrawIplImage2MFC(IplImage* img, unsigned int id)
{
BYTE *g_pBits;
HDC g_hMemDC;
HBITMAP g_hBmp, g_hOldBmp;
CDC *pDC;
CStatic *pic;
int width, height;
CRect rect;
pDC = GetDlgItem(id)->GetDC();
pic = (CStatic*)GetDlgItem(id);
pic->GetClientRect(&rect);
width = rect.Width();
height = rect.Height();
g_hMemDC =::CreateCompatibleDC(pDC->m_hDC);
BYTE bmibuf[sizeof(BITMAPINFO)+256 * sizeof(RGBQUAD)];
memset(bmibuf, 0, sizeof(bmibuf));
BITMAPINFO *pbmi = (BITMAPINFO*)bmibuf;
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = img->width;
pbmi->bmiHeader.biHeight = img->height;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 24;
pbmi->bmiHeader.biCompression= BI_RGB;
g_hBmp =::CreateDIBSection(g_hMemDC, pbmi, DIB_RGB_COLORS, (void**)&g_pBits, 0, 0);
g_hOldBmp = (HBITMAP)::SelectObject(g_hMemDC, g_hBmp);
BitBlt(g_hMemDC, 0, 0, width, height, pDC->m_hDC, 0, 0, SRCCOPY);
int l_width = WIDTHBYTES(img->width* pbmi->bmiHeader.biBitCount);
for (int row = 0; row < img->height;row++)
memcpy(&g_pBits[row*l_width],&img->imageData[ (img->height - row - 1)*l_width], l_width);
TransparentBlt(pDC->m_hDC, 0, 0, width, height, g_hMemDC, 0, 0, img->width, img->height, RGB(0, 0, 0));
SelectObject(g_hMemDC, g_hOldBmp);
DeleteDC(g_hMemDC);
DeleteObject(pic);
DeleteObject(g_hBmp);
DeleteObject(g_hOldBmp);
}
该方法是将opencv的显示窗口与MFC的控件链接起来,效果是opencv的窗口恰好覆盖在控件上。
//pic是opencv窗口的标志符,name是窗口名字,ID同上,是MFC控件ID
bool CXXXDlg::attachWindow(string &pic,const char* name,int ID)
{
pic=string(name);
cv::namedWindow(pic, 1);
HWND hWnd = (HWND) cvGetWindowHandle(name);
HWND hParent = ::GetParent(hWnd);
::SetParent(hWnd, GetDlgItem(ID)->m_hWnd);
::ShowWindow(hParent, SW_HIDE);
return true;
}
bool CXXXDlg::showImage(string pic,int id,cv::Mat mat)
{
CRect rect;
GetDlgItem(id)->GetClientRect(&rect);
cv::resize(mat,mat,cv::Size(rect.Width(),rect.Height()),CV_INTER_CUBIC);
imshow(pic,mat);
return true;
}
</pre><pre>
使用方法是先链接opencv窗口的标识符和控件ID
string pic;
attachWindow(pic,"win",IDC_PIC);
然后在需要显示图像的地方调用showImage
Mat mat=imread("1.jpg");
showImage(pic,IDC_PIC,mat);