画像と形状のモーメント
■ 画像と形状のモーメント
画像や形状の特徴を定量的に表現する方法の一つにモーメントがある.画像の(x_order+y_order)次の空間モーメントは次のように定義される.Mx_order,y_order=sumx,y(I(x,y)•xx_order•yy_order)
ここで,I(x,y)は座標(x, y) の輝度値であり,x_order, y_orderはそれぞれx方向,y方向の次数を示している.
2値画像の場合,0次モーメントM0,0が面積を表し,( M1,0/M0,0, M0,1/M0,0 )が重心座標を表す事になる.
サンプル
画像のモーメント
画像の各種モーメント値を計算する
サンプルコード
#include <stdio.h> #include <cv.h> #include <highgui.h> int main (int argc, char **argv) { char text[10][30]; int i; double spatial_moment, central_moment, norm_c_moment; IplImage *src_img = 0; CvFont font; CvSize text_size; CvMoments moments; CvHuMoments hu_moments; // (1)画像を読み込む.3チャンネル画像の場合はCOIがセットされていなければならない if (argc >= 2) src_img = cvLoadImage (argv[1], CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); if (src_img == 0) return -1; if (src_img->nChannels == 3 && cvGetImageCOI (src_img) == 0) cvSetImageCOI (src_img, 1); // (2)入力画像の3次までの画像モーメントを計算する cvMoments (src_img, &moments, 0); cvSetImageCOI (src_img, 0); // (3)モーメントやHuモーメント不変量を,得られたCvMoments構造体の値を使って計算する. spatial_moment = cvGetSpatialMoment (&moments, 0, 0); central_moment = cvGetCentralMoment (&moments, 0, 0); norm_c_moment = cvGetNormalizedCentralMoment (&moments, 0, 0); cvGetHuMoments (&moments, &hu_moments); // (4)得られたモーメントやHuモーメント不変量を文字として画像に描画 cvInitFont (&font, CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0, 0, 2, 8); snprintf (text[0], 30, "spatial=%.3f", spatial_moment); snprintf (text[1], 30, "central=%.3f", central_moment); snprintf (text[2], 30, "norm=%.3f", spatial_moment); snprintf (text[3], 30, "hu1=%f", hu_moments.hu1); snprintf (text[4], 30, "hu2=%f", hu_moments.hu2); snprintf (text[5], 30, "hu3=%f", hu_moments.hu3); snprintf (text[6], 30, "hu4=%f", hu_moments.hu4); snprintf (text[7], 30, "hu5=%f", hu_moments.hu5); snprintf (text[8], 30, "hu6=%f", hu_moments.hu6); snprintf (text[9], 30, "hu7=%f", hu_moments.hu7); cvGetTextSize (text[0], &font, &text_size, 0); for (i = 0; i < 10; i++) cvPutText (src_img, text[i], cvPoint (10, (text_size.height + 3) * (i + 1)), &font, cvScalarAll (0)); // (5)入力画像とモーメント計算結果を表示,キーが押されたときに終了 cvNamedWindow ("Image", CV_WINDOW_AUTOSIZE); cvShowImage ("Image", src_img); cvWaitKey (0); cvDestroyWindow ("Image"); cvReleaseImage (&src_img); return 0; }
// (1)画像を読み込む.3チャンネル画像の場合はCOIがセットされていなければならない
コマンド引数で指定されたファイル名の画像(入力画像)をオープンし,関数 cvLoadImage()で読み込む.もしも,指定された画像が3チャンネル画像であれば,COIがセットされていなければ,モーメントの計算が出来ないためチェックした上,一番最初のチャンネルを指定しておく.
// (2)入力画像の3次までの画像モーメントを計算する
画像の3次までの空間モーメントと中心モーメントを関数cvMoments()で計算する.
CvMoments構造体は,以下のように定義されており
typedef struct CvMoments { double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03; /* spatial moments */ double mu20, mu11, mu02, mu30, mu21, mu12, mu03; /* central moments */ double inv_sqrt_m00; /* m00 != 0 ? 1/sqrt(m00) : 0 */ } CvMoments;サンプル例の場合であれば,例えば直接,moments.m00 として0次モーメントの計算結果を取得する事もできる.
結果表示のため,COIの設定を解除しておく.
// (3)モーメントやHuモーメント不変量を得られたCvMoments構造体の値を使って計算する.
上のように直接構造体の内容にアクセスしても計算結果は取得できるが,OpenCVには関数cvGetSpatialMoment(), cvGetCentralMoment(), cvGetNormalizedCentralMoment()などで,必要な空間モーメントや中心モーメント,正規化された中心モーメント等を取得する事が出来る.サンプル例ではすべての0次モーメント値の取得を指定した.
またHuモーメント不変量も計算する.7つのHuモーメント不変量のそれぞれの意味は,リファレンスを参照の事.
// (4)得られた各種モーメント値やHuモーメント不変量を文字として画像に描画
ウィンドウを生成し,求めたモーメント値を表示するために,関数cvPutText()を用いて,値をテキストとして画像に上書きし,何かキーが押されるまで待つ.