利用MKL實現OpenCV的模板匹配(matchTemplate)

Icys發表於2024-05-19

基於FFT實現OpenCV的模板匹配(matchTemplate)

以 TM_CCORR_NORMED 為例,因為這個實現簡單,並且效率高。

先看公式

\[R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y'))}{\sqrt{ \sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} \]

顯然,分子是I圖和T圖的卷積。

分母是T圖平方的求和乘以I圖平方和T圖大小的全為1的矩陣,開方的結果。

根據卷積定理,實現方法就很顯然了。

import numpy as np
from scipy import signal
from matplotlib import pyplot as plt

import cv2

I = cv2.imread('3.png', cv2.IMREAD_GRAYSCALE)
T = cv2.imread('4.png', cv2.IMREAD_GRAYSCALE)

I = I.astype(np.float32) / 255
T = T.astype(np.float32) / 255

import mkl_fft

def mkl_fft_conv2d(A,K):
    tmp_cols = A.shape[0] + K.shape[0] - 1
    tmp_rows = A.shape[1] + K.shape[1] - 1

    input = np.zeros((tmp_cols, tmp_rows)).astype(np.float32)
    input[:A.shape[0], :A.shape[1]] = A
    kernel = np.zeros((tmp_cols, tmp_rows)).astype(np.float32)
    kernel[:K.shape[0], :K.shape[1]] = K

    fi = mkl_fft.fft2(input)
    fk = mkl_fft.fft2(kernel)

    # output as valid
    output = mkl_fft.ifft2(fi * fk)
    output = np.real(output)
    output = output[K.shape[0]-1:-K.shape[0]+1, K.shape[1]-1:-K.shape[1]+1]
    return output

import time

t0 = time.time()
r0 = mkl_fft_conv2d(I, np.flip(T,axis=(0,1)))
ST = np.sum(T ** 2)
S = mkl_fft_conv2d(I ** 2, np.ones_like(T))
r0 = r0 / np.sqrt(ST * S)


t1 = time.time()
print('fftconvolve:', t1-t0)
t0 = time.time()
r1 = cv2.matchTemplate(I, T, cv2.TM_CCORR_NORMED)
t1 = time.time()
print('matchTemplate:', t1-t0)

plt.figure()
plt.imshow(r0)
plt.colorbar()
plt.title('fftconvolve')

plt.figure()
plt.imshow(r1)
plt.colorbar()
plt.title('matchTemplate')

plt.show()

max_x0, max_y0 = np.unravel_index(np.argmax(r0), r0.shape)
max_x1, max_y1 = np.unravel_index(np.argmax(r1), r1.shape)

print(max_x0, max_y0)
print(max_x1, max_y1)

print(r0[max_x1, max_y1])

和OpenCV效果對比

image
image

可以看出結果是一樣的

相關文章