OpenCV(Python)でTemplate Matchingを使用して物体検出をしてみた

2022.03.05

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 IoT事業部の若槻です。

前回のエントリではOpenCV(Python)のHigh-level GUIを使用して画像をウィンドウで開いてみました。

今回は、OpenCVPython)でTemplate Matchingを使用して画像内の検索(物体検出)をしてみました。

環境

$  sw_vers  
ProductName:	macOS
ProductVersion:	11.6
BuildVersion:	20G165

$  python
Python 3.9.6 (default, Jun 29 2021, 06:20:32) 
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> cv2.__version__
'4.5.5'

やってみた

検索対象の画像(めそ子)を用意し、そこから切り取ったクラスメソッドのロゴ画像(旧Ver)を検索元(テンプレート)としてみます。

  • 検索対象(mesoko.jpg

  • テンプレート(cm_logo.jpg

OpenCVで画像内を検索したい場合は、matchTemplate()でTemplate Matchingを行って検索結果を取得し、minMaxLoc()を使用して検索結果から最小および最大の信頼度と位置座標を取得します。

import cv2

# 検索対象画像とテンプレート画像の読み込み
img = cv2.imread('mesoko.jpg')
template = cv2.imread('cm_logo.jpg')

# テンプレート画像の幅と高さを取得
w, h, _ = template.shape

# 画像の検索(Template Matching)
result = cv2.matchTemplate(img, template, cv2.TM_CCORR_NORMED)
# 検索結果の信頼度と位置座標の取得
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

ここで、minMaxLoc()の結果は次のようになります。max_val0.9998985528945923と非常に高い信頼度となっています。

cv2.minMaxLoc(result)
(0.7578669190406799, 0.9998985528945923, (306, 692), (23, 606))

画像内で検索結果の位置を示したい場合はrectangle()が便利です。

# 検索結果の左上頂点の座標を取得
top_left = max_loc

# 検索結果の右下頂点の座標を取得
bottom_right = (top_left[0] + w, top_left[1] + h)

# 検索対象画像内に、検索結果を長方形で描画
cv2.rectangle(img, top_left, bottom_right, (255, 255, 0), 2)

# 画像を表示
cv2.imshow('img', img)
cv2.waitKey(1)

画像内のロゴ部分がちゃんと長方形で指定されていますね!

別の画像内を検索した場合

同様のテンプレート画像が含まれる別の画像内を検索してみます。

検索対象の画像はこちら。真ん中上部のロゴ部分がヒットして欲しい。

まず、先程と同じテンプレート画像を使用して、画像内を検索し、最小および最大の信頼度と位置座標を取得します。最大の信頼度は0.9530391693115234と先程よりは若干小さい値となっていますね。

img2 = cv2.imread('mesoko2.jpg')
result2 = cv2.matchTemplate(img2, template, cv2.TM_CCORR_NORMED)
min_val2, max_val2, min_loc2, max_loc2 = cv2.minMaxLoc(result2)
cv2.minMaxLoc(result2)
# (0.8216370940208435, 0.9530391693115234, (353, 708), (356, 989))

最大の信頼度の位置座標を表示してみると、期待とは全く異なる位置となってしまっています。

top_left2 = max_loc2
bottom_right2 = (top_left2[0] + w, top_left2[1] + h)
cv2.rectangle(img2, top_left2, bottom_right2, (255, 255, 0), 2)

cv2.imshow('img2', img2)
cv2.waitKey(1)

信頼度が約0.99だと完璧に検索できていましたが、約0.95だと全く見当外れな検索結果となりました。検索結果に一致したと判定する信頼度の値は試行回数を重ねてチューニングが必要そうです。

参考

以上