画像からテンプレート画像を探す(テンプレートマッチング)

テンプレート画像を与え 入力画像から そのテンプレートにマッチングした領域を探すことを テンプレートマッチングといいます。
OpenCvSharpでは  CvクラスMatchTemplateメソッドで テンプレートマッチングを行います。
static void MatchTemplate(CvArr image,CvArr templ,CvArr result,MatchTemplateMethod method)
CvArr image : テンプレートの検索対象となる 画像
CvArr templ : テンプレート画像。検索対象となる画像より小さいサイズで 同じデータ型でなければなりません。
CvArr result : 比較結果のマップ。 シングルチャネル 32ビット浮動小数点。
imageの大きさが(W,H) templの大きさが(w,h)とすると result の大きさは(W-w+1,H-h+1)でなければいけません。
注意)Android版では、領域を確保さえすれば 自動的にタイプ・大きさが決定されますが OpenCvSharpでは明示的にタイプ・大きさを指定する必要がありました。
MatchTemplateMethod method : 比較手法を示す定数。詳しくは OpenCv2.2 C++リファレンスを参照してください。

MatchTemplateメソッドで求めた結果 result を元に MinMaxLocメソッドで最もHitした位置を 求めることができます。
static void MinMaxLoc(CvArr arr,out CvPoint min_loc,out CvPoint max_loc) 
CvArr arr : 入力マトリックス
CvPoint min_loc : 最小値の位置(col,row)
CvPoint max_loc : 最大値の位置(col,row)

 テストデータ 

検索対象とする画像
実際の画像は 640*480 ですが 1/2に縮小して表示しています。

テンプレート画像
上の画像 一番上の行右から2番目の黒石を切り取った画像 ただし この画像は原寸大を表示しています。

 コーディング 

検索ボタンクリック時の処理
テンプレート画像を検出した位置を 赤色の矩形で示す処理を 実装しました。

private void btnDetect_Click(object sender, EventArgs e)
{
    CvMat result = new CvMat(src.Height - tmp.Height + 1, src.Width - tmp.Width + 1, MatrixType.F32C1);
    Cv.MatchTemplate(src, tmp, result, MatchTemplateMethod.CCoeffNormed);
    CvPoint minPoint = new CvPoint();
    CvPoint maxPoint = new CvPoint();
    Cv.MinMaxLoc(result, out minPoint, out maxPoint);
    img = src.Clone();
    CvRect rect = new CvRect(maxPoint,tmp.Size);
    img.DrawRect(rect, new CvScalar(0, 0, 255), 2);
    pictureBox1.Invalidate();
}
 処理結果 

人間の目では区別できませんが 見事に一番上の行右から2番目の黒石を検出しています。

 Windows7 Vs2008 OpenCv2.4 And OpenCvSharp
スポンサーリンク
Rectangle大広告
Rectangle大広告

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

コメント

  1. tagao より:

    メモリ異常
    C#2010 で OpenCVSharp2.4 を使用していて、下記のようにすると、Webカメラからのキャプチャーはできます。
    しかし、継続的に処理しているとメモリフルで異常終了しました。

    //顔の分類器読み込み
    CvHaarClassifierCascade cascade_face = CvHaarClassifierCascade.FromFile(“haarcascade_frontalface_alt2.xml”);
    この行からをコメントにすると、メモリフルになりません。
    メモリフルを解消する方法を教えてもらえるでしょうか?

    private void timer_Tick(object sender, EventArgs e)
    {
    const double Scale = 1.00;
    const double ScaleFactor = 1.139;
    const int MinNeighbors = 1;
    CvSize MinSize = new CvSize(30, 30);

    IplImage img = cap.QueryFrame();
    if (img != null)
    {
    IplImage smallImg = new IplImage(new CvSize(Cv.Round(img.Width / Scale), Cv.Round(img.Height / Scale)), BitDepth.U8, 1);
    //顔検出用の画像の生成
    IplImage gray = new IplImage(img.Size, BitDepth.U8, 1);

    Cv.CvtColor(img, gray, ColorConversion.BgrToGray);
    Cv.Resize(gray, smallImg, Interpolation.Linear);
    Cv.EqualizeHist(smallImg, smallImg);
    Cv.ReleaseImage(gray);
    gray = null;

    //顔の分類器読み込み
    CvHaarClassifierCascade cascade_face = CvHaarClassifierCascade.FromFile(“haarcascade_frontalface_alt2.xml”);
    CvMemStorage storage = new CvMemStorage();
    storage.Clear();

    //顔の描画
    for (int d = 0; d < faces.Total; d++)
    {
    CvRect r = faces[d].Value.Rect;
    CvPoint pt1 = new CvPoint(r.X, r.Y);
    CvPoint pt2 = new CvPoint((r.X + r.Width), (r.Y + r.Height));
    img.Rectangle(pt1, pt2, CvColor.Red, 2, LineType.Link8, 0);
    }

    //リソース解放
    Cv.ReleaseMemStorage(storage);
    Cv.ReleaseHaarClassifierCascade(cascade_face);
    cascade_face = null;

    Bitmap bm = BitmapConverter.ToBitmap(img);
    bm.SetResolution(picWatch.Width, picWatch.Height);
    picWatch.Image = bm;

    //メモリリークが発生するので定期的にガベージコレクション
    if (GC.GetTotalMemory(false) > 600000) GC.Collect();

    Cv.ReleaseImage(smallImg);
    Cv.ReleaseImage(img);
    smallImg = null;
    img = null;
    bm = null;
    }
    }

  2. のぼった より:

    メモリ異常
    ご質問の件 せっかくご質問いただいたのですが 自分もよちよち歩きの状態で お答えできるまでのスキルを持ち合わせておりません。
    いずれメモリの解放がうまくいっていないせいだとは思いますが・・
    disposeでのメモリ解放も試されましたか??

  3. tagao より:

    メモリ異常
    早速の回答ありがとうございます。
    実は解決いたしました。

    分類器の読み込みの箇所に問題があり、タイマー処理の中で読み込んでいたため、XMLの情報がメモリにたまり続けていました。
    よって、分類器の読み込みをタイマー開始前に宣言することで、メモリ異常が解消されました。

    大変お騒がせしました。
    では、失礼します。