物体追跡
■ 動的輪郭追跡
動的輪郭追跡とは,変形する輪郭(物体形状そのものの輪郭が変形しない場合でも,画像に投影された輪郭が変形する場合がある) を逐次計算する(多くの場合は反復計算)手法である. 追跡対象となる物体は,それらの手法により,三次元形状物体,変形物体,関節構造体など様々である.Opencvで実装されているsnakeは,動的輪郭追跡手法の最も基本的な手法の一つである. snakeでは,内部エネルギーと外部エネルギーの和が最小になるような輪郭を求める. 適切な輪郭を得る為には各エネルギーの重みとなるパラメータが重要な役割を果たすが, これらのパラメータを決定するためには,追跡物体形状や背景画像の特徴がある程度既知である必要がある. また,基本的なsnakeでは,探索空間が二次元画像そのもので表される空間なので,輪郭の自由度が高い分,影などの外乱の影響を受けやすい.
サンプル
snakeによる輪郭追跡(静止画) cvSnakeImage
snakeにより動的輪郭追跡を行う(今回は対象が静止画なので,どちらかというと輪郭検出)
サンプルコード
#include <cv.h> #include <highgui.h> #include <math.h> #include <stdio.h> typedef struct parameter Parameter; struct parameter { float alpha; float beta; float gamma; }; int main (int argc, char **argv) { int i, j = 0, c; IplImage *src_img, *dst_img; CvPoint *contour; CvPoint center; int length = 60; /* 動的輪郭を構成する点数 */ Parameter snake_param = { 0.45, 0.35, 0.2 }; /* cvSnakeImage のパラメータ */ CvFont font; char iter[8]; // (1)画像を読み込む if (argc < 2 || (src_img = cvLoadImage (argv[1], CV_LOAD_IMAGE_GRAYSCALE)) == 0) return -1; dst_img = cvCreateImage (cvGetSize (src_img), IPL_DEPTH_8U, 3); cvInitFont (&font, CV_FONT_HERSHEY_DUPLEX, 0.7, 0.7); center.x = src_img->width / 2; center.y = src_img->height / 2; // (2)動的輪郭の初期化 contour = (CvPoint *) cvAlloc (sizeof (CvPoint) * length); for (i = 0; i < length; i++) { contour[i].x = (int) (center.x * cos (2 * CV_PI * i / length) + center.x); contour[i].y = (int) (center.y * sin (2 * CV_PI * i / length) + center.y); } // (3)初期輪郭の描画 cvCvtColor (src_img, dst_img, CV_GRAY2RGB); for (i = 0; i < length - 1; i++) { cvLine (dst_img, contour[i], contour[i + 1], CV_RGB (255, 0, 0), 2, 8, 0); } cvLine (dst_img, contour[length - 1], contour[0], CV_RGB (255, 0, 0), 2, 8, 0); cvNamedWindow ("Snakes", CV_WINDOW_AUTOSIZE); cvShowImage ("Snakes", dst_img); cvWaitKey (0); /* 動的輪郭の収束計算(過程を表示する) */ while (1) { // (4)動的輪郭の輪郭計算 cvSnakeImage (src_img, contour, length, &snake_param.alpha, &snake_param.beta, &snake_param.gamma, CV_VALUE, cvSize (15, 15), cvTermCriteria (CV_TERMCRIT_ITER, 1, 0.0), 1); // (5)計算された動的輪郭の描画 cvCvtColor (src_img, dst_img, CV_GRAY2RGB); for (i = 0; i < length - 1; i++) { cvLine (dst_img, contour[i], contour[i + 1], CV_RGB (255, 0, 0), 2); } cvLine (dst_img, contour[length - 1], contour[0], CV_RGB (255, 0, 0), 2); snprintf (iter, 8, "%03d", ++j); cvPutText (dst_img, iter, cvPoint (15, 30), &font, CV_RGB (0, 0, 255)); // (6)結果の表示 cvShowImage ("Snakes", dst_img); c = cvWaitKey (0); if (c == '\x1b') break; } cvDestroyWindow ("Snakes"); cvReleaseImage (&src_img); cvReleaseImage (&dst_img); return 0; }
// (1)画像を読み込む
コマンド引数で指定されたファイル名の画像(入力画像)をオープンし,関数
cvLoadImage()で読み込む.2番目の引数にCV_LOAD_IMAGE_GRAYSCALE
を指定することで,元画像をグレースケール画像として読み込む.
また,結果を表示するために,入力画像と同一サイズのカラー画像を作成する.
// (2)動的輪郭の初期化
初期輪郭の位置を決定する.本来は,追跡される物体の形状に応じた適切な初期輪郭が設定されるべきであるが,
今回は単に,与えられた画像矩形に内接するような楕円を初期輪郭として利用している.
// (3)初期輪郭の描画
初期化された輪郭を描画して,実際に表示する.何かキーが押下されるまで待つ.
// (4)動的輪郭の輪郭計算
動的輪郭の輪郭を計算する.このサンプルでは,入力画像に対する前処理など
は何も行っていないが,実際には,例えばノイズの除去やコントラストの強調,
あるいはエッジの検出などが前処理として行われる場合がある.
ここでは,輪郭が収束する過程を表示するために,関数
cvSnakeImage()が1回の反復計算しか行わないようにパラメータを設定している(CvTermCriteria).
例えば,以下のようにすると,
「100回反復計算が行われるか,あるいは各反復計算において移動する点の数
が0以下(全ての点が移動しなくなる)まで」,関数cvSnakeImage()内で反復計算が行われてから返る.
つまり,通常は,反復計算の為のループは必要ない.
cvSnakeImage( src_img, contour, length, &snake_param.alpha, &snake_param.beta, &snake_param.gamma, CV_VALUE, cvSize(15, 15), cvTermCriteria( CV_TERMCRIT_ITER, 100, 0.0), 1);また,勾配フラグ(関数cvSnakeImage()の最後の引数)が1なので,画像勾配がエネルギー場として利用される. その他,各引数の詳細については,リファレンスマニュアルを参照のこと.
// (5)計算された動的輪郭の描画
計算され,更新された輪郭(ここでは,1ステップ分),および,現在の反復数を画像上に描画する.
// (6)結果の表示
処理結果を表示する.
"Esc"キーが押された場合は終了し,それ以外が押された場合は,次の反復計算に入る.
実行結果例
初期位置 | iter=10 | iter=30 | iter=50 |