首页 > 解决方案 > cv::imread 图像未显示在 MFC 的图片框上

问题描述

我正在构建基于对话框的 MFC 应用程序。当我单击按钮时,我可以从文件资源管理器中选择图像,并且该图像也被加载到cv::imread(). 并且还显示在优化校准中。

我可以使用以下代码在优化校准中加载和显示图像。

void CMFCApplication3Dlg::OnBnClickedButton1()
{
    cv::Mat src = cv::imread("D:/source/repos/Testing_Photos/Large/cavalls.png");
    Display(src);

}

但不是用下面的代码。

void CMFCApplication3Dlg::OnBnClickedButton1()
{
    TCHAR szFilter[] = _T("PNG (*.png)|*.png|JPEG (*.jpg)|*.jpg|Bitmap (*.bmp)|*.bmp||");
    CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter, AfxGetMainWnd());

    if (dlg.DoModal() == IDC_BUTTON1)
    {
        CString cstrImgPath = dlg.GetPathName();
        CT2CA pszConvertedAnsiString(cstrImgPath);
        std::string strStd(pszConvertedAnsiString);
        cv::Mat src = cv::imread(strStd);

        Display(src);
    }
}

以下是“显示”功能。

void CMFCApplication3Dlg::Display(cv::Mat& mat) {

    CStatic * PictureB = (CStatic *)GetDlgItem(IDC_STATIC);

    CWnd* cwn = (CWnd *)GetDlgItem(IDC_STATIC);
    CDC* wcdc = cwn->GetDC();
    HDC whdc = wcdc->GetSafeHdc();

    RECT rec;
    cwn->GetClientRect(&rec);

    cv::Size matSize;
    matSize = cv::Size(rec.right, rec.bottom);

    BITMAPINFO bitmapinfo;

    bitmapinfo.bmiHeader.biBitCount = 24;
    bitmapinfo.bmiHeader.biWidth = mat.cols;
    bitmapinfo.bmiHeader.biHeight = -mat.rows;
    bitmapinfo.bmiHeader.biPlanes = 1;
    bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitmapinfo.bmiHeader.biCompression = BI_RGB;
    bitmapinfo.bmiHeader.biClrImportant = 0;
    bitmapinfo.bmiHeader.biClrUsed = 0;
    bitmapinfo.bmiHeader.biSizeImage = 0;
    bitmapinfo.bmiHeader.biXPelsPerMeter = 0;
    bitmapinfo.bmiHeader.biYPelsPerMeter = 0;


    StretchDIBits(
        whdc,
        0, 0,
        matSize.width, matSize.height,
        0, 0,
        mat.cols, mat.rows,
        mat.data,
        &bitmapinfo,
        DIB_RGB_COLORS,
        SRCCOPY
    );

}

我对 MFC 很陌生,我真的不知道我错在哪里。请帮我!谢谢你。

标签: opencvmfc

解决方案


这不是正确的绘画方法。每次有绘画请求时,图片都会被删除。

这就是CFileDialog在您绘制图像后立即强制重新绘制的情况。您必须回复OnPaintor OnDrawItem,或CStatic::SetBitmap按照评论中的说明使用。

你可以在CImage课堂上做到这一点,不需要 OpenCV:

CImage img;
if(S_OK == img.Load(L"unicode.jpg"))
{
    CStatic *control = (CStatic*)GetDlgItem(IDC_STATIC);
    control->ModifyStyle(0, SS_BITMAP);
    auto oldbmp = control->SetBitmap(img.Detach());
    if(oldbmp)  
        DeleteObject(oldbmp);
}

或者您可以使用 OpenCV 创建HBITMAP句柄。

请注意,OpenCV 不处理 Unicode 文件名。CW2A将 Unicode 转换为 ANSI 字符编码。如果一个或多个代码点无法在当前活动的代码页中表示,则会失败。为了解决这个问题,我们可以使用CFileor打开文件std::ifstream,将其读取为二进制文件,然后使用打开cv::imdecode。例子:

//open the file from unicode path:
const wchar_t *filename = L"unicode.jpg";
std::ifstream fin(filename, std::ios::binary);
if(!fin.good())
    return;

//read from memory
std::vector<char> vec(std::istreambuf_iterator<char>(fin), {});
cv::Mat src = cv::imdecode(vec, cv::IMREAD_COLOR);
if(!src.data)
    return;

//create hbitmap
BITMAPINFOHEADER bi = { sizeof(bi), src.cols, -src.rows, 1, 24 };
CClientDC dc(this);
auto hbmp = CreateDIBitmap(dc, &bi, CBM_INIT, src.data, (BITMAPINFO*)&bi, 0);

//send hbitmap to control
auto control = (CStatic*)GetDlgItem(IDC_STATIC);
auto oldbmp = control->SetBitmap(hbmp);
if (oldbmp)
    DeleteObject(oldbmp);

推荐阅读