Processing+OpenCVでテンプレートマッチングを行う

ここのところ週末も仕事で時間がとれず、すっかりブログ更新の間があいてしまいました。一段落したらなんとか週一ペースに戻したいと思います。

今回は、前回セットアップしたOpenCV for Processingを使ってテンプレートマッチングを行ってみたいと思います。

テンプレートマッチングとは

テンプレートマッチングは手本となる画像(テンプレート)が対象画像の中にあるかを判定する画像処理の手法です。OpenCVではmatchTemplateという関数でテンプレートマッチングの機能が提供されています。

処理手順

OpenCVを使ったテンプレートマッチングは以下の手順で行います。

  1. テンプレート画像と入力画像を行列に変換する
  2. 結果の出力先となる行列を用意する
  3. matchTemplate関数でテンプレートマッチングを行う
  4. 一番類似度の高かった結果を表示する

4の結果表示では、処理の仕方を変更することで、一定の類似度以上の結果すべてを表示するといったことも可能です。

実際のコード

実際にProcessing+OpenCVでテンプレートマッチングを行うコードは以下になります。

import gab.opencv.*;
import org.opencv.core.Mat;
import org.opencv.core.CvType;
import org.opencv.imgproc.Imgproc;
import org.opencv.core.Core.MinMaxLocResult;
import org.opencv.core.Core;

// 入力画像の準備
PImage inputImage = loadImage("http://placekitten.com/300/300", "jpg");
OpenCV inputCV = new OpenCV(this, inputImage);
Mat inputMat = OpenCV.imitate(inputCV.getGray());

// テンプレート画像の準備
PImage templateImage = inputImage.get(120, 40, 80, 80); // 入力画像の一部を切り出し
templateImage.filter(BLUR, 4); // 切り出した画像をぼかす
OpenCV templateCV = new OpenCV(this, templateImage);
Mat templateMat = OpenCV.imitate(templateCV.getGray());

// 結果格納用の行列の準備
int resultCols = inputMat.cols() - templateMat.cols() + 1;
int resultRows = inputMat.rows() - templateMat.rows() + 1;
Mat resultMat = new Mat(resultRows, resultCols, CvType.CV_32FC1);

// テンプレートマッチングを実行
Imgproc.matchTemplate(inputCV.getColor(), templateCV.getColor(), resultMat, Imgproc.TM_CCOEFF_NORMED);

// 結果を描画
size(400, 300);
image(inputImage, 100, 0);
image(templateImage, 10, 10);

MinMaxLocResult mmlr = Core.minMaxLoc(resultMat);

if (mmlr.maxVal > 0.9) {
  println("Val: " + mmlr.maxVal);
  stroke(255, 0, 0);
  strokeWeight(3);
  noFill();
  rect((int)mmlr.maxLoc.x + 100, (int)mmlr.maxLoc.y, templateMat.cols(), templateMat.rows());
}

今回は入力画像の一部を切り出して、(それだけではあまりに芸がないので)ぼかしをかけた画像をテンプレート画像として使用しています。

実行結果

作成したコードの実行結果がこちらになります。

f:id:tkitao:20140614150617p:plain

ぼやけたテンプレート画像に対して、最も類似度の高い領域が認識できています。