2021/02/28
OpenCVでテンプレートマッチングを使う
画像の中に下図のようなスケールがあり、そのスケールの目盛の値をどのように読み取るかを考えている中で、まず数字を画像認識しなくてはならないなと思い、OpenCVでテンプレートマッチングを行ってみました。OpenCVは良く使いますが、テンプレートマッチングは初めてです。ネット上にいろいろ情報があるので、それらを参考にしました。

import cv25行目で入力画像を読み込み、8〜14行目で9個のテンプレート画像(0〜8数字の画像)を読み込みます。17行目から各数字についてテンプレートマッチング(20行目)を行います。今回は、正規化相関係数法(NCC: Normalized Cross Correlation)で類似度を判断しました。OpenCVではcv2.TM_CCOEFF_NORMEDを指定しました。
import numpy as np
# Input Image
img = cv2.imread('scale.png',0)
# Template Image
TempFilename = []
TempValname = []
for i in range(9):
TempFilename.append(str(i)+'.png')
TempValname.append('Template'+str(i))
# Image read
TempValname[i] = cv2.imread(TempFilename[i],0)
# Template matching
for i in range(9):
w, h = TempValname[i].shape[::-1] # Template image size
res = cv2.matchTemplate(img, TempValname[i], cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(str(i) + ' -> max_val: ' + str('{:.3f}'.format(max_val)), ', max_loc: ' + str(max_loc))
# Result image
top_left = max_loc
btm_right = (top_left[0]+w, top_left[1]+h)
img_temp = img.copy()
cv2.rectangle(img_temp, top_left, btm_right, 0, 2)
cv2.imwrite('res'+str(i)+'.png',img_temp)
22行目の結果は以下の通りでした。数字の0〜8について、最大値(max_val)が1に近いほどマッチングが良いことを表していますが、同じ画像から採取しているので、当然、完全マッチングしていることが分かります。max_locは検出したオブジェクトの左上の座標を表しています。


次に一番初めのスケール画像の結果は以下の通りになりました。

今回初めてテンプレートマッチングを触ってみましたが、簡単に数字とその画像上の座標を検出できることが分かりました。いろいろと応用が利きそうなので別案件でも使ってみようと思います。