ランダムな点列を包含する矩形
C
#include <cv.h>
#include <highgui.h>
int
main (int argc, char **argv)
{
int i;
IplImage *img = 0;
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq *points;
CvRNG rng = cvRNG(cvGetTickCount());
CvPoint pt;
CvRect rect;
// (1)allocate and initialize an image
img = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 3);
cvZero(img);
// (2)generate and draw a sequence of random 2d points
points = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);
for( i = 0 ;i < 50; 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, 8, 0);
}
// (3)calculate and draw a bounding rectangle of points
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, 8, 0);
// (4)show the iamge, and quit when any key pressed
cvNamedWindow ("BoundingRect", CV_WINDOW_AUTOSIZE);
cvShowImage ("BoundingRect", img);
cvWaitKey (0);
cvDestroyWindow("BoundingRect");
cvReleaseImage(&img);
cvReleaseMemStorage(&storage);
return 0;
}
// (1)画像領域を確保し,初期化します.
cvCreateImage によって,指定のサイズ,ビット深度の画像を作成した後に,cvZero を用いて画像を黒で塗りつぶして初期化します.この関数は,次のようにマクロ定義されたものです.
#define cvZero cvSetZero
// (2)ランダムな2次元座標列を生成し,その座標を中心とする円を描画します.
cvCreateSeq によって確保されたシーケンスに,ランダムに生成された座標を代入します. cvRandInt によって生成された疑似乱数は,画像の中心部(全体の面積の1/4)にあるように調整され, cvSeqPush によりシーケンスに追加されます.また,それぞれの座標を中心として円を描画する(cvCircle)ことで,生成された点列を可視化します.
// (3)点列の包含矩形を求め,それを描画します.
cvBoundingRect を用いて,生成された点列を包含するような最小の矩形を求めます.ただし,この矩形は傾き(回転)が考慮されません.これが cvMinAreaRect2 との違いであり,前者は cvRect を返しますが,後者は CvBox2D を返します.求められた矩形を cvRectangle によって描画します.
// (4)画像を表示し,何かキーが押されると終了します.
結果画像を表示し,何かキーが押された場合にはプログラムを終了します.
C++
#include <cv.h>
#include <highgui.h>
using namespace cv;
int
main (int argc, char **argv)
{
// (1)allocate and initialize an image
Mat img = Mat::zeros(Size(640, 480), CV_8UC3);
if(!img.data) return -1;
// (2)generate a sequence of random 2d points
Mat points(Size(50, 1), CV_32SC2);
/// randu(points, Scalar(img.cols/4, img.rows/4), Scalar(img.cols*3./4., img.rows*3./4.));
RNG(getTickCount()).fill(points, RNG::UNIFORM, Scalar(img.cols/4, img.rows/4), Scalar(img.cols*3./4, img.rows*3./4));
// (3)draw the points as small circles
#if 1
MatIterator_<Vec2i> it = points.begin<Vec2i>(), it_end = points.end<Vec2i>();
for(; it!=it_end; ++it) {
circle(img, Point((*it)[0], (*it)[1]), 3, Scalar(0,255,0), -1);
}
#elif 1
vector<Mat> planes;
split(points, planes);
MatIterator_<int> it0 = planes[0].begin<int>(), it0_end = planes[0].end<int>();
MatIterator_<int> it1 = planes[1].begin<int>();
for(; it0 != it0_end; ++it0, ++it1) {
circle(img, Point(*it0, *it1), 3, Scalar(0,255,0), -1);
}
#else
/// only if points has no gap
int *p = points.ptr<int>();
int inc = points.elemSize()/sizeof(int);
for(int i=0; i<points.cols; i++, p+=inc) {
circle(img, Point(p[0], p[1]), 3, Scalar(0,255,0), -1);
}
#endif
// (4)calculate and draw a bounding rectangle of points
Rect brect = boundingRect(points);
rectangle(img, brect.tl(), brect.br(), Scalar(0,0,255), 2);
// (5)show the iamge, and quit when any key pressed
namedWindow("img", CV_WINDOW_AUTOSIZE);
imshow("img", img);
waitKey(0);
return 0;
}
// (1)画像領域を確保し,初期化します.
Matlab 形式の Mat::zeros を利用して,0で初期化された Mat クラスのインスタンスを作成します.
// (2)ランダムな2次元座標列を生成します.
指定範囲内(上述のCの例と同様)に一様分布する疑似乱数で,行列を埋めます.
ここでは,低レベルな関数 RNG を利用して行列を埋めていますが, randu を利用しても同様のことが可能です.ただし,randu
は,常に同じシードを利用するデフォルト乱数生成器を利用するため,常に同じ順列の乱数が生成されます.実行の度に異なる乱数を使用したい場合には,例えばここで用いているように getTickCount を利用して乱数を生成します.
// (3)それぞれの点を描画します.
イテレータを利用して行列内を横断し, circle を用いて各点を中心とする円を描画します.
また,マクロでコメントアウトされているように,
・チャンネル毎(x座標とy座標)のイテレータを利用する方法
vector<Mat> planes;
split(points, planes);
MatIterator_<int> it0 = planes[0].begin<int>(), it0_end = planes[0].end<int>();
MatIterator_<int> it1 = planes[1].begin<int>();
for(; it0 != it0_end; ++it0, ++it1) {
circle(img, Point(*it0, *it1), 3, Scalar(0,255,0), -1);
}
・ポインタを利用する方法(gapがない場合)
int *p = points.ptr<int>();
int inc = points.elemSize()/sizeof(int);
for(int i=0; i<points.cols; i++, p+=inc) {
circle(img, Point(p[0], p[1]), 3, Scalar(0,255,0), -1);
}
などでも同様のことが可能です.
// (4)点列の包含矩形を求め,それを描画します.
boundingRect を用いて,生成された点列を包含するような最小の矩形を求めます.ただし,この矩形は傾き(回転)が考慮されません.これが minAreaRect との違いであり,前者は Rect を返しますが,後者は RotatedRect を返します.求められた矩形を rectangle によって描画します.
// (5)画像を表示し,何かキーが押されると終了します.
結果画像を表示し,何かキーが押された場合にはプログラムを終了します.


