中編

竹田 大祐 / 高鹿 陽介
さて，前回に続き OpenCV について解説します．前回は，カメラとの接続と，カメラからの画像に図形を描画するところまで説明しました．今回はそれらを利用しつつ，さらに発展させて，テンプレート・マッチングによる図形認識について述べていきます．
（筆者）

1 テンプレート・マッチングの概要

2

テンプレート・マッチングのためのプログ
ラム―― cvMatchTemplate 関数を使用

OpenCV には，画像処理アルゴリズムを実装するための関数も用意されています．今回は，そのなかで，テンプレート・● テンプレート・マッチング・プログラムの概要
リスト 1（sample3.c）に示すテンプレート・マッチングのマッチングによる画像認識を行ってみます．
テンプレート・マッチングは，認識しようとする対象の画像プログラムは，カメラから取り込んだ画像中の目標物を検出をテンプレートとしてもち，対象画像の各部分との類似度を計し，四角い枠で囲うというものです．枠で囲う処理には，前編算することによって対象物の画像中の位置を求める処理です．

（2006 年 11 月号，pp.186 -192）の図形描写の例で用いた関数を類似度の計算には，相互相関などを用いることが一般的です．

使います．

テンプレート・マッチングは，画像認識としては基本的な処

テンプレート・マッチングに使用した関数は，cvMatch

理です．OpenCV にはテンプレート・マッチングを行う関数がTemplate 関数です．この関数は，テンプレート画像と入力画用意されているので，カメラの画像中から目標物を検出すると像の類似度を計算し，結果を指定した配列に出力する関数です．

いうような処理が簡単に実現できます．

テンプレート・マッチングとひと口にいっても，類似度の計算にはいくつかの方法があります．代表的な手法として 2 乗残差法と相互相関法が挙げられますが，今回は相互相関法を用いました．こちらの手法のほうが計算時間はかかりますが，より変数の宣言および構造体を確保

図 2 テンプレー
ト画像

テンプレートの読み込み四角形が表示された

カメラ画像をグレー・スケールに変換
cvCvtColor

テンプレートとカメラからの画像の相関値計算
cvMatchTemplate

相関値最大の座標を検出
cvMinMaxLoc

相関値0.75以上かNoYes
相関値最大の座標をテンプレート画像の大きさだけ枠で囲う

図 1 テンプレート・マッチング・プログラムのフローチャート

図 3 テンプレート・マッチング・プログラムの出力結果

142 KEYWORD ―― 動画像処理，OpenCV，テンプレート・マッチング，相互関数，画像認識，Makefile，
USB カメラ，色空間，グレー・スケール，正規化

Dec. 2006

確実な検出が行えるとされています．cvMatchTemplate 関数● プログラムの実行もこの二つの手法を提供しています．

テンプレート画像には，図 2 のような簡単な図形を用いまし● プログラムの流れた．もちろん，これ以外の図形でもかまいません．
リスト 2 の Makefile を実行してみましょう．図 3 のようにテプログラムのフローチャートを図 1 に示します．簡単に説明

ンプレート画像が認識され，赤い枠が表示されれば成功です．

すると，（1）テンプレート画像の読み込みを行う（2）カメラからの画像との相関値を計算する（3）相関値のいちばん高い座標を検索し，その場所に四角い枠

3

テンプレート・マッチングのための関数を描画するというものです．ただし，認識対象が画像中にない場合，相関ここで使用している関数について解説します．なお，これら値は低い値になります．この状態で値のいちばん高い部分を枠の関数もすべて docs フォルダ以下のリファレンス中に説明がで囲っても意味がないので，しきい値を設定します．なお，今あります．

回は 0.75 に設定しました．

リスト 1 テンプレート・マッチング・プログラム（sample3.c）/* OpenCV 動画のテンプレート・マッチング *///カメラ・デバイスから画像を取得
img=cvQueryFrame(camera);#include <stdio.h>//画像が取得できなかったときのエラー処理
if(img==NULL){
printf("Cannot Open Video Data!¥n");break;}//OpenCV 用のヘッダ・ファイル#include <cv.h>#include <highgui.h>
int main(void){
int key_input;
CvCapture* camera//キー入力//カメラ・デバイス= NULL;

IplImage *img = NULL;
IplImage *grey = NULL;
IplImage *temp = NULL;
IplImage *dst = NULL;//グレー・スケールに変換して格納
cvCvtColor(img,grey, CV_BGR2GRAY);//画像データ格納用構造体//処理用画像データ//(取り込み画像のグレー・スケール)//テンプレート用画像格納構造体//相関情報格納用構造体

double max_interlinkage=0;
double min_interlinkage=0;//相関値の最大値を代入する変数//相関値の最小値を代入する変数

CvPoint max_point;//相関値の最大値の座標を代入する変数
CvPoint min_point;//相関値の最小値の座標を代入する変数
CvPoint corner_point; //ターゲットのもう一方の四隅座標//テンプレート・マッチングのための相関値の計算cvMatchTemplate(grey,temp,dst,CV_TM_CCOEFF_NORMED);//テンプレート・マッチングでいちばんマッチしている部分を検索
cvMinMaxLoc(dst,&min_interlinkage,&max_interlinkage,&min_point,&max_point,NULL);//相関値 0.75 以下ならば Lost を表示して次に行く
if(max_interlinkage>0.75){//座標を見やすく代入(直接代入でもよい)
corner_point=cvPoint(max_point.x+temp>width,max_point.y+temp->height);//カメラ・デバイスの先頭ポインタを取得
camera=cvCaptureFromCAM(-1);//マッチング箇所を四角で描画
cvRectangle(img,max_point,corner_point,CV_RGB(255,0,0),2);
printf("Detection¥n");//カメラ・デバイスが見つからないときの処理
if(camera==NULL){
printf("Cannot Open Camera Device!¥n");return(0);
}

}
else{
printf("Lost¥n");}//テンプレート画像の読み込み(グレー・スケール)
temp=cvLoadImage("cup.bmp",0);//画像表示cvShowImage("Show",img);//Window の生成
cvNamedWindow("Show", CV_WINDOW_AUTOSIZE);//キー入力key_input = cvWaitKey(10);//カメラ・デバイスから画像を取得
img=cvQueryFrame(camera);//ESC で終了
if(key_input==0x1b){
printf("ESC KEY Quit¥n");break;}//テンプレート・マッチングに用いる相関値データを格納する画像の領域確保//グレー・スケール画像用に領域確保
grey=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
dst =cvCreateImage(cvSize(img->width-temp->width+1, img>height-temp->height+1),IPL_DEPTH_32F,1);//動画キャプチャと表示のループの開始
for(;;){}//メモリ開放cvReleaseCapture(&camera);
cvDestroyWindow("Show");
return(0);Dec. 2006

143