Problem

掲題の件、普通は下記のような形でRAWデータ (ここでは、画素値だけを格納したデータ形式) だけを抜き出す。

1
2
3
var mat = Cv2.ImRead(@"Test.png", ImreadModes.GrayScale);
var raw = new byte[mat.Total()];
Marshal.Copy(mat.Data, raw, 0, raw.Length);

問題は、あるMatからROIを指定した後に、ROIで抽出されたMatをRAWデータを抜き出す場合。
つまり下記のようなケース。

1
2
3
4
5
6
7
var mat = Cv2.ImRead(@"Test.png", ImreadModes.GrayScale);

// ROIを設定
var cropped = new Mat(mat, new Rect(50, 50, 100, 100));

var raw = new byte[cropped.Total()];
Marshal.Copy(cropped.Data, raw, 0, raw.Length);

上記のケースで抜き出されるRAWデータは壊れているようなデータになる。

ROIを指定した場合、抜き出されたMatは、元のMatのデータ領域を指し示しているだけで、コピーでは無い。
そのため、抜き出されたMatのDataプロパティからポインタを介してメモリ領域から連続したデータを抜き出しても意味が無い。

Solution

回答は下記。

1
2
3
4
5
6
7
8
9
10
11
var mat = Cv2.ImRead(@"Test.png", ImreadModes.GrayScale);

// ROIを設定
var temp = new Mat(mat, new Rect(50, 50, 100, 100));

// ROIを設定した領域を新しいMatとして切り出す
var cropped = new Mat(100, 100, MatType.CV_8U);
temp.CopyTo(cropped);

var raw = new byte[cropped.Total()];
Marshal.Copy(cropped.Data, raw, 0, raw.Length);

OpenCvSharp.Mat.CopyToメソッドを利用して、ROIで切り出したMatを新しく確保したMatにコピーしています。
これで意図した結果になります。