cv::MatからCvMatへの変換時の注意点

C++の配列クラスからCの配列構造体への変換で嵌ったのでメモ。

正常ケース

OpenCVでは以下のような方法で、
cv::MatからCvMatに変換できます。

cv::Mat eye = cv::Mat::eye(3,3,CV_8UC1);
CvMat eyeC = eye;
std::cout << cv::Mat(&eyeC) << std::endl;

出力結果

[1, 0, 0;
  0, 1, 0;
  0, 0, 1]

問題ケース

しかし、次のような記載をすると、
eyeCが期待した結果になりません。

CvMat eyeC = cv::Mat( cv::Mat::eye(3,3,CV_8UC1) );
std::cout << cv::Mat(&eyeC) << std::endl;

出力結果

[221, 221, 221;
  221, 221, 221;
  221, 221, 221]

問題ケースの原因

原因は、eyeCの参照するデータ領域が解放されていることでした。
今回のようにcv::MatからCvMatに変換した場合、
CvMatはcv::Matで確保されたデータ領域を参照します。

しかし、問題ケースの“cv::Mat( cv::Mat::eye(3,3,CV_8UC1) )”は1行目が終わった時点で解放されます。
なので、2行目以降ではeyeCの参照するデータ領域は既に解放されていることになります。

ちなみに、今回の問題ケースはVisual StudioのDebugビルドで実行しており、
eyeCの出力結果はeye行列ではありません。
しかし、Releaseビルドの場合だと、
問題ケースにおけるeyeCの出力結果がeye行列になる場合があります。


気付きにくく、放っておくとひどいバグの原因になりそう。