LoginSignup
1
4

More than 1 year has passed since last update.

【画像処理】Numpyでテンプレートマッチング

Posted at

Numpyでテンプレートマッチングを実装してみます。

まず、マッチングを行う画像を読み込みます。

import numpy as np
import matplotlib.pyplot as plt

original_image = plt.imread(image_name)
if np.issubdtype(original_image.dtype, np.integer):
  original_image = original_image / np.iinfo(original_image.dtype).max
gray_image = 0.2116 * original_image[:,:,0] + 0.7152 * original_image[:,:,1] + 0.0722 * original_image[:,:,2]
plt.imshow(gray_image, cmap='gray')

GrayImage.png

テンプレート画像を用意します。

template_image = gray_image[10:55,60:120]
plt.figure(figsize=(1, 1))
plt.imshow(template_image, cmap='gray')

TemplateImage.png

SSD

SSD(Sum of Squared Difference)で相違度を計算します。

R_{ssd}(x, y) = \sum_{i=0}^{N-1}\sum_{j=0}^{M-1}(I(x+i,y+j) - T(i,j))^2

$R_{ssd}(x,y)$は位置$(x,y)$におけるSSDの値、$I(i,j)$と$T(i,j)$はそれぞれ位置$(i,j)$におけるマッチング対象の画像の画素値とテンプレートの画素値、$(N,M)$はテンプレートの大きさとなります。

def match_template_ssd(image, template):
  shape = (image.shape[0] - template.shape[0] + 1, image.shape[1] - template.shape[1] + 1) + template.shape
  strided_image = np.lib.stride_tricks.as_strided(image, shape, image.strides * 2)
  return np.sum((strided_image - template) ** 2.0, axis=(2, 3))

ssd_image = match_template_ssd(gray_image, template_image)
plt.imshow(ssd_image, cmap='gray')
plt.colorbar()

SsdImage.png

SSDが最も小さい箇所がテンプレートと最もマッチする箇所になります。そこに四角形を描画しています。四角形の描画に関しては以下の記事を参照してください。
【画像処理】Numpyで図形描画 - Qiita

def stroke_rectangle(image, color, weight, center, size):
  coord = np.fromfunction(lambda y, x: np.dstack((y + 0.5, x + 0.5)), image.shape[:2])
  dist = np.dstack((abs(coord[:,:,1] - center[0]) - size[0] / 2, abs(coord[:,:,0] - center[1]) - size[1] / 2)).max(axis=2)
  condition = abs(dist) - weight * 0.5 <= 0
  if image.ndim == 3:
    condition = np.tile(condition.reshape(condition.shape + (1,)), (1, 1, image.shape[2]))
  return np.where(condition, color, image)

index = np.unravel_index(np.argmin(ssd_image), ssd_image.shape)
ssd_rect_image = stroke_rectangle(original_image, np.array([1.0, 0.0, 1.0]), 2.0, (index[1] + template_image.shape[1] / 2, index[0] + template_image.shape[0] / 2), (template_image.shape[1], template_image.shape[0]))
plt.imshow(ssd_rect_image)

SsdMatchImage.png

SAD

SAD(Sum of Absolute Difference)で相違度を計算します。

R_{sad}(x, y) = \sum_{i=0}^{N-1}\sum_{j=0}^{M-1}|I(x+i,y+j) - T(i,j)|
def match_template_sad(image, template):
  shape = (image.shape[0] - template.shape[0] + 1, image.shape[1] - template.shape[1] + 1) + template.shape
  strided_image = np.lib.stride_tricks.as_strided(image, shape, image.strides * 2)
  return np.sum(np.abs(strided_image - template), axis=(2, 3))

sad_image = match_template_sad(gray_image, template_image)
plt.imshow(sad_image, cmap='gray')
plt.colorbar()

SadImage.png

SSDと同様にSADの値が最も小さい箇所が最もマッチする箇所なので、そこに四角形を描画します。

index = np.unravel_index(np.argmin(sad_image), sad_image.shape)
sad_rect_image = stroke_rectangle(original_image, np.array([1.0, 0.0, 1.0]), 2.0, (index[1] + template_image.shape[1] / 2, index[0] + template_image.shape[0] / 2), (template_image.shape[1], template_image.shape[0]))
plt.imshow(sad_rect_image)

SadMatchImage.png

NCC

NCC(Normalized Cross-Correlation)で類似度を計算します。

R_{ncc}(x, y) = \frac{\sum_{i=0}^{N-1}\sum_{j=0}^{M-1}I(x+i,y+j)T(i,j)}{\sqrt{\sum_{i=0}^{N-1}\sum_{j=0}^{M-1}I(x+i,y+j)^2\times\sum_{i=0}^{N-1}\sum_{j=0}^{M-1}T(i,j)^2}}
def match_template_ncc(image, template):
  shape = (image.shape[0] - template.shape[0] + 1, image.shape[1] - template.shape[1] + 1) + template.shape
  strided_image = np.lib.stride_tricks.as_strided(image, shape, image.strides * 2)
  return np.sum(strided_image * template, axis=(2, 3)) \
    / (np.sqrt(np.sum(strided_image * strided_image, axis=(2, 3)) * np.sum(template * template)))

ncc_image = match_template_ncc(gray_image, template_image)
plt.imshow(ncc_image, cmap='gray')
plt.colorbar()

NccImage.png

NCCは最も値が大きい箇所が最もマッチする箇所になるので、そこに四角形を描画します。

index = np.unravel_index(np.argmax(ncc_image), ncc_image.shape)
ncc_rect_image = stroke_rectangle(original_image, np.array([1.0, 0.0, 1.0]), 2.0, (index[1] + template_image.shape[1] / 2, index[0] + template_image.shape[0] / 2), (template_image.shape[1], template_image.shape[0]))
plt.imshow(ncc_rect_image)

NccMatchImage.png


実装したコードはGoogle Colaboratoryに置いてあります。

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4