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 を引き起こすでしょう。

2021年2月3日水曜日

Proj4 C++ 座標変換忘備録

Proj4 ver 6.3.1 で座標変換するコードの習作
#include <proj.h>
#include <iostream>

int main() {

  PJ_CONTEXT* C;
  PJ*         P;
  PJ*         P_for_GIS;

  C = proj_context_create();
  P = proj_create_crs_to_crs( C, "EPSG:3857", "EPSG:6679", NULL );
  if( !P ) {
    std::cerr << "Fail to create proj crs conversion" << std::endl;
    return 1;
  }
  P_for_GIS = proj_normalize_for_visualization(C,P);
  if( !P_for_GIS ) {
    std::cerr << "Fail to normalize proj" << std::endl;
    return 1;
  }
  proj_destroy(P);
  P = P_for_GIS;
  
  PJ_COORD sp = proj_coord(15734773.4,5323579.9,0,0);
  
  PJ_COORD dp = proj_trans(P, PJ_FWD, sp);
  std::cout << std::fixed << sp.v[0] << "," << sp.v[1] << std::endl;
  std::cout << " to ";
  std::cout << dp.v[0] << "," << dp.v[1] << std::endl;
  
  proj_destroy(P);
  proj_context_destroy(C);
  
  return 0;
}
参考: https://github.com/OSGeo/PROJ/blob/master/examples/pj_obs_api_mini_demo.c