OpenCV 5.0.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 5.0.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
テンプレートマッチング

目的

この章では、以下を学ぶ

理論

テンプレートマッチングは、より大きな画像の中でテンプレート画像の位置を探索して見つけるための手法である。OpenCV にはこの目的のための関数 cv.matchTemplate() が用意されている。この関数はテンプレート画像を入力画像上で(2次元の畳み込みと同様に)スライドさせ、テンプレート画像と、その下にある入力画像のパッチとを比較する。OpenCV にはいくつかの比較手法が実装されている(詳細はドキュメントを参照)。戻り値はグレースケール画像であり、各ピクセルはそのピクセルの近傍がテンプレートとどれだけマッチするかを表す。

入力画像のサイズが (WxH)、テンプレート画像のサイズが (wxh) であれば、出力画像のサイズは (W-w+1, H-h+1) となる。結果が得られたら、cv.minMaxLoc() 関数を使って最大値・最小値の位置を見つけられる。その位置を矩形の左上隅とし、(w,h) を矩形の幅と高さとする。その矩形がテンプレートの領域となる。

覚え書き
比較手法として cv.TM_SQDIFF を使う場合は、最小値が最良のマッチを与える。

OpenCV におけるテンプレートマッチング

ここでは例として、メッシ (Messi) の写真の中から彼の顔を探す。そこで以下のようなテンプレートを作成した:

image

すべての比較手法を試して、それらの結果がどのように見えるかを確認する:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE)
assert img is not None, "file could not be read, check with os.path.exists()"
img2 = img.copy()
template = cv.imread('template.jpg', cv.IMREAD_GRAYSCALE)
assert template is not None, "file could not be read, check with os.path.exists()"
w, h = template.shape[::-1]
# All the 6 methods for comparison in a list
methods = ['TM_CCOEFF', 'TM_CCOEFF_NORMED', 'TM_CCORR',
'TM_CCORR_NORMED', 'TM_SQDIFF', 'TM_SQDIFF_NORMED']
for meth in methods:
img = img2.copy()
method = getattr(cv, meth)
# Apply template Matching
res = cv.matchTemplate(img,template,method)
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv.rectangle(img,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(img,cmap = 'gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.suptitle(meth)
plt.show()
void minMaxLoc(InputArray src, double *minVal, double *maxVal=0, Point *minLoc=0, Point *maxLoc=0, InputArray mask=noArray())
Finds the global minimum and maximum in an array.
Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
Loads an image from a file.
void rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
Draws a simple, thick, or filled up-right rectangle.
void matchTemplate(InputArray image, InputArray templ, OutputArray result, int method, InputArray mask=noArray())
Compares a template against overlapped image regions.

以下の結果を参照:

image
image
image
image
image
image

cv.TM_CCORR を使った結果は、期待したほど良くないことがわかる。

複数オブジェクトのテンプレートマッチング

前の節では、画像内に一度しか現れないメッシの顔を探した。複数回出現する物体を探す場合、cv.minMaxLoc() ではすべての位置を得ることはできない。その場合はしきい値処理を用いる。この例では有名なゲーム Mario のスクリーンショットを使い、その中のコインを見つける。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img_rgb = cv.imread('mario.png')
assert img_rgb is not None, "file could not be read, check with os.path.exists()"
img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
template = cv.imread('mario_coin.png', cv.IMREAD_GRAYSCALE)
assert template is not None, "file could not be read, check with os.path.exists()"
w, h = template.shape[::-1]
res = cv.matchTemplate(img_gray,template,cv.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
cv.imwrite('res.png',img_rgb)
bool imwrite(const String &filename, InputArray img, const std::vector< int > &params=std::vector< int >())
Saves an image to a specified file.
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)
Converts an image from one color space to another.

結果:

image