つれづれなる備忘録

日々の発見をあるがままに綴る

OpenCVの使い方35 ~ テンプレートマッチング

今回はOpenCVを用いたテンプレートマッチングについて紹介する。

1. テンプレート画像とテスト画像

テンプレートマッチングは、テンプレート画像と一致する箇所を適用する画像の中から検出する処理である。

今回はテスト画像として標準画像データベースからText.bmpを選択した。

"Text.bmp"
Text.bmp

テンプレート画像はText.bmpから右端の8の文字を切り出した画像とする、

"テンプレート画像"
テンプレート画像

2. テンプレートマッチング処理

処理方法の詳細説明は以下

labs.eecs.tottori-u.ac.jp

まずテスト画像とテンプレート画像を読み込み、それぞれグレースケール画像gray, tempとする。

from google.colab import files
uploaded_file = files.upload()
uploaded_file_name = next(iter(uploaded_file))

orig = cv2.imread(uploaded_file_name)
gray = cv2.cvtColor(orig, cv2.COLOR_BGR2GRAY)

from google.colab import files
uploaded_file = files.upload()
uploaded_file_name = next(iter(uploaded_file))

orig2 = cv2.imread(uploaded_file_name)
temp = cv2.cvtColor(orig2, cv2.COLOR_BGR2GRAY)

テスト画像grayからテンプレート画像tempにマッチする箇所を検出するにはcv2.matchTemplate()を使用する。 ここでmethodを指定するときに名前ではなく番号していするため、eval('cv2.TM_CCOEFF')などと記述する。 出力は類似度を表すグレースケール画像が出力される。ここで、類似度が一番高い位置を検出するためcv2.minMaxLoc()を使用する。

res = cv2.matchTemplate(gray,temp,eval('cv2.TM_CCOEFF'))
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = max_loc

検出した位置からテンプレート画像と同じサイズのボックスを描画する。

w, h = temp.shape[::-1]
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(gray,top_left, bottom_right, 255, 2)
plt.subplot(121),plt.imshow(res,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(gray,cmap = 'gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])

"マッチング結果"
マッチング結果

結果はテスト画像から切り抜いた場所の文字8とぴったり一致した。

3. 複数箇所の検出

上の例では最大類似度の1か所のみを検出したが、複数の8の文字を検出するためには閾値を設けて、ボックスを複数描画するように変更すればよい。 閾値以上の類似度をもつ場所が何か所あるか表示させると26か所となった。なお閾値と比較する際にcv2.matchTemplate()の返り値resは最大値max_valで正規化している。

img=np.copy(gray)
threshold = 0.82
loc = np.where(res/(max_val) >= threshold)
i=0
for pt in zip(*loc[::-1]):
    cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), 255, 2)
    i=i+1
print(i)

>26

検出結果を確認するため描画すると、実際には5か所だけに見える。よく見ると類似度が一番高い8の周りのボックス線が太くなっており、類似度最大の8の文字に対して近傍複数の箇所が検出されていると考えられる。

plt.subplot(121),plt.imshow(res,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img,cmap = 'gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])

"複数マッチング結果"
複数マッチング結果