2021年2月17日水曜日

OpenCV copy between cv::Mat and Windows BITMAP 忘備録

opencv のコードを一部修正したくて、vcpkg の opencv を update したら、バージョン 3.4.3 から 4.3.0 にアップデートされた。
既存コードをコンパイルしてみると、IplImage が定義されていないと怒られてしまう。どうやら、IplImage が deprecated になったようだ。

どこで IplImage を使っていたかと言うと、BITMAPハンドルとcv::Matの相互変換部分。
cv::Mat BitmapToMat(HANDLE hBitmap) {
  cv::Mat result;
  {
    BITMAP bm;
    GetObject(hBitmap, sizeof(BITMAP), &bm );
    result = cv::Mat( bm.bmHeight, bm.bmWidth, CV_8UC4, cv::Scalar(255,255,255,255) );
    IplImage img = result;
    memcpy( img.imageData, bm.bmBits, bm.bmWidthBytes * bm.bmHeight );
  }
  return result;
}

HBITMAP MatToBitmap(const cv::Mat& src, HDC hMemDC) {
  HBITMAP hBitmap = NULL;
  if( !src.empty() && src.cols > 0 && src.rows > 0 ) {
    BITMAPINFO bi;
    bi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
    bi.bmiHeader.biWidth       = src.cols;
    bi.bmiHeader.biHeight      = src.rows;
    bi.bmiHeader.biPlanes      = 1;
    bi.bmiHeader.biBitCount    = 32;
    bi.bmiHeader.biCompression = BI_RGB;
    {
      LPDWORD lpPixels;
      hBitmap = CreateDIBSection( hMemDC, &bi, DIB_RGB_COLORS, reinterpret_cast<void**>(&lpPixels), NULL, 0 );
      GdiFlush();
    }
    BITMAP bm;
    GetObject(hBitmap, sizeof(BITMAP), &bm);
    cv::Mat rev;
    cv::flip(src, rev, 0);
    IplImage img = rev;
    memcpy( bm.bmBits, img.imageData, src.cols * src.rows * 4 );
  }
  return hBitmap;
}
どう手直ししたら良いのかわからなくて、ググってみたが情報が少ない。
これは需要があるかもしれん?と思って、ここに記すことにした
cv::Mat BitmapToMat(HANDLE hBitmap) {
  cv::Mat result;
  {
    BITMAP bm;
    GetObject(hBitmap, sizeof(BITMAP), &bm );
    result = cv::Mat( bm.bmHeight, bm.bmWidth, CV_8UC4, (void*)bm.bmBits );
  }
  return result;
}

HBITMAP MatToBitmap(const cv::Mat& src, HDC hMemDC) {
  HBITMAP hBitmap = NULL;
  if( !src.empty() && src.cols > 0 && src.rows > 0 ) {
    BITMAPINFO bi;
    bi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
    bi.bmiHeader.biWidth       = src.cols;
    bi.bmiHeader.biHeight      = src.rows;
    bi.bmiHeader.biPlanes      = 1;
    bi.bmiHeader.biBitCount    = 32;
    bi.bmiHeader.biCompression = BI_RGB;
    {
      LPDWORD lpPixels;
      hBitmap = CreateDIBSection( hMemDC, &bi, DIB_RGB_COLORS, reinterpret_cast<void**>(&lpPixels), NULL, 0 );
      GdiFlush();
    }
    BITMAP bm;
    GetObject(hBitmap, sizeof(BITMAP), &bm);
    cv::Mat rev;
    cv::flip(src, rev, 0);
    memcpy( bm.bmBits, rev.ptr(), src.cols * src.rows * 4 );
  }
  return hBitmap;
}
ポインタをダイレクトに扱っているので、適正に使用しないと Abnormal Termination を引き起こすでしょう。

0 件のコメント: