丸いマーカーを検出するには?という質問があったので、今回はcvHoughCirclesを用いた円検出を紹介します。
CV Droneにもサンプルとして収録されてあります。
https://github.com/puku0x/cvdrone/blob/master/src/samples/sample_hough_circle.cpp手順は
1. 画像をグレースケール変換
2. ノイズ除去のため画像をぼかす
3. 円を検出が簡単になるようにエッジを出す
4. cvHoughCircles()で円検出
です。
#include "ardrone/ardrone.h"
#define KEY_DOWN(key) (GetAsyncKeyState(key) & 0x8000)
#define KEY_PUSH(key) (GetAsyncKeyState(key) & 0x0001)
// --------------------------------------------------------------------------
// main(引数の数、引数リスト)
// メイン関数です
// 戻り値 正常終了:0 エラー:-1
// --------------------------------------------------------------------------
int main(int argc, char **argv)
{
// AR.Droneクラス
ARDrone ardrone;
// 初期化
if (!ardrone.open()) {
printf("Failed to initialize.");
return -1;
}
// 画像取得
IplImage* image = ardrone.getImage();
// 画像
IplImage *gray = cvCreateImage(cvGetSize(image), image->depth, 1);
IplImage *smooth = cvCreateImage(cvGetSize(image), image->depth, 1);
IplImage *canny = cvCreateImage(cvGetSize(image), image->depth, 1);
// Cannyエッジ用の閾値
int th1 = 50, th2 = 100;
cvNamedWindow("canny");
cvCreateTrackbar("th1", "canny", &th1, 255);
cvCreateTrackbar("th2", "canny", &th2, 255);
// メインループ
while (!GetAsyncKeyState(VK_ESCAPE)) {
// 更新
if (!ardrone.update()) break;
// 画像取得
image = ardrone.getImage();
// グレースケールに変換
cvCvtColor(image, gray, CV_BGR2GRAY);
// ノイズ除去
cvSmooth(gray, smooth, CV_GAUSSIAN, 23, 23);
// エッジ検出
cvCanny(smooth, canny, th1, th2, 3);
// 円検出
CvMemStorage *storage = cvCreateMemStorage(0);
CvSeq *circles = cvHoughCircles(smooth, storage, CV_HOUGH_GRADIENT, 1.0, 10.0, MAX(th1,th2), 20);
// 円表示
for (int i = 0; i < circles->total; i++) {
float *p = (float*) cvGetSeqElem(circles, i);
cvCircle(image, cvPoint(cvRound(p[0]), cvRound(p[1])), cvRound(p[2]), CV_RGB(0,255,0), 3, 8, 0);
}
// メモリ解放
cvReleaseMemStorage(&storage);
// カメラ切り替え
static int mode = 0;
if (KEY_PUSH('C')) ardrone.setCamera(++mode%4);
// 表示
cvShowImage("camera", image);
cvShowImage("canny", canny);
cvWaitKey(1);
}
// メモリ解放
cvReleaseImage(&gray);
cvReleaseImage(&smooth);
cvReleaseImage(&canny);
// さようなら
ardrone.close();
return 0;
}
45行目でグレースケールに変換していますが、マーカーの色が赤や青であれば、YCrCbに色変換して色差成分に対してハフ変換をかければ検出しやすくなると思います。
// YCrCb用
IplImage *ycrcb = cvCreateImage(cvGetSize(image), image->depth, 3);
IplImage *y = cvCreateImage(cvGetSize(image), image->depth, 1);
IplImage *cr = cvCreateImage(cvGetSize(image), image->depth, 1);
IplImage *cb = cvCreateImage(cvGetSize(image), image->depth, 1);
// YCrCbに変換
cvCvtColor(image, ycrcb, CV_BGR2YCrCb);
cvSplit(ycrcb, y, cr, cb); // 分離
cvSmooth(cr, smooth, CV_GAUSSIAN, 23, 23); // 赤のマーカー
// エッジ検出
cvCanny(smooth, canny, th1, th2, 3);
// 円検出
CvMemStorage *storage = cvCreateMemStorage(0);
CvSeq *circles = cvHoughCircles(smooth, storage, CV_HOUGH_GRADIENT, 1.0, 10.0, MAX(th1,th2), 20);
安定して検出できるかどうかは微妙なところですが...