はじめに
こんにちは。
今週はAIエージェント開発の話題から一呼吸おいて、画像処理の内容です!
今回は業務の一環として取り組んでいる、ロゴ画像照合システムについて僕が現状考えている技術内容を皆さんに共有します。
開発に使用するテンプレートマッチングを使用しますので、みなさんもぜひ遊んでみてください〜
なお、先週の記事も添付していますので、ぜひ一読いただければ幸いです!
今回やること
今回は、ロゴ画像照合システムの核となるテンプレートマッチング手法について紹介します。
特に、入力画像がどのような状態であっても安定した検出を実現するため、入力する2枚の画像に対してエッジ処理(Canny処理)を適用した上でテンプレートマッチングを行います。
これにより、画像の色味や明暗の変化に依存しない画像照合処理を実装してみます。

画像処理
テンプレートマッチング
テンプレートマッチングとは、入力画像の中からあらかじめ用意したテンプレート画像と一致する領域を探索し、入力画像上の各位置における類似度を算出して、最も高い類似度を示す位置を検出する手法です。

テンプレートマッチングでは、基本的な評価指標としてSAD(Sum of Absolute Differences)、SSD(Sum of Squared Differences)、NCC(Normalized Cross-Correlation)、ZNCC(Zero-means Normalized Cross-Correlation)の4つが用いられることが一般的です。
今回はエッジ処理により二値的な特徴を持つ画像を扱うため、ZNCC(Zero-means Normalized Cross-Correlation)を採用します。

ZNCCを数式で表現すると複雑に見えますが、OpenCVはとても充実しているのでこれを利用することで、誰でも簡単に実装することができます!
エッジ処理(Canny処理)
エッジ処理とは、入力画像中の物体のエッジを検出し、エッジ部分の画素を255(白)、それ以外を0(黒)とすることで、色情報や明暗情報を削減した2値画像を得る手法です。
下記のコード例では、Canny処理において低閾値を50、高閾値を150に設定しています。
この2つの閾値により、150以上の勾配強度を持つ部分は確実にエッジとして検出され、50未満の部分はノイズとして除去されます。
target_path = sys.argv[1]
template_path = sys.argv[2]
target_gray = cv2.imread(target_path, cv2.IMREAD_GRAYSCALE)
template_gray = cv2.imread(template_path, cv2.IMREAD_GRAYSCALE)
target_color = cv2.imread(target_path, cv2.IMREAD_COLOR) #カラー画像用
edges_target = cv2.Canny(target_gray, 50, 150)
edges_template = cv2.Canny(template_gray, 50, 150)
この処理をすることで入力とする画像が次のように変換されます。


処理結果の画像をテンプレートマッチングの対象とすれば、より正確な検出ができると思います。
実装
ここまでの処理で、入力画像とテンプレート画像に対してエッジ処理を施した画像を入力として、テンプレートマッチングを実装します。
冒頭で述べた通り、今回はエッジ処理を対象としたテンプレートマッチングのため、類似度指標としてZNCC(Zero-mean Normalized Cross-Correlation)を用います。
数式で表現すると複雑でしたが、OpenCVの関数cv2.matchTemplate
の第三引数にcv2.TM_CCOEFF_NORMED
を指定するだけで、この指標によるテンプレートマッチングを簡単に実行できます。
result_edges = cv2.matchTemplate(edges_target, edges_template, cv2.TM_CCOEFF_NORMED) #テンプレートマッチング_, max_val_edge, _, max_loc_edge = cv2.minMaxLoc(result_edges)
h, w = template_gray.shape
bottom_right = (max_loc_edge[0] + w, max_loc_edge[1] + h)
result_img = target_color.copy() #カラー画像に変換
cv2.rectangle(result_img, max_loc_edge, bottom_right, (0, 0, 255), 2)
cv2.imwrite("dst_matchImg.png", result_img)
テンプレートマッチングの結果
弊社のロゴを対象としてテンプレートマッチングをしてみた結果、次の図のように結果を得ることができました。



このようにエッジ処理をした画像に対してテンプレートマッチングをしてみると、やや角度のある入力画像でも適切にロゴの検出をすることができるようになりました。
偽物画像に対する検出結果
テンプレートマッチングでは元画像とテンプレート画像がどのくらい一致しているかを走査する手法と説明しましたが、例えば元画像が偽物のロゴであった場合にはどうなるでしょうか?
今回の入力画像の例で使用した弊社ロゴを偽物風に加工し、試してみます。


結果としては、このようにロゴの部分に検出はされませんでしたが、画像上部に検出がされる結果となってしまいました。
ロゴが検出されなかったのは良い結果ですが、画像のどこであっても検出がされてしまえば、照合システムとしての機能が損なわれてしまうので考えないとですね…
おわりに
いかがでしたでしょうか。
今回は、ロゴの検出をすることを目的に、画像処理の基本的な手法であるテンプレートマッチングをやってみました。
また、入力とする2枚の画像に対してエッジ処理をした上でのテンプレートマッチングは色味や明暗を削減しているためか、うまい具合に検出ができていることを確認できました。
今回作成したソースコードは以下のGit Hubから使用することができます。
ご自身で入力画像とテンプレートを用意してぜひ遊んでみてください!
今後の課題
偽物画像に対してのテンプレートマッチングの結果、ロゴは検出されませんでしたが、画像中のどこかが検出されるという例がありました。
本来は検出されないのが好ましい処理結果なので、今後は過検出がされないような処理を考えていきます。
参考URL

