如何在 MFC 视图上显示 OpenCV Mat

2022-01-12 00:00:00 opencv c++ mfc

我认为在 MFC 视图上显示 OpenCV2 Mat 很简单,但事实并非如此.这只是我在 google 上找到的相关资料.请原谅我的无知,但我找不到任何其他材料来展示如何将 SetDIBitsToDevice 与一维数组数据"成员返回一起使用.更具体地说,我需要知道如何为函数指定 BITMAPINFO.我要回到旧的 C 风格 OpenCV 来使用 MFC 吗?

I thought displaying OpenCV2 Mat on MFC View is simple but is not. This is only relevant material I found on google. Excuse me for my ignorance but I can't find any other materials showing how to use SetDIBitsToDevice with one dimensional array "data" member returns. More specifically, I need to know how to specify BITMAPINFO for the function. Do I go back to Old C-style OpenCV to work with MFC?

更新:

我发现 SetDIBitsToDevice 的一个例子 这实际上是用于旧的 C 风格的 OpenCV.但是将其转换为 OpenCV2 很简单.我需要提到一些事情才能让它发挥作用:

I found an example of SetDIBitsToDevice which is actually for old C-style OpenCV. But it was straightforward to convert it for OpenCV2. There are things I need to mention to make it work:

  1. Bpp 方法效果不佳,因为 Mat 的深度返回 0.我只是这样更改:

  1. Bpp method does not work well as Mat's depth returns 0. I just changed like this:

static int Bpp(cv::Mat img) { return 8 * img.channels(); } 

  • Mat 没有原始成员.但是对于 FillBitmapInfo 方法的 origin 参数,简单地放置 0 就可以了.

  • Mat does not have origin member. But simply putting 0 is fine for origin argument of FillBitmapInfo method.

    除此之外,以下代码效果很好.希望这对其他开发者也有帮助.

    Other than that, following code works great. Hope this helps other devs too.

    void COpenCVTestView::OnDraw(CDC* pDC)
    {
    COpenCVTestDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;
    if(pDoc->m_cvImage.empty()) return;
    // TODO: add draw code for native data here
    int height=pDoc->m_cvImage.rows;
    int width=pDoc->m_cvImage.cols;
    uchar buffer[sizeof( BITMAPINFOHEADER ) + 1024]; 
    BITMAPINFO* bmi = (BITMAPINFO* )buffer; 
    FillBitmapInfo(bmi,width,height,Bpp(pDoc->m_cvImage),0);
    SetDIBitsToDevice(pDC->GetSafeHdc(), 0, 0, width,
        height, 0, 0, 0, height, pDoc->m_cvImage.data, bmi,
        DIB_RGB_COLORS);
    }
    void COpenCVTestView::FillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin) 
    { 
    assert(bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32)); 
    
    BITMAPINFOHEADER* bmih = &(bmi->bmiHeader); 
    
    memset(bmih, 0, sizeof(*bmih)); 
    bmih->biSize = sizeof(BITMAPINFOHEADER); 
    bmih->biWidth = width; 
    bmih->biHeight = origin ? abs(height) : -abs(height); 
    bmih->biPlanes = 1; 
    bmih->biBitCount = (unsigned short)bpp; 
    bmih->biCompression = BI_RGB; 
    
    if (bpp == 8) 
    { 
        RGBQUAD* palette = bmi->bmiColors; 
    
                for (int i = 0; i < 256; i++) 
        { 
            palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i; 
            palette[i].rgbReserved = 0; 
        } 
    } 
    }
    

    推荐答案

    来自 MSDN:

    lpvBits [in]指向存储为字节数组的颜色数据的指针.有关详细信息,请参阅以下备注部分.

    lpvBits [in] A pointer to the color data stored as an array of bytes. For more information, see the following Remarks section.

    这是您必须使用从 Mat::data 返回的数据初始化的指针.

    This is the pointer you must init with the data returned from Mat::data.

  • 相关文章