OpenCV 2.4 : Displaying a cv::Mat in MFC

2020-06-06 07:32发布

问题:

I am updating an existing code base from IplImage* to the newer cv::Mat. I was wondering how to display my cv::Mat object to MFC. The current solution we are using is based on the old CvvImage class:

void DrawPicToHDC(IplImage *img, UINT ID, bool bOnPaint)
{
    CDC *pDC = GetDlgItem(ID)->GetDC();
    HDC hDC= pDC->GetSafeHdc();
    CRect rect;
    GetDlgItem(ID)->GetClientRect(&rect);
    CvvImage cimg;
    cimg.CopyOf( img );
    cimg.DrawToHDC( hDC, &rect );
    ReleaseDC( pDC );
}

I came across this thread but unfortunately the answer provided doesn't meet my needs because the answers still require you to convert the Mat to an IplImage* before displaying.

Is there any way to do this using cv::Mat only? Any help is much appreciated.

UPDATE: I adapted the above function to using cv::Mat with the help from Kornel's answer. I now do not need to include the CvvImage class:

void DrawPicToHDC(cv::Mat cvImg, UINT ID, bool bOnPaint)
{
    // Get the HDC handle information from the ID passed
    CDC *pDC = GetDlgItem(ID)->GetDC();
    HDC hDCDst = pDC->GetSafeHdc();
    CRect rect;
    GetDlgItem(ID)->GetClientRect(&rect);
    cv::Size winSize(rect.right, rect.bottom);

    // Resize the source to the size of the destination image if necessary
    cv::Mat cvImgTmp(winSize, CV_8UC3);
    if (cvImg.size() != winSize)
    {
        cv::resize(cvImg, cvImgTmp, winSize);
    }
    else
    {
        cvImgTmp = cvImg;
    }

    // Rotate the image
    cv::flip(cvImgTmp,cvImgTmp,0);

    // Initialize the BITMAPINFO structure
    BITMAPINFO bitInfo;
    bitInfo.bmiHeader.biBitCount = 24;
    bitInfo.bmiHeader.biWidth = winSize.width;
    bitInfo.bmiHeader.biHeight = winSize.height;
    bitInfo.bmiHeader.biPlanes = 1;
    bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitInfo.bmiHeader.biCompression = BI_RGB;
    bitInfo.bmiHeader.biClrImportant = 0;
    bitInfo.bmiHeader.biClrUsed = 0;
    bitInfo.bmiHeader.biSizeImage = 0;
    bitInfo.bmiHeader.biXPelsPerMeter = 0;
    bitInfo.bmiHeader.biYPelsPerMeter = 0;

    // Add header and OPENCV image's data to the HDC
    StretchDIBits(hDCDst, 0, 0,
        winSize.width, winSize.height, 0, 0,
        winSize.width, winSize.height,
        cvImgTmp.data, &bitInfo, DIB_RGB_COLORS, SRCCOPY);

    ReleaseDC( pDC );
}

回答1:

Suppose we have an OpenCV image cv::Mat cvImg which one should be converted to CImage* mfcImg.
Of course the MFC image should be displayed on an MFC window i.e. in CStatic winImg

So the following transformations should be performed in order to display an OpenCV image in an MFC window:

cv::Mat -> CImage -> CStatic

Define MFC window size:

RECT r;
winImg.GetClientRect(&r);
cv::Size winSize(r.right, r.bottom);

The size of cvImg is not always the same as an MFC window’s:

cv::Mat cvImgTmp(winSize, CV_8UC3);
if (cvImg.size() != winSize)
{
    cv::resize(cvImg, cvImgTmp, winSize);
}
else 
{
    cvImgTmp = cvImg.clone();
}

Rotate the image:

cv::flip(cvImgTmp, cvImgTmp, 0);

Create an MFC image:

if (mfcImg)
{
    mfcImg->ReleaseDC();
    delete mfcImg; mfcImg = nullptr;
}

mfcImg = new CImage();
mfcImg->Create(winSize.width, winSize.height, 24);

For mfcImg you need a header. Create it by using BITMAPINFO structure

BITMAPINFO bitInfo;
bitInfo.bmiHeader.biBitCount = 24;
bitInfo.bmiHeader.biWidth = winSize.width;
bitInfo.bmiHeader.biHeight = winSize.height;
bitInfo.bmiHeader.biPlanes = 1;
bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitInfo.bmiHeader.biCompression = BI_RGB;
bitInfo.bmiHeader.biClrImportant = 0;
bitInfo.bmiHeader.biClrUsed = 0;
bitInfo.bmiHeader.biSizeImage = 0;
bitInfo.bmiHeader.biXPelsPerMeter = 0;
bitInfo.bmiHeader.biYPelsPerMeter = 0;

Add header and OpenCV image’s data to mfcImg

StretchDIBits(mfcImg->GetDC(), 0, 0,
    winSize.width, winSize.height, 0, 0,
    winSize.width, winSize.height,
    cvImgTmp.data, &bitInfo, DIB_RGB_COLORS, SRCCOPY
);

Display mfcImg in MFC window

mfcImg->BitBlt(::GetDC(winImg.m_hWnd), 0, 0);

Release mfcImg, if you will not use it:

if (mfcImg)
{
    mfcImg->ReleaseDC();
    delete mfcImg; mfcImg = nullptr;
}


标签: c++ opencv mfc