2011/12/19

OpenCVで作るビジョンプログラム(4)

こんにちは、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 件のコメント: