如何在MFC视图上显示OpenCV Mat

时间:2011-12-14 08:59:15

标签: c++ mfc opencv

我认为在MFC View上显示OpenCV2 Mat很简单,但事实并非如此。 This is only relevant material I found on google。请原谅我的无知,但我找不到任何其他材料显示如何使用一维数组“数据”成员返回SetDIBitsToDevice。更具体地说,我需要知道如何为函数指定BITMAPINFO。我是否会回到旧C风格的OpenCV与MFC合作?

更新

我发现an example of SetDIBitsToDevice实际上是旧C风格的OpenCV。但是将它转换为OpenCV2很简单。有些事情我需要提及才能使其发挥作用:

  1. 当Mat的深度返回0时,Bpp方法不能正常工作。我只是改变了这样:

    static int Bpp(cv::Mat img) { return 8 * img.channels(); } 
    
  2. Mat没有原始成员。但是简单地将0设置为FillBitmapInfo方法的原点参数。

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

    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; 
        } 
    } 
    }
    

3 个答案:

答案 0 :(得分:2)

这是在MFC中显示OpenCV数据的另一种可能方式,我使用并且效果很好:

IplImage* image// <-- this contains the image you want to display
CvvImage tempdefault;
RECT myrect;   // <-- specifiy where on the screen you want it to be displayed
myrect.top    =  0;
myrect.bottom = _pictureh;
myrect.left   = _picturex;
myrect.right =  _picturew+_picturex;
tempdefault.Create(_pictureh,_picturew,32);
tempdefault.CopyOf(image);
tempdefault.DrawToHDC(pDC->GetSafeHdc(),&myrect);

答案 1 :(得分:1)

来自MSDN:

  

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

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

答案 2 :(得分:1)

新版OpenCV中没有CvvImage。使用以下代码,您可以将Mat转换为CImage ,然后在任何地方显示CImage:

int Mat2CImage(Mat *mat, CImage &img){
  if(!mat || mat->empty())
    return -1;
  int nBPP = mat->channels()*8;
  img.Create(mat->cols, mat->rows, nBPP);
  if(nBPP == 8)
  {
    static RGBQUAD pRGB[256];
    for (int i = 0; i < 256; i++)
        pRGB[i].rgbBlue = pRGB[i].rgbGreen = pRGB[i].rgbRed = i;
    img.SetColorTable(0, 256, pRGB);
  }
  uchar* psrc = mat->data;
  uchar* pdst = (uchar*) img.GetBits();
  int imgPitch = img.GetPitch();
  for(int y = 0; y < mat->rows; y++)
  {
    memcpy(pdst, psrc, mat->cols*mat->channels());//mat->step is incorrect for those images created by roi (sub-images!)
    psrc += mat->step;
    pdst += imgPitch;
  }

  return 0;
}