OpenCV_cv::Mat が 4 バイト云々 と step について

OpenCV_画像を IplImage型 で読み込んで System::Drawing::Bitmap^ に変換、の続き。
よく分からんが、bitmap は 幅を 4 の倍数のバイトに調整しているが
mat の step は 4 の倍数にしていない、ということでいいか。

 

横幅が 4 の倍数でないとエラーのワケ

画像 1 行あたりのバイト数
IpImage → widthStep
cv::Mat → step

widthStep の場合、ビットマップファイルと同様に
4 バイト単位になるよう調整されていたが、
cv::imread 関数を使って読み込むと、
step の値は 4 バイト単位に調整されない ( 画像幅 × チャンネル数 ) 。

cvLoadImage を使って読込み、cv::Mat に変換した方がよい。
ex )

    cv::Ptr<IplImage> iplimg = cvLoadImage("test.bmp");
    cv::Mat img(iplimg);

cvLoadImage の第二引数
CV_LOAD_IMAGE_COLOR:3 チャンネルに変換
CV_LOAD_IMAGE_GRAYSCALE:1 チャンネルに変換
CV_LOAD_IMAGE_ANYCOLOR:入力画像のまま
指定しないと CV_LOAD_IMAGE_COLOR。

 

 

step の注意点

下記のコードは、srcdststep 値が異なる可能性がある。

     cv::Mat dst = src.clone();

 src の cols が 4 の倍数でなく、step が 4 の倍数になるように
IplImage から Mat を作った場合、clone( ) で確保した dst の step は
cols × channels ( 4 の倍数とならない場合がある ) で確保されてしまう。

ex ) ( 333 * 3 ) / 4  = 249.75 剰余は 3 。
幅 × 24bit だと → 333 * ( 8 * 3 ) / 4 = 1998 。剰余は 0 。

 

--Memo--
gcnew System::Drawing::Bitmap( の stride を 4 の倍数に調整した値を設定した。
例外は発生しなくなったが、画像が斜めになってしまった。

  // 調整
  int tmpStep = mat.step;
  int padding = tmpStep % 4;
  tmpStep += 4 - padding;

メモリの確保の仕方が間違っているバグと同じ現象らしい。

 mat.step が 10 として、bitmap で表示したいので 12 幅とした場合、
12 幅に mat の 10 データ分がセットされるが、残り 2 データ分が必要。
この分は mat の 次の行にある頭 2 データ分がセットされる。故に斜めになるのかと。

なので、BitmapData を使って画像の 1 行ごとにデータをコピー。

    System::Drawing::Bitmap ^ bmp = gcnew Syste 略
    System::Drawing::Imaging::BitmapData ^ data = bmp->LockBits  略
    for (int y = 0; y < mat.rows; ++y)
    {
        std::copy(mat.data + y * mat.step,
            mat.data + (y + 1) * mat.step,
            (unsigned char *)data->Scan0.ToPointer() + y * tmpStep);
    }
    bmp->UnlockBits(data);

mat 画像がメモリ上で連続してない場合は画素にアクセスして代入するしかない ?

 

 

Mat 初期化時の引数 step

Mat::Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0) から。

行列の各行が占めるバイト数を指定できる。
各行の終端にパディングバイトが存在すれば,それも含む。
このパラメータが指定されない場合 ( cv::AUTO_STEP にセットされて )
パディングは存在しないとみなされ、実際の step
cols * elemSize() として計算される。パディング:詰め物

 

Mat::elemSize():
要素サイズをバイト単位で返す。( 1 画素あたりのバイト数 )
CV_16SC3 の場合、3 * sizeof(short) または 6 を返す。
CV_16U は unsigned short 。short は 2 バイト。

 

Mat::elemSize1():
これはチャンネル毎のサイズをバイト単位で返す。
つまりチャンネル数は無視される。
CV_16SC3 の場合、sizeof(short) または 2 を返す。

 

 

 

こちらから。
https://imagingsolution.net/program/opencv/iplimage2bitmap/
http://imagingsolution.blog.fc2.com/blog-entry-178.html
http://opencv.jp/opencv-1.0.0/document/opencvref_highgui_loadsave.html
OpenCV: C API
基本構造体 — opencv 2.2 documentation
https://docs.opencv.org/3.4/d3/d63/classcv_1_1Mat.html#aba7a5ef00b22b70668fba575005dfe55
https://docs.opencv.org/3.4/d3/d63/classcv_1_1Mat.html#a51615ebf17a64c968df0bf49b4de6a3a
http://www.wakayama-u.ac.jp/~chen/cmake/LearningOpenCV.html

以上。