こんにちは、Shinpukuです。
今回はフィールド領域の検出を行います。
これはフィールド外の物体を誤って検出しないようにするためです。
それではアルゴリズムを紹介していきます。
まず、閾値処理により緑色を抽出します。
次にノイズ除去のため膨張・収縮を行います。
一番大きい領域のみ残します。
cvConvexHull2関数を用いて欠けた領域の補間を行います。
これでフィールド領域を検出することが出来ました。
黄色や白色との論理積を取ることでボールや白線を検出することができます。
コードは以下の通りです。
void Vision::detectField(Data &data)
{
double max = 0;
CvSeq *contour = NULL, *maxContour = NULL;
CvMemStorage *contourStorage = cvCreateMemStorage();
// 膨張・縮小
cvMorphologyEx(images.cvGreen, images.cvField, NULL, NULL, CV_MOP_CLOSE);
// 中心円を描く
const int radius = MIN(IMAGE_HALF_WIDTH, IMAGE_HALF_HEIGHT) * 0.3;
cvCircle(images.cvField, images.center, radius, cvScalarAll(255), -1);
// 輪郭を抽出
cvFindContours(images.cvField, contourStorage, &contour, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
// 一番大きい領域を求める
while (contour) {
double size = fabs(cvContourArea(contour, CV_WHOLE_SEQ));
if (size > max) {
maxContour = contour;
max = size;
}
contour = contour->h_next;
}
// 初期化
cvZero(images.cvField);
// 見つかった
if (maxContour) {
// 凸包を求める
CvSeq *hull = cvConvexHull2(maxContour);
// 凸包を構成する点
CvPoint *pts = new CvPoint[hull->total];
for(int i = 0; i < hull->total; ++i) pts[i] = **(CvPoint**)cvGetSeqElem(hull, i);
// フィールド領域を描画
cvFillConvexPoly(images.cvField, pts, hull->total, cvScalarAll(255));
cvAnd(images.cvField, images.cvMask, images.cvField);
// メモリ解放
delete [] pts;
}
// メモリ解放
cvReleaseMemStorage(&contourStorage);
}
次回は白線を検出してみようと思います。
0 件のコメント:
コメントを投稿