【Python/OpenCV】テンプレートマッチング(NCC)の実装例

この記事では、Pythonで画像のテンプレートマッチング(類似度尺度NCC)を行う方法をソースコード付きで解説します。

テンプレートマッチング(NCC)

テンプレートマッチング(Template matching)とは、入力画像中からテンプレート画像(部分画像)と最も類似する箇所を探索する処理です。
原理については下記事で解説しています。
【参考】テンプレートマッチングの原理・計算式・例題(SAD, SSD, NCC)

■NCC
NCC(Normalized Cross Correlation)では、「正規化相互相関」で類似度を評価します。
NCCの値は-1.0~1.0に収まり、最大値である1.0に近いほど類似度が高くなります。

今回は、SADを評価値とし、以下の2通りの方法でテンプレートマッチングの処理を実装しました。

①NumPyライブラリで実装
②OpenCVの「cv2.matchTemplate」で実装

書式(OpenCV)

match = cv2.matchTemplate(gray, temp,cv2.TM_CCORR_NORMED)
min_value, max_value, pt_min, pt_max = cv2.minMaxLoc(match)
パラメータ 説明
gray 入力画像(グレースケール)
temp テンプレート画像(グレースケール)
pt_min スコアが最小の走査位置(最も類似しない点)
pt_max スコアが最大の走査位置(最も類似する点)

ソースコード(Python3)

サンプルプログラムのソースコードです。

#-*- coding:utf-8 -*-
import cv2
import numpy as np

def template_matching_ncc(src, temp):
    # 画像の高さ・幅を取得
    h, w = src.shape
    ht, wt = temp.shape
    
    # スコア格納用の2次元リスト
    score = np.empty((h-ht, w-wt))

    # 配列のデータ型をuint8からfloatに変換
    src = np.array(src, dtype="float")
    temp = np.array(temp, dtype="float")

    # 走査
    for dy in range(0, h - ht):
        for dx in range(0, w - wt):
            # 窓画像
            roi = src[dy:dy + ht, dx:dx + wt]
            # NCCの計算式
            num = np.sum(roi * temp)
            den = np.sqrt( (np.sum(roi ** 2))) * np.sqrt(np.sum(temp ** 2)) 
            if den == 0: score[dy, dx] = 0
            score[dy, dx] = num / den

    # スコアが最大(1に最も近い)の走査位置を返す
    pt = np.unravel_index(score.argmax(), score.shape)

    return (pt[1], pt[0])


def main():
    # 入力画像とテンプレート画像をで取得
    img = cv2.imread("input.png")
    temp = cv2.imread("temp.png")

    # グレースケール変換
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)   
    temp = cv2.cvtColor(temp, cv2.COLOR_RGB2GRAY)   

    # テンプレート画像の高さ・幅
    h, w = temp.shape

    # テンプレートマッチング(NumPyで実装)
    pt = template_matching_ncc(gray, temp)

    # テンプレートマッチング(OpenCVで実装)
    #match = cv2.matchTemplate(gray, temp, cv2.TM_CCOEFF_NORMED)
    #min_value, max_value, min_pt, max_pt = cv2.minMaxLoc(match)
    #pt = max_pt

    # テンプレートマッチングの結果を出力
    cv2.rectangle(img, (pt[0], pt[1] ), (pt[0] + w, pt[1] + h), (0,0,200), 3)
    cv2.imwrite("output.png", img)


if __name__ == "__main__":
    main()

※動作には、OpenCVとNumPyライブラリが必要です。(導入方法は下記参照)
【Python3】OpenCV3をインストール

実行結果

サンプルプログラムの実行結果です。

■左から入力画像(input.jpg)、テンプレート画像(temp.jpg)、出力画像(result.jpg)

お借りした画像:プロ生ちゃん(暮井 慧)

【関連記事】
【画像処理入門】アルゴリズム&プログラミング

シェア&フォローお願いします!