在 MFC/C++ 中显示图像使用 OpenCV 的应用程序

发布于 2024-11-15 20:04:42 字数 379 浏览 2 评论 0原文

我想在 MFC 应用程序中显示我使用 OpenCV(cvCaptureFromAVI 函数)从 avi 文件捕获的帧。

我是 MFC 的新手,但感觉我已经接近让它工作了。但框架不是显示在图片框中,而是显示在新窗口中。

cvGetWindowName 始终返回空值。

有我的代码:

CWnd* hPic = 0;
hPic = GetDlgItem(IDC_STATICPIC1);  
const char* szWindName = cvGetWindowName(hPic->GetSafeHwnd());
cvShowImage(szWindName, frame_copy);

I would like to display in a MFC application, frames that I capture from an avi file with OpenCV (cvCaptureFromAVI function).

I'm new to MFC but feel like I'm close to making it work. But instead of the frames being displayed in the picture box they are displayed in a new window.

cvGetWindowName returns always a null value.

There is my code:

CWnd* hPic = 0;
hPic = GetDlgItem(IDC_STATICPIC1);  
const char* szWindName = cvGetWindowName(hPic->GetSafeHwnd());
cvShowImage(szWindName, frame_copy);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

戒ㄋ 2024-11-22 20:04:42

因此,经过长期研究,我找到了一些可以让它发挥作用的东西。

解决方案是创建窗口,然后将其插入图片框内。我不确定这是否是好的做法,但目前我还没有找到更好的做法。

cvNamedWindow("IDC_STATIC_OUTPUT", 0); 
cvResizeWindow("IDC_STATIC_OUTPUT", 420, 240);

HWND hWnd = (HWND) cvGetWindowHandle("IDC_STATIC_OUTPUT"); 
HWND hParent = ::GetParent(hWnd); 
     ::SetParent(hWnd, GetDlgItem(IDC_PIC1)->m_hWnd); 
     ::ShowWindow(hParent, SW_HIDE); 

cvShowImage("IDC_STATIC_OUTPUT", frame_copy);

在本例中,图片框称为 IDC_PIC1,frame_copy 是 OpenCV IplImage。

希望这对某人有帮助。

So I found something to make it work after long researches.

The solution is to create the window and then insert it inside the picture box. I'm not sure it's good practice but I haven't found anything better for now.

cvNamedWindow("IDC_STATIC_OUTPUT", 0); 
cvResizeWindow("IDC_STATIC_OUTPUT", 420, 240);

HWND hWnd = (HWND) cvGetWindowHandle("IDC_STATIC_OUTPUT"); 
HWND hParent = ::GetParent(hWnd); 
     ::SetParent(hWnd, GetDlgItem(IDC_PIC1)->m_hWnd); 
     ::ShowWindow(hParent, SW_HIDE); 

cvShowImage("IDC_STATIC_OUTPUT", frame_copy);

In this case the picture box is called IDC_PIC1 and frame_copy is a OpenCV IplImage.

Hope this helps somebody.

孤独陪着我 2024-11-22 20:04:42

使用以下代码,您可以将 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;
}

Using the following code you can convert Mat to CImage and then display CImage everywhere you want:

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;
}
烟─花易冷 2024-11-22 20:04:42

注意:如果将 StretchDIBits() 方法与 BITMAPINFO 方法一起使用,则必须注意 StretchDIBits() 期望原始 OpenCV Mat::data 指针的行长度为 4 字节的偶数倍!如果没有,当您尝试通过 StretchDIBits() 将数据复制到 DC 时,您会遇到奇怪的剪切 - 图像不仅沿某个角度剪切,而且颜色也全部被丢弃。

这是我的代码的完整工作版本,它还支持在目标控件的矩形中维护图像长宽比。它可能可以做得更快一点,但目前可以使用:

void AdjustAspectImageSize( const Size& imageSize,
                            const Size& destSize, 
                                  Size& newSize )
{
   double destAspectRatio   =  float( destSize.width  )  /  float( destSize.height  );
   double imageAspectRatio  =  float( imageSize.width )  /  float( imageSize.height );

   if ( imageAspectRatio > destAspectRatio )
   {
      // Margins on top/bottom
      newSize.width    =   destSize.width;
      newSize.height   =   int( imageSize.height  *  
                                    ( double( destSize.width )  /  double( imageSize.width ) ) );
   }
   else
   {
      // Margins on left/right
      newSize.height   =   destSize.height;
      newSize.width    =   int( imageSize.width  *
                                    ( double( destSize.height )  /  double( imageSize.height ) ) );
   }
}


void DrawPicToHDC( Mat  cvImg, 
                   UINT nDlgID, 
                   bool bMaintainAspectRatio /* =true*/  )
{
   // Get the HDC handle information from the ID passed
   CDC* pDC  =  GetDlgItem(nDlgID)->GetDC();
   HDC  hDC  =  pDC->GetSafeHdc();

   CRect rect;
   GetDlgItem(nDlgID)->GetClientRect(rect);

   Size winSize( rect.right, rect.bottom );

   // Calculate the size of the image that
   // will fit in the control rectangle.
   Size origImageSize( cvImg.cols, cvImg.rows );
   Size imageSize;
   int  offsetX;
   int  offsetY;

   if ( ! bMaintainAspectRatio )
   {
      // Image should be the same size as the control's rectangle
      imageSize = winSize;
   }
   else
   {
      Size newSize;

      _AdjustAspectImageSize( origImageSize,
                              winSize,
                              imageSize );
   }

   offsetX   =   ( winSize.width  - imageSize.width  )  /  2;
   offsetY   =   ( winSize.height - imageSize.height )  /  2;

   // Resize the source to the size of the destination image if necessary
   Mat cvImgTmp;

   resize( cvImg, 
           cvImgTmp, 
           imageSize,
           0,
           0,
           INTER_AREA );

   // To handle our Mat object of this width, the source rows must
   // be even multiples of a DWORD in length to be compatible with 
   // SetDIBits().  Calculate what the correct byte width of the 
   // row should be to be compatible with SetDIBits() below.
   int stride  =  ( ( ( ( imageSize.width * 24 )  +  31 )  &  ~31 )  >>  3 );

   // Allocate a buffer for our DIB bits
   uchar* pcDibBits  =  (uchar*) malloc( imageSize.height * stride );

   if ( pcDibBits != NULL )
   {
      // Copy the raw pixel data over to our dibBits buffer.
      // NOTE: Can setup cvImgTmp to add the padding to skip this.
      for ( int row = 0;  row < cvImgTmp.rows;  ++row )
      {
         // Get pointers to the beginning of the row on both buffers
         uchar* pcSrcPixel  =  cvImgTmp.ptr<uchar>(row);
         uchar* pcDstPixel  =  pcDibBits  +  ( row * stride );

         // We can just use memcpy
         memcpy( pcDstPixel,
                 pcSrcPixel,
                 stride );
      }

      // Initialize the BITMAPINFO structure
      BITMAPINFO bitInfo;

      bitInfo.bmiHeader.biBitCount       =  24;
      bitInfo.bmiHeader.biWidth          =   cvImgTmp.cols;
      bitInfo.bmiHeader.biHeight         =  -cvImgTmp.rows;
      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;      //winSize.height * winSize.width * * 3;
      bitInfo.bmiHeader.biXPelsPerMeter  =  0;
      bitInfo.bmiHeader.biYPelsPerMeter  =  0;

      // Add header and OPENCV image's data to the HDC
      StretchDIBits( hDC, 
                     offsetX, 
                     offsetY,
                     cvImgTmp.cols,
                     cvImgTmp.rows,
                     0, 
                     0,
                     cvImgTmp.cols,
                     cvImgTmp.rows,
                     pcDibBits,
                     & bitInfo, 
                     DIB_RGB_COLORS, 
                     SRCCOPY );

      free(pcDibBits);
   }

   ReleaseDC(pDC);
}

NOTE: If you use the StretchDIBits() method with the BITMAPINFO approach, you MUST be aware that StretchDIBits() expects the raw OpenCV Mat::data pointer to have row lengths in even multiples of 4 bytes! If not, you'll get freaky shearing when you try to copy the data to the DC via StretchDIBits() - where the image is not only sheered along an angle, but the colors are all be trashed as well.

Here is my completely working edition of the code, which also supports maintaining image aspect ratio in the target control's rectangle. It can probably be made a bit faster, but it works for now:

void AdjustAspectImageSize( const Size& imageSize,
                            const Size& destSize, 
                                  Size& newSize )
{
   double destAspectRatio   =  float( destSize.width  )  /  float( destSize.height  );
   double imageAspectRatio  =  float( imageSize.width )  /  float( imageSize.height );

   if ( imageAspectRatio > destAspectRatio )
   {
      // Margins on top/bottom
      newSize.width    =   destSize.width;
      newSize.height   =   int( imageSize.height  *  
                                    ( double( destSize.width )  /  double( imageSize.width ) ) );
   }
   else
   {
      // Margins on left/right
      newSize.height   =   destSize.height;
      newSize.width    =   int( imageSize.width  *
                                    ( double( destSize.height )  /  double( imageSize.height ) ) );
   }
}


void DrawPicToHDC( Mat  cvImg, 
                   UINT nDlgID, 
                   bool bMaintainAspectRatio /* =true*/  )
{
   // Get the HDC handle information from the ID passed
   CDC* pDC  =  GetDlgItem(nDlgID)->GetDC();
   HDC  hDC  =  pDC->GetSafeHdc();

   CRect rect;
   GetDlgItem(nDlgID)->GetClientRect(rect);

   Size winSize( rect.right, rect.bottom );

   // Calculate the size of the image that
   // will fit in the control rectangle.
   Size origImageSize( cvImg.cols, cvImg.rows );
   Size imageSize;
   int  offsetX;
   int  offsetY;

   if ( ! bMaintainAspectRatio )
   {
      // Image should be the same size as the control's rectangle
      imageSize = winSize;
   }
   else
   {
      Size newSize;

      _AdjustAspectImageSize( origImageSize,
                              winSize,
                              imageSize );
   }

   offsetX   =   ( winSize.width  - imageSize.width  )  /  2;
   offsetY   =   ( winSize.height - imageSize.height )  /  2;

   // Resize the source to the size of the destination image if necessary
   Mat cvImgTmp;

   resize( cvImg, 
           cvImgTmp, 
           imageSize,
           0,
           0,
           INTER_AREA );

   // To handle our Mat object of this width, the source rows must
   // be even multiples of a DWORD in length to be compatible with 
   // SetDIBits().  Calculate what the correct byte width of the 
   // row should be to be compatible with SetDIBits() below.
   int stride  =  ( ( ( ( imageSize.width * 24 )  +  31 )  &  ~31 )  >>  3 );

   // Allocate a buffer for our DIB bits
   uchar* pcDibBits  =  (uchar*) malloc( imageSize.height * stride );

   if ( pcDibBits != NULL )
   {
      // Copy the raw pixel data over to our dibBits buffer.
      // NOTE: Can setup cvImgTmp to add the padding to skip this.
      for ( int row = 0;  row < cvImgTmp.rows;  ++row )
      {
         // Get pointers to the beginning of the row on both buffers
         uchar* pcSrcPixel  =  cvImgTmp.ptr<uchar>(row);
         uchar* pcDstPixel  =  pcDibBits  +  ( row * stride );

         // We can just use memcpy
         memcpy( pcDstPixel,
                 pcSrcPixel,
                 stride );
      }

      // Initialize the BITMAPINFO structure
      BITMAPINFO bitInfo;

      bitInfo.bmiHeader.biBitCount       =  24;
      bitInfo.bmiHeader.biWidth          =   cvImgTmp.cols;
      bitInfo.bmiHeader.biHeight         =  -cvImgTmp.rows;
      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;      //winSize.height * winSize.width * * 3;
      bitInfo.bmiHeader.biXPelsPerMeter  =  0;
      bitInfo.bmiHeader.biYPelsPerMeter  =  0;

      // Add header and OPENCV image's data to the HDC
      StretchDIBits( hDC, 
                     offsetX, 
                     offsetY,
                     cvImgTmp.cols,
                     cvImgTmp.rows,
                     0, 
                     0,
                     cvImgTmp.cols,
                     cvImgTmp.rows,
                     pcDibBits,
                     & bitInfo, 
                     DIB_RGB_COLORS, 
                     SRCCOPY );

      free(pcDibBits);
   }

   ReleaseDC(pDC);
}
几度春秋 2024-11-22 20:04:42

int DrawImageToHDC(IplImage* img, HDC hdc, int xDest, int yDest, UINT iUsage, DWORD rop)

    char m_chBmpBuf[2048];
    BITMAPINFO *m_pBmpInfo = 0;
    m_pBmpInfo = (BITMAPINFO*)m_chBmpBuf;
    m_pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    m_pBmpInfo->bmiHeader.biWidth = img->width;
    m_pBmpInfo->bmiHeader.biHeight = -img->height;
    m_pBmpInfo->bmiHeader.biBitCount = 24;

    m_pBmpInfo->bmiHeader.biPlanes = 1;
    m_pBmpInfo->bmiHeader.biCompression = BI_RGB;
    m_pBmpInfo->bmiHeader.biSizeImage = 0;
    m_pBmpInfo->bmiHeader.biXPelsPerMeter = 0;
    m_pBmpInfo->bmiHeader.biYPelsPerMeter = 0;
    m_pBmpInfo->bmiHeader.biClrUsed = 0;
    m_pBmpInfo->bmiHeader.biClrImportant = 0;

    return StretchDIBits(hdc, xDest, yDest, img->width, img->height, 0, 0,
img->width, img->height, img->imageData, m_pBmpInfo, DIB_RGB_COLORS, SRCCOPY);

用法:DrawImageToHDC(img, pDC->m_hDC, Area.left, Area.top, DIB_RGB_COLORS, SRCCOPY);

int DrawImageToHDC(IplImage* img, HDC hdc, int xDest, int yDest, UINT iUsage, DWORD rop)

    char m_chBmpBuf[2048];
    BITMAPINFO *m_pBmpInfo = 0;
    m_pBmpInfo = (BITMAPINFO*)m_chBmpBuf;
    m_pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    m_pBmpInfo->bmiHeader.biWidth = img->width;
    m_pBmpInfo->bmiHeader.biHeight = -img->height;
    m_pBmpInfo->bmiHeader.biBitCount = 24;

    m_pBmpInfo->bmiHeader.biPlanes = 1;
    m_pBmpInfo->bmiHeader.biCompression = BI_RGB;
    m_pBmpInfo->bmiHeader.biSizeImage = 0;
    m_pBmpInfo->bmiHeader.biXPelsPerMeter = 0;
    m_pBmpInfo->bmiHeader.biYPelsPerMeter = 0;
    m_pBmpInfo->bmiHeader.biClrUsed = 0;
    m_pBmpInfo->bmiHeader.biClrImportant = 0;

    return StretchDIBits(hdc, xDest, yDest, img->width, img->height, 0, 0,
img->width, img->height, img->imageData, m_pBmpInfo, DIB_RGB_COLORS, SRCCOPY);

Usage: DrawImageToHDC(img, pDC->m_hDC, Area.left, Area.top, DIB_RGB_COLORS, SRCCOPY);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文