テンプレート画像を与え 入力画像から そのテンプレートにマッチングした領域を探すことを テンプレートマッチングといいます。
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 |
コメント
メモリ異常
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;
}
}
メモリ異常
ご質問の件 せっかくご質問いただいたのですが 自分もよちよち歩きの状態で お答えできるまでのスキルを持ち合わせておりません。
いずれメモリの解放がうまくいっていないせいだとは思いますが・・
disposeでのメモリ解放も試されましたか??
メモリ異常
早速の回答ありがとうございます。
実は解決いたしました。
分類器の読み込みの箇所に問題があり、タイマー処理の中で読み込んでいたため、XMLの情報がメモリにたまり続けていました。
よって、分類器の読み込みをタイマー開始前に宣言することで、メモリ異常が解消されました。
大変お騒がせしました。
では、失礼します。