今からでも間に合う

技術を学ぶのは今からでも遅くない

opencvでパターンマッチング(テンプレートマッチング)

ある画像の中から、パターン(テンプレート)と一致する個所を検出するパターンマッチングを試してみました。

環境

  • VSCode
  • python 3.11.0

使用するライブラリ

  • cv2

パッケージのインストール方法についてはこちら

使用する画像

検索対象

google先生のTOPページ

google先生のTOPページ

テンプレート画像

テンプレート画像

試してみる

上記検索対象画像から、テンプレート画像にマッチする個所を探していきます。

コード全文

import cv2
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
  
def show_image(title, image):
    cv2.imshow(title, image)
    cv2.waitKey()
    cv2.destroyAllWindows()
  
def pattern_match():
    file_image = r"./google.png"
    file_template = r"./google_template.png"
  
    image = cv2.imread(file_image)
    template = cv2.imread(file_template)
  
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
  
    result = cv2.matchTemplate(image_gray, template_gray, cv2.TM_CCOEFF_NORMED)
  
    df = pd.DataFrame(result)
    sns.heatmap(df)
    plt.show()
  
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
    w, h = template_gray.shape[::-1]
    top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)
      
    ret_image = cv2.rectangle(image, top_left, bottom_right, (0, 0, 255), 2)
    show_image("img", ret_image)
      
if __name__=="__main__":
    pattern_match()

グレースケール化

画像を読み込み、グレースケール化します。
パターンマッチはグレースケール化されてないと動作しません。

image = cv2.imread(file_image)
template = cv2.imread(file_template)
  
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)

グレースケール

パターンマッチ

cv2.matchTemplateを使用します。

result = cv2.matchTemplate(image_gray, template_gray, cv2.TM_CCOEFF_NORMED)
  
df = pd.DataFrame(result)
sns.heatmap(df)
plt.show()

第1引数:対象画像
第2引数:テンプレート画像
第3引数:検出方法

検出方法にはいくつか種類があります(6種)。
どのような場合にどの方法を選択すればよいのかはわかりません。
とりあえず今回はTM_CCOEFF_NORMEDを選択してみました。

戻り値にはマッチ結果の情報が含まれています。
これをヒートマップで表示してみると↓のような結果が得られました。
それっぽいところが一致度高そうに見えています。

TM_CCOEFF_NORMED

以下は参考です。
TM_CCOEFF

左:TM_CCOEFF、右:TM_CCOEFF_NORMED

TM_CCORR

左:TM_CCORR、右:TM_CCORR_NORMED

TM_SQDIFF

左:TM_SQDIFF、右:TM_SQDIFF_NORMED

マッチ度の高い箇所を表示する

検出した個所を可視化します。
cv2.minMaxLoc()に得られた結果を渡すことで、マッチ度最小、最大、その位置を取得できます。
その情報を使って、四角で囲みます。

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
w, h = template_gray.shape[::-1]
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
  
ret_image = cv2.rectangle(image, top_left, bottom_right, (0, 0, 255), 2)
show_image("img", ret_image)

結果

無事検出できました。

結果

おしまい

パターンマッチはサイズや傾きまで一致していないと検出してくれないようです。
せっかくなので、異なるサイズのパターンマッチも試してみます。

python入門Top

プライバシーポリシー


d払いポイントGETモール