前回は難しい事をして失敗したので、今回は単純にテンプレート画像を縮小してマッチングしてみる。
以下、テンプレート画像のリサイズをしてマッチングしている。
public class TemplateMatching { private static final float SIKITI = 0.95f; public static void main(String[] args) { List<Mat> images = Arrays.asList( imread("{武将カードリスト画像}"), imread("{武将カードリスト画像}"), imread("{武将カードリスト画像}")); Mat template = imread("{テンプレート画像}", CV_LOAD_IMAGE_GRAYSCALE); // サイズ調整 resize(template, template, new Size(40, 64), 0, 0, INTER_AREA); for (Mat image : images) { Mat grey = new Mat(image.size(), CV_8UC1); cvtColor(image, grey, COLOR_BGR2GRAY); Size size = new Size(grey.cols() - template.cols() + 1, grey.rows() - template.rows() + 1); Mat result = new Mat(size, CV_32FC1); matchTemplate(grey, template, result, TM_CCORR_NORMED); getPointsFromMatAboveThreshold(result, SIKITI).stream().forEach((point) -> { rectangle(image, new Rect(point.x(), point.y(), template.cols(), template.rows()), Scalar.RED, 2, 0, 0); }); imshow("Result", image); waitKey(0); } destroyAllWindows(); } public static List<Point> getPointsFromMatAboveThreshold(Mat m, float t) { List<Point> matches = new ArrayList<>(); FloatIndexer indexer = m.createIndexer(); for (int y = 0; y < m.rows(); y++) { for (int x = 0; x < m.cols(); x++) { if (indexer.get(y, x) > t) { System.out.println("(" + x + "," + y + ") = " + indexer.get(y, x)); matches.add(new Point(x, y)); } } } return matches; } }
リサイズは 横40 縦64 としている。
この数値は 三国志大戦.NET から参照している。
以下、実行結果。
いい感じに判定されている!
画像を縮小させる事は大事ですね。
ただ比較対象の画像サイズによっては 横40 縦64 でもうまく判定されないものがあります。
機器によって画面サイズが違うのでズレが生じるのかな。
より精度を上げるには比較する画像から武将カードのサイズを取得して、それに合わせてテンプレート画像をリサイズする必要がありますね。
うーん、どんどん深い所へと行っていますね。
肝となる部分なので後回しにしても痛い目を見そうだ。
どうしようかな。