OpenCVを使ってテンプレートマッチングをする場合、比較結果があるしきい値以上の箇所を全てリストアップしたくなる時ありますよね?
サンプルコードだと、Core#minMaxLoc()を使って最も一致する箇所のみですが、これをしきい値以上の場合に変更してみました。
複数検出
//対象画像とテンプレート画像を読み込み Mat img = Highgui.imread(srcFile.getAbsolutePath(), Highgui.CV_LOAD_IMAGE_COLOR); Mat tmpl = Highgui.imread(tmplFile.getAbsolutePath(), Highgui.CV_LOAD_IMAGE_COLOR); //比較結果を格納するMatを生成 Mat result = new Mat(img.rows() - tmpl.rows() + 1, img.cols() - tmpl.cols() + 1, CvType.CV_32FC1); //テンプレートマッチ実行(TM_CCOEFF_NORMED:相関係数+正規化) Imgproc.matchTemplate(img, tmpl, result, Imgproc.TM_CCOEFF_NORMED); //結果から相関係数がしきい値以下を削除(0にする) Imgproc.threshold(result, result, 0.8, 1.0, Imgproc.THRESH_TOZERO); //しきい値=0.8 for (int i=0;i<result.rows();i++) { for (int j=0;j<result.cols();j++) { if (result.get(i, j)[0] > 0) { Core.rectangle(img, new Point(j, i), new Point(j + tmpl.cols(), i + tmpl.rows()), new Scalar(0, 0, 255)); } } } //結果画像を出力 Highgui.imwrite(outputFile.getAbsolutePath() + "/out.jpg", img);
Imgproc#threshold()を使うだけで簡単にできます。
実行例
入力
結果
赤枠で囲われた箇所が検出箇所です。
あとがき
Matのrowとcolと、画像の座標x,yをよく間違えてしまう。
しばらくハマった後、原因がこれだとわかるとどっと疲れるわ…。
画像の座標(x,y)の相関値は、result.get(y, x)[0]で取得する。