エッジを検出する

スクリーンショット_112312_080115_PM

形を認識する際はエッジの検出が不可欠です。

ここでは、エッジ検出用の関数

  • Cannyアルゴリズム
  • Sobelオペレータ
  • Laplacianオペレータ

を紹介します。

 

Cannyアルゴリズム

CannyアルゴリズムはCannyさんが開発したエッジ検出アルゴリズムです。

細かい話はまた別途紹介するとして、今回はとりあえず使ってみようというモチベーションではなしをすすめます。

Cannyを使えばエッジが検出できる程度で十分です。

以下のようにプログラムを組みましょう(VisualC++,コンソールアプリケーションで組みました)

int _tmain(int argc, _TCHAR* argv[])
{
	//画像データの読込
    IplImage* src = cvLoadImage("C:\\opencv\\samples\\c\\lena.jpg", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
    if (src == NULL){
        return 0;
    }
	IplImage* dst;
	dst=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
	//グレースケールへ変換
	cvCvtColor(src,dst,CV_BGR2GRAY);
	//Cannyアルゴリズム
	cvCanny(dst,dst,30,90,3);
    //表示ウィンドウの作成
    cvNamedWindow("画像");
    //画像の表示
    cvShowImage ("画像", dst);
    //キー入力待ち
    cvWaitKey (0);
    //ウィンドウの削除
    cvDestroyWindow("画像");
    //画像データの解放
    cvReleaseImage(&src);
	return 0;
}

解説

このプログラムのみそは

void cvCanny(
	const CvArr* image,	//処理対象の画像(8ビット1チャネル)
	CvArr*	dst,		//結果
	double	threshold1,	//閾値の下限
	double	threshold2,	//閾値の上限
	int	size		//フィルタサイズ(1,3,5,7のどれか)
);

という関数です。閾値の下限、閾値の上限、フィルタサイズを変えることで、エッジの検出度合いを調整します。

実行すると以下のようになります。

スクリーンショット_112312_080115_PM

たしかに境界が抽出できていますね。

Sobelオペレータ

Sobelオペレータは水平方向や垂直方向のエッジを別々に検出できます。

命令は以下の関数を使用します。

 

水平方向に処理する場合は,xを1以上にしてyを0にします。

垂直方向に処理する場合は,xを0にして、yを1以上にします。

void cvSobel(
	const CvArr*	src,	//処理対象画像
	CvArr*	dst,		//結果
	int x,		//x導関数の次数
	int y,		//y導関数の次数
	int size	//フィルタサイズ(1,3,5,7のどれか)
);

では、水平方向に処理してみましょう。Sobelオペレータは処理途中にオーバーフローが発生するのを防ぐために、16ビットの深度を指定する必要があることに注意して、プログラムをみてください。

int _tmain(int argc, _TCHAR* argv[])
{
	//画像データの読込
    IplImage* src = cvLoadImage("C:\\opencv\\samples\\c\\lena.jpg", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
    if (src == NULL){
        return 0;
    }
	IplImage* dst;
	IplImage* dst16;
	dst=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
	dst16=cvCreateImage(cvGetSize(src),IPL_DEPTH_16S,1);
	//グレースケールへ変換
	cvCvtColor(src,dst,CV_BGR2GRAY);
	//Sobelオペレータ
	cvSobel(dst,dst16,1,0,1);
	//8bitに変換する
	cvConvertScaleAbs(dst16,dst,1,0);
    //表示ウィンドウの作成
    cvNamedWindow("画像");
    //画像の表示
    cvShowImage ("画像", dst);
    //キー入力待ち
    cvWaitKey (0);
    //ウィンドウの削除
    cvDestroyWindow("画像");
    //画像データの解放
    cvReleaseImage(&src);
	cvReleaseImage(&dst);
	cvReleaseImage(&dst16);
	return 0;
}

実行すると次のようになります。

スクリーンショット_112312_081328_PM

Laplacianオペレータ

最後にLaplacianオペレータを使ってみます。ラプラシアンフィルタのマスクは

0 1 0
1 -4 1
0 1 0

となっています。

以下の関数を使います。

void cvLaplace(
	const CvArr*	src,	//処理対象画像
	CvArr*	dst,	//結果
	int size	//フィルタサイズ(1,3,5,7のいずれか)
}

cvSobelを次のように書き換えて実行してみてください。

cvLaplace(dst,dst16,3);

実行すると以下のようになります。

スクリーンショット_112312_081845_PM

著者:安井 真人(やすい まさと)