曲線と形状
■ 曲線と形状の描画
OpenCVでは,数種類のプリミティブ形状を描画する関数が用意されている. 用意されている形状は,線分,矩形,円,楕円(扇形),凸多角形,任意の多角形である. なんらかの検出結果や探索範囲などを実際の画像上に重畳表示する際や, ヒストグラムなどのグラフ作成(可視化)の際などに利用される.サンプル
図形の描画 cvLine, cvRectangle, cvCircle, cvEllipse
線分,矩形,円,楕円(扇形を含む)をランダムに描画する
サンプルコード
#include <cv.h> #include <highgui.h> #include <time.h> int main (int argc, char **argv) { int i; IplImage *img = 0; CvRNG rng = cvRNG (time (NULL)); CvPoint pt1, pt2; CvScalar rcolor; int irandom; // (1)画像領域を確保し初期化する img = cvCreateImage (cvSize (800, 800), IPL_DEPTH_8U, 3); cvZero (img); // (2)ランダムな線分を描画する for (i = 0; i < 5; i++) { pt1.x = cvRandInt (&rng) % (img->width); pt1.y = cvRandInt (&rng) % (img->height); pt2.x = cvRandInt (&rng) % (img->width); pt2.y = cvRandInt (&rng) % (img->height); irandom = cvRandInt (&rng); rcolor = CV_RGB (irandom & 255, (irandom >> 8) & 255, (irandom >> 16) & 255); cvLine (img, pt1, pt2, rcolor, cvRandInt (&rng) % 4, CV_AA, 0); } // (3)ランダムな矩形を描画する for (i = 0; i < 5; i++) { pt1.x = cvRandInt (&rng) % (img->width); pt1.y = cvRandInt (&rng) % (img->height); pt2.x = cvRandInt (&rng) % (img->width); pt2.y = cvRandInt (&rng) % (img->height); irandom = cvRandInt (&rng); rcolor = CV_RGB (irandom & 255, (irandom >> 8) & 255, (irandom >> 16) & 255); cvRectangle (img, pt1, pt2, rcolor, cvRandInt (&rng) % 5 - 1, CV_AA, 0); } // (4)ランダムな円を描画する for (i = 0; i < 5; i++) { pt1.x = cvRandInt (&rng) % (img->width); pt1.y = cvRandInt (&rng) % (img->height); irandom = cvRandInt (&rng); rcolor = CV_RGB (irandom & 255, (irandom >> 8) & 255, (irandom >> 16) & 255); cvCircle (img, pt1, cvRandInt (&rng) % (img->width / 4) + img->width / 4, rcolor, cvRandInt (&rng) % 5 - 1, CV_AA, 0); } // (5)ランダムな楕円を描画する for (i = 0; i < 5; i++) { pt1.x = cvRandInt (&rng) % (img->width); pt1.y = cvRandInt (&rng) % (img->height); irandom = cvRandInt (&rng); rcolor = CV_RGB (irandom & 255, (irandom >> 8) & 255, (irandom >> 16) & 255); cvEllipse (img, pt1, cvSize (img->width / 2, img->height / 2), irandom % 180, irandom % 90, irandom % 90 + 90, rcolor, cvRandInt (&rng) % 5 - 1, 0); } // (6)画像の表示,キーが押されたときに終了 cvNamedWindow ("Drawing", CV_WINDOW_AUTOSIZE); cvShowImage ("Drawing", img); cvWaitKey (0); cvDestroyWindow ("Drawing"); cvReleaseImage (&img); return 0; }
// (1)画像領域を確保し初期化する
このサンプルでは,外部画像を読み込まずに,プログラム内部で画像を用意する.
また,作成されたカラー画像を,黒(0)で塗りつぶして初期化する.
// (2)ランダムな線分を描画する
画像内に収まるように,ランダムなサイズと色を持つ線分を5本作成し,描画する.
// (3)ランダムな矩形を描画する
画像内に収まるように,ランダムなサイズと色を持つ矩形を5つ作成し,描画する.
// (4)ランダムな円を描画する
画像内に収まるように,ランダムなサイズと色を持つ円を5つ作成し,描画する.
// (5)ランダムな楕円を描画する
画像内に収まるように,ランダムなサイズと色を持つ楕円を5つ作成し,描画する.
// (6)画像の表示,キーが押されたときに終了
結果の画像を表示し,何かキーが押されるまで待つ.
実行結果例
ポリゴンの描画 cvFillpoly
1つのあるいは複数のポリゴンによって区切られた領域を塗りつぶす
サンプルコード
#include <cv.h> #include <highgui.h> int main (int argc, char **argv) { IplImage *img1, *img2, *img3; int npts[3] = { 3, 3, 4 }; CvPoint **pts; // (1)画像を確保し初期化する img1 = cvCreateImage (cvSize (500, 500), IPL_DEPTH_8U, 3); img2 = cvCloneImage (img1); img3 = cvCloneImage (img1); cvZero (img1); // (2)ポリゴンの頂点を配列に代入 pts = (CvPoint **) cvAlloc (sizeof (CvPoint *) * 3); pts[0] = (CvPoint *) cvAlloc (sizeof (CvPoint) * 3); pts[1] = (CvPoint *) cvAlloc (sizeof (CvPoint) * 3); pts[2] = (CvPoint *) cvAlloc (sizeof (CvPoint) * 4); pts[0][0].x = 0 + 50; pts[0][0].y = int (200 * 1.73) + 50; pts[0][1].x = 200 + 50; pts[0][1].y = 0 + 50; pts[0][2].x = 400 + 50; pts[0][2].y = int (200 * 1.73) + 50; pts[1][0].x = 0 + 50; pts[1][0].y = 0 + 50; pts[1][1].x = 200 + 50; pts[1][1].y = int (200 * 1.73) + 50; pts[1][2].x = 400 + 50; pts[1][2].y = 0 + 50; pts[2][0].x = 200; pts[2][0].y = int (200 * 1.73 / 2.0) + 50; pts[2][1].x = 200 + 50; pts[2][1].y = int (200 * 1.73 * 1 / 4.0) + 50; pts[2][2].x = 200 + 100; pts[2][2].y = int (200 * 1.73 / 2.0) + 50; pts[2][3].x = 200 + 50; pts[2][3].y = int (200 * 1.73 * 3 / 4.0) + 50; // (3)ポリゴンを描画する cvFillPoly (img1, pts, npts, 1, CV_RGB (255, 0, 0)); cvFillPoly (img2, pts, npts, 2, CV_RGB (255, 0, 0)); cvFillPoly (img3, pts, npts, 3, CV_RGB (255, 0, 0)); // (4)画像の表示,キーが押されたときに終了 cvNamedWindow ("Fillpoly1", CV_WINDOW_AUTOSIZE); cvShowImage ("Fillpoly1", img1); cvNamedWindow ("Fillpoly2", CV_WINDOW_AUTOSIZE); cvShowImage ("Fillpoly2", img2); cvNamedWindow ("Fillpoly3", CV_WINDOW_AUTOSIZE); cvShowImage ("Fillpoly3", img3); cvWaitKey (0); cvDestroyWindow ("Fillpoly1"); cvDestroyWindow ("Fillpoly2"); cvDestroyWindow ("Fillpoly3"); cvReleaseImage (&img1); cvReleaseImage (&img2); cvReleaseImage (&img3); cvFree (&pts[0]); cvFree (&pts[1]); cvFree (&pts[2]); cvFree (pts); return 0; }
// (1)画像を確保し初期化する
このサンプルでは,外部画像を読み込まずに,プログラム内部で画像を用意する.
また,作成されたカラー画像を,黒(0)で塗りつぶして初期化する.
// (2)ポリゴンの頂点を配列に代入
描画するためのポリゴンを定義する.
3頂点のポリゴン(三角形)を二つ,4頂点のポリゴン(四角形)を一つ,分の頂点を,
CvPointの二次元配列ptsに代入する.
// (3)ポリゴンを描画する
関数cvFillPoly()の4番目の引数は,与えられた配列のうち,実際に描画されるポリゴンの個数を表しており,
今回は,三つのポリゴン(を表す頂点座標)が与えれているので,この引数が取りうる範囲は1〜3になる.
これは,内部的に配列のインデックスとして利用されるので,0や,用意されたポリゴン数を越えるような値を指定することはできない.
// (4)画像の表示,キーが押されたときに終了
結果の画像を表示し,何かキーが押されるまで待つ.
1番目の画像は,単に三角形のポリゴンを表示するだけであるが,2番目の画像では,
二つの三角形ポリゴン(1番目の画像のポリゴンとそれを上下反転したポリゴン)の重ね合わせが表示されている.重なった場所は,ポリゴンの塗りつぶしが行われない.
3番目の画像では,さらに四角形(菱形)のポリゴンが追加されており,三つのポリゴンが重なった場所では,
通常どおりに塗りつぶしが行われている事が分かる.
実行結果例
凸ポリゴンの描画 cvFillConvexpoly
1つの凸ポリゴンを塗りつぶす
サンプルコード
#include <cv.h> #include <highgui.h> int main (int argc, char **argv) { int i; IplImage *img1, *img2; CvPoint *pts; // (1)画像領域を確保し初期化する img1 = cvCreateImage (cvSize (400, 400), IPL_DEPTH_8U, 3); cvZero (img1); img2 = cvCloneImage (img1); // (2)ポリゴンの頂点を配列に代入 pts = (CvPoint *) cvAlloc (sizeof (CvPoint) * 4); pts[0].x = 100; pts[0].y = 100; pts[1].x = 200; pts[1].y = 150; pts[2].x = 140; pts[2].y = 300; pts[3].x = 30; pts[3].y = 200; // (3)凸ポリゴンを描画する cvFillConvexPoly (img1, pts, 4, CV_RGB (255, 0, 0), CV_AA, 0); cvFillConvexPoly (img1, pts, 4, CV_RGB (0, 255, 0), CV_AA, 1); // (4)ポリゴンの座標を1ビット右シフトさせて,描画する for (i = 0; i < 4; i++) { pts[i].x >>= 1; pts[i].y >>= 1; } cvFillConvexPoly (img2, pts, 4, CV_RGB (0, 0, 255), CV_AA, 0); // (5)画像の表示,キーが押されたときに終了 cvNamedWindow ("Fillconvexpoly1", CV_WINDOW_AUTOSIZE); cvShowImage ("Fillconvexpoly1", img1); cvNamedWindow ("Fillconvexpoly2", CV_WINDOW_AUTOSIZE); cvShowImage ("Fillconvexpoly2", img2); cvWaitKey (0); cvDestroyWindow ("Fillconvexpoly1"); cvDestroyWindow ("Fillconvexpoly2"); cvReleaseImage (&img1); cvReleaseImage (&img2); cvFree (&pts); return 0; }
// (1)画像領域を確保し初期化する
このサンプルでは,外部画像を読み込まずに,プログラム内部で画像を用意する.
また,作成されたカラー画像を,黒(0)で塗りつぶして初期化する.
// (2)ポリゴンの頂点を配列に代入
4頂点の凸ポリゴン(四角形)を一つ描画するために,そのポリゴンの頂点座標を定義する.
// (3)凸ポリゴンを描画する
上で定義した凸ポリゴンを描画する.
関数cvFillConvexPoly()の最後の引数は,頂点座標のShift量を表しており,
例えば,ここに"1"を指定すると,座標値の下位1ビットは小数点以下を表すビットであると見なされる.
つまり,各頂点座標が1ビット右シフトされた(座標値が1/2になった)ポリゴンとほぼ同じものが表示される.
ここでは,赤色で指定座標そのままのポリゴンを,緑色で最後に引数に"1"を指定した場合のポリゴンを描画する.
また,その輪郭が水平なスキャンラインと2回以下しか交差しないような単純なポリゴンを仮定しているため,
この関数cvFillConvexPoly()は,関数cvFillPoly()よりも高速に動作する.
// (4)ポリゴンの座標を1ビット右シフトさせて,描画する
比較のために,各座標値を右に1ビットシフトさせたポリゴンを,別画像に青色で描画する.
// (5)画像の表示,キーが押されたときに終了
結果の画像それぞれを表示し,何かキーが押されるまで待つ.