About BBS

輪郭処理

作成者: 怡土順一, 最終変更者: 怡土順一, 最終変更リビジョン: 355, 最終変更日時: 2007-12-04 13:54:49 +0900 (火, 04 12月 2007)

■ 輪郭処理

OpenCVの輪郭処理では,検出された輪郭(を表す点列)に対しての処理を行う. 輪郭の近似や,長さ,面積の算出,また,二分木構造を利用した輪郭同士の比 較などを行う関数が用意されている.

サンプル


点列を包含する矩形 cvBoundingRect

点列を包含する矩形を求める

サンプルコード

#include <cv.h> #include <highgui.h> #include <time.h> int main (int argc, char **argv) { int i; IplImage *img = 0; CvMemStorage *storage = cvCreateMemStorage (0); CvSeq *points; CvRNG rng = cvRNG (time (NULL)); CvPoint pt; CvRect rect; // (1)画像を確保し初期化する img = cvCreateImage (cvSize (640, 480), IPL_DEPTH_8U, 3); cvZero (img); // (2)点列を生成する points = cvCreateSeq (CV_SEQ_ELTYPE_POINT, sizeof (CvSeq), sizeof (CvPoint), storage); for (i = 0; i < 20; i++) { pt.x = cvRandInt (&rng) % (img->width / 2) + img->width / 4; pt.y = cvRandInt (&rng) % (img->height / 2) + img->height / 4; cvSeqPush (points, &pt); cvCircle (img, pt, 3, CV_RGB (0, 255, 0), CV_FILLED); } // (3)点列を包含する矩形を求めて描画する rect = cvBoundingRect (points, 0); cvRectangle (img, cvPoint (rect.x, rect.y), cvPoint (rect.x + rect.width, rect.y + rect.height), CV_RGB (255, 0, 0), 2); // (4)画像の表示,キーが押されたときに終了 cvNamedWindow ("BoundingRect", CV_WINDOW_AUTOSIZE); cvShowImage ("BoundingRect", img); cvWaitKey (0); cvDestroyWindow ("BoundingRect"); cvReleaseImage (&img); cvReleaseMemStorage (&storage); return 0; }

// (1)画像を確保し初期化する
このサンプルでは,外部画像を読み込まずに,プログラム内部で画像を用意する. また,作成されたカラー画像を,黒(0)で塗りつぶして初期化する.

// (2)点列を生成する
関数cvRandInt()を用いて,画像内のある範囲に収まるようなランダムな点列を生成する. また,個々の点を中心とする小さな円を画像に描画し,点の位置を表す. このサンプルでは,ランダムな点列を用いているが,もちろん事前に検出した 輪郭(を構成する点列)に対しても,処理を行うことができる.

// (3)点列を包含する矩形を求めて描画する
関数cvBoundingRect()を用いて,点列を包含する最小の矩形(ただし傾いていない)を求める. 関数cvMinAreaRect2()との違いは,この傾きを考慮するか否かである. cvBoundingRect()はcvRectを返すが,cvMinAreaRect2()はcvBox2Dを返す. 求められたcvRectを画像に描画する.

// (4)画像の表示,キーが押されたときに終了
結果の画像を表示し,何かキーが押されるまで待つ.

実行結果例


輪郭領域の面積と輪郭の長さ cvContourArea, cvArcLength

輪郭によって区切られた領域の面積と,輪郭の長さを求める

サンプルコード

#include <cv.h> #include <highgui.h> #include <time.h> #include <math.h> #include <stdio.h> int main (int argc, char **argv) { int i, size = 500; char text[2][64]; double scale, area, length; IplImage *img = 0; CvMemStorage *storage = cvCreateMemStorage (0); CvSeq *points; CvRNG rng = cvRNG (time (NULL)); CvPoint pt0, pt1; CvRect rect; CvFont font; // (1)画像を確保し初期化する img = cvCreateImage (cvSize (size, size), IPL_DEPTH_8U, 3); cvZero (img); // (2)点列を生成する points = cvCreateSeq (CV_SEQ_POLYLINE, sizeof (CvSeq), sizeof (CvPoint), storage); scale = cvRandReal (&rng) + 0.5; pt0.x = int (cos (0) * size / 4 * scale + size / 2); pt0.y = int (sin (0) * size / 4 * scale + size / 2); cvCircle (img, pt0, 2, CV_RGB (0, 255, 0)); cvSeqPush (points, &pt0); for (i = 1; i < 20; i++) { scale = cvRandReal (&rng) + 0.5; pt1.x = int (cos (i * 2 * CV_PI / 20) * size / 4 * scale + size / 2); pt1.y = int (sin (i * 2 * CV_PI / 20) * size / 4 * scale + size / 2); cvLine (img, pt0, pt1, CV_RGB (0, 255, 0), 2); pt0.x = pt1.x; pt0.y = pt1.y; cvCircle (img, pt0, 3, CV_RGB (0, 255, 0), CV_FILLED); cvSeqPush (points, &pt0); } cvLine (img, pt0, *CV_GET_SEQ_ELEM (CvPoint, points, 0), CV_RGB (0, 255, 0), 2); // (3)包含矩形,面積,長さを求める rect = cvBoundingRect (points, 0); area = cvContourArea (points); length = cvArcLength (points, CV_WHOLE_SEQ, 1); // (4)結果を画像に書き込む cvRectangle (img, cvPoint (rect.x, rect.y), cvPoint (rect.x + rect.width, rect.y + rect.height), CV_RGB (255, 0, 0), 2); snprintf (text[0], 64, "Area: wrect=%d, contour=%d", rect.width * rect.height, int (area)); snprintf (text[1], 64, "Length: rect=%d, contour=%d", 2 * (rect.width + rect.height), int (length)); cvInitFont (&font, CV_FONT_HERSHEY_SIMPLEX, 0.7, 0.7, 0, 1, CV_AA); cvPutText (img, text[0], cvPoint (10, img->height - 30), &font, cvScalarAll (255)); cvPutText (img, text[1], cvPoint (10, img->height - 10), &font, cvScalarAll (255)); // (5)画像を表示,キーが押されたときに終了 cvNamedWindow ("BoundingRect", CV_WINDOW_AUTOSIZE); cvShowImage ("BoundingRect", img); cvWaitKey (0); cvDestroyWindow ("BoundingRect"); cvReleaseImage (&img); cvReleaseMemStorage (&storage); return 0; }

// (1)画像を確保し初期化する
このサンプルでは,外部画像を読み込まずに,プログラム内部で画像を用意する. また,作成されたカラー画像を,黒(0)で塗りつぶして初期化する.

// (2)点列を生成する
関数cvRandInt()を用いて,画像内のある範囲に収まるようなランダムな点列を生成する. ただし,面積を求める際に分かり易いように自己交差しないようにする. また,個々の点を中心とする小さな円を画像に描画し,点の位置を表す. さらに,閉じた領域になるように更に点列同士を結ぶ線分を描画する. このサンプルでは,ランダムな点列を用いているが,もちろん事前に検出した 輪郭(を構成する点列)などに対しても,処理を行うことができる.

// (3)包含矩形,面積,長さを求める
前述のサンプルと同様に,関数cvBoundingRect()を用いて点列を包含する矩形領域を求める. さらに,関数cvContourArea()によって点列が構成する輪郭の面積を求め, 関数cvArcLength()にってその長さ(周囲長)を求める. cvContourArea()の2番目の引数は,輪郭のどの部分の面積を計算するかを表しており, この引数が指定されない場合にはデフォルト引数であるCV_WHOLE_SEQが用いられる. この場合は,輪郭が表す領域全ての面積が求められる. cvArcLength()の2番目の引数の意味も同様であり,3番目の引数に0より大きい値を指定することで,輪郭を閉曲線として扱う. その他の値については,リファレンスを参照すること.

// (4)結果を画像に書き込む
包含矩形,包含矩形の面積と長さ,輪郭の面積と長さ,を画像に書き込む.

// (5)画像を表示,キーが押されたときに終了
結果の画像を表示し,何かキーが押されるまで待つ.

実行結果例

OpenCV-1.0 リファレンス マニュアル
OpenCV-1.1pre リファレンス マニュアル
OpenCVサンプルコード


画素値の直接操作
部分画像のシャッフル
画像の連結
画像のコピー
画像形状の変形
タイリング
画像の反転
逆行列(擬似逆行列)の計算
色空間の写像
離散フーリエ変換
階層構造を持つ輪郭の座標取得
図形の描画
ポリゴンの描画
凸ポリゴンの描画
テキストの描画
IplImage構造体情報の保存
マップのシーケンスを保存
IplImage構造体情報の読み込み
マップのシーケンスを読み込む
K-means法によるクラスタリング
クラスタリングによる減色処理
エッジの検出
コーナーの検出
並進移動のためのピクセルサンプリング
回転移動のためのピクセルサンプリング
画像のサイズ変更
画像のアフィン変換(1)
画像のアフィン変換(2)
画像の透視投影変換
全方位画像の透視投影変換
モルフォロジー変換
平滑化
ユーザ定義フィルタ
境界線の作成
画像の二値化
画像の二値化(大津の手法)
画像ピラミッドの作成
画像ピラミッドを用いた画像の領域分割
平均値シフト法による画像のセグメント化
Watershedアルゴリズムによる画像の領域分割
輪郭の検出と描画
画像のモーメントを計算
ハフ変換による直線検出
ハフ変換による円検出
距離変換とその可視化
不要オブジェクトの除去
ヒストグラムの描画
ヒストグラム間の距離
二次元のヒストグラム
バックプロジェクションパッチ
ヒストグラムの均一化
テンプレートマッチング
形状のマッチング
点列を包含する矩形
輪郭領域の面積と輪郭の長さ
二つの矩形を包含する矩形
楕円のフィッティング
点列を包含する図形
動的背景更新による物体検出
snakeによる輪郭追跡(静止画)
オプティカルフロー1
オプティカルフロー2
オプティカルフロー3
Condensation
顔の検出
カメラキャリブレーション
歪み補正
マップを利用した歪み補正
サポートベクターマシン
画像の各ピクセル値を特徴ベクトルとしたSVMの学習
画像の各ピクセル値を特徴ベクトルとしたSVMによる物体検出
マウスイベントの取得
トラックバーの利用
カメラからの画像キャプチャ
動画としてファイルへ書き出す
ラベリング