投稿者:

OpenCV cv::Matとメモリ

2016年9月30日 (開発者日記)

OpenCVにおいて画像を格納するクラスはほとんどの方がcv::Matクラスを使用していると思います。Matクラスの振る舞いを理解しておくとコーディングがはかどります。


cv::Mat blue(300,300,CV_8UC3,cv::Scalar(0,0,255));
cv::Mat copy = blue;
for(int y = 0;y < copy.rows;++y){
for(int x = 0;x < copy.cols;++x){
for(int i = 0;i < 3;++i){
copy.data[copy.step * y + copy.channels() * x + i] = 255;
}
}
}

みたいなコードがあったときに、変数copyは白一色を表しますが、Mat型では初期化演算子、代入演算子ともに値のコピーを作成するのではなく参照先のコピーを作るだけです。つまりcopyが指しているメモリ空間は変数blueと共用していて、copyの値を書き換えるとblueの値も書き換わってしまいます。この結果blueは白色の画像になります。

メモリーの共有を防ぐには
cv::Mat copy = blue.clone();
という様に書きます。

OpenCVでは前者を浅いコピー、後者を深いコピーといいます。前者のほうが高速にコピーを行えます。

なぜOpenCVがこのような使用になっているかというと、画像の範囲を指定して処理を行いたいときにこの使用が生きてきます。

 

例えば画像の中心だけ画像処理させたいとき、このように書けます。

cv::Mat white(300,300,CV_8UC3,cv::Scalar(255,255,255));
cv::Mat roi = white(cv::Rect(150,150,150,150));
for(int y = 0;y < roi.rows;++y){
for(int x = 0;x < roi.cols;++x){
for(int i = 0;i < 3;++i){
roi.data[roi.step * y + roi.channels() * x + i] = 0;
}
}
}

このコードでは白い画像の中心150*150ピクセルが黒色になります。

このように画像の範囲を指定して処理を行いたいときに、威力を発揮します。(自分はそれしか知りませんが、ほかにも使用用途があれば教えてください…)

コメントは受け付けていません。