OpenCV C++ matrix class
前回、OpenCV 2.0 – cv::Ptr ではスマートポインタである cv::Ptr について調べました。
今回はOpenCV 2.0のC++インタフェースの中でも重要な役割を持つ cv::Mat クラスについて。
このクラスは従来の IplImage 及び CvMat に取って代わるものになっていますが、
かなり大きいクラスなので何回かに分けて調べていきたいと思います。
cv::Mat はマルチチャンネルとROI(Region Of Interest)をサポートしている二次元行列です。
オブジェクトの生成方法は複数ありますが、ここでは基本的な方法から紹介します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
using namespace cv; using namespace std; // create() メソッド (5行5列,各要素が8ビット符号なし整数型 3チャンネル) // タイプ指定:CV_<bit-depth>{U|S|F}C<number_of_channels> Mat matA; matA.create(5, 5, CV_8UC3); // コンストラクタ (3行3列,各要素が32ビット浮動小数点型 1チャンネル) Mat matB(3, 3, CV_32FC1); // コンストラクタの引数に cv::Size を指定 Mat matC(Size(640, 480), CV_8UC3); // 二次元配列を使って初期化 double data[][3] = { {1,2,3}, {4,5,6}, {7,8,9} }; Mat matD(Size(3, 3), CV_64FC1, data); // std::vector を使って初期化 // デフォルトでは浅いコピー、第二引数にtrueを指定すると深いコピーになる // この場合、10行1列の行列が生成され、要素は全て0で初期化される vector<double> v(10); Mat matE(v); // or Mat matE(v, true); // cv::Scalar を使って初期化 Mat matF(5, 5, CV_32FC2, Scalar(1.0, 3.0)); // コピーコンストラクタ (浅いコピー, refcount++) Mat copy(matA); // clone() メソッド (深いコピー) Mat clone = matA.clone(); // ROIを設定 (cv::Rect で位置と大きさを指定) Mat roi(matC, Rect(10, 10, 100, 100)); // IplImage から cv::Mat に変換 IplImage* src_img = cvLoadImage("lena.jpg", CV_LOAD_IMAGE_COLOR); Mat img(src_img); // CvMat から cv::Mat に変換 CvMat* cv_mat = cvCreateMat(3, 3, CV_32FC1); Mat mat(cv_mat); |
次はMatクラスの構造について。
gdbで上のコードのmatAを見てみると、
1 2 3 4 5 6 7 8 9 10 11 |
(gdb) p matA $1 = { flags = 1124024336, rows = 5, cols = 5, step = 15, data = 0xb07ff0 "", refcount = 0xb0803c, datastart = 0xb07ff0 "", dataend = 0xb0803b "" } |
flags | // |
rows | 行数 |
cols | 列数 |
step | 一行のバイト数 |
data | データへのポインタ |
refcount | 参照カウントへのポインタ |
datastart | データの始まりへのポインタ |
dataend | データの終わりへのポインタ |
メンバは基本的にCvMatと同様のものを備えています。
flagsはMatクラスの各メソッドで内部的に利用されているものなので特に気にしなくて構いません。
また、サイズはIplImageと比べるとかなり小さく、sizeofしてみるとIplImageは112、Matは32となっています。
各要素のアドレスは以下のように計算します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// M(i, j) の要素のアドレス // elemSize() は1要素のバイト数を返す M.data + M.step*i + j*M.elemSize() // 要素の型が既知の場合は at(int y, int x) が利用可能 // 内部では、指定された型のポインタでキャストされた (data + step*y)[x] がreturnされている &M.at<double>(i, j) --------------------------------------- // 各行の先頭アドレスは ptr(int y) で取得可能 (内部では、return data + step*y) // 型指定しない場合は uchar* が返される M.ptr<double>(y) M.ptr(y) |
とりあえず今回はcv::Matクラスの構造を主に紹介しました。
次からは実際にこのクラスを利用していろいろな処理を行いたいと思います。
:: 追記
* IplImage, CvMat と cv::Mat の互換性について
とりあえず、ドキュメントに載っていたコードを使って確認を行いました。
1 2 3 4 5 6 7 8 9 |
/* IplImage -> cv::Mat -> CvMat の順で変換 */ IplImage* img = cvLoadImage("lena.jpg", CV_LOAD_IMAGE_COLOR); Mat mtx(img); CvMat oldmat = mtx; // OpenCV Error: Assertion failed~ は発生しないことを確認 CV_Assert(oldmat.cols == img->width && oldmat.rows == img->height && oldmat.data.ptr == (uchar*)img->imageData && oldmat.step == img->widthStep); |
関連記事:
OpenCV 2.0 – cv::Ptr
OpenCV 2.0を試してみた