I have a custom template matching function that is based on Zero mean Normalized Cross Correlation: ZNCC formula
def ZNCC_mat(array1, array2):
array1 = array1 / 255
array2 = array2 / 255
zmean_array1 = array1 - np.mean(array1)
zmean_array1_norm = zmean_array1 / np.linalg.norm(zmean_array1)
array2_view = np.lib.stride_tricks.sliding_window_view(
array2, window_shape=array1.shape
)
zmean_array2 = array2_view - np.mean(array2_view, axis=(2, 3), keepdims=True)
zmean_array2_view_norm = zmean_array2 / np.linalg.norm(
zmean_array2, axis=(2, 3), keepdims=True
)
result = np.einsum("ij,klij->kl", zmean_array1_norm, zmean_array2_view_norm)
return result
Quick explanation:
- normalize the gray images to have values between 0-1
- subtract the template by its mean and divide by the std
- use
np.lib.stride_tricks.sliding_window_viewto divide the source image into sub images/matrices - subtract each region by its mean and divide by the std
- use
np.einsumto compute the cross correlation between the zero mean normalized template and each zero mean normalized region of the source
However after computing array2_view it is very heavy to do operations on the submatrices. I get this error:
Traceback (most recent call last):
File "test/similarity_metrics_comparisons.py", line 17, in <module>
result = ZNCC_mat(template_gray, source_gray)
File "test/einsum_tests.py", line 145, in ZNCC_mat
zmean_array2 = array2_view - np.mean(array2_view, axis=(2, 3), keepdims=True)
numpy.core._exceptions._ArrayMemoryError: Unable to allocate 35.4 GiB for an array with shape (478, 1150, 97, 89) and data type float64
Any tips on what could optimize the operations?
if you want to run the code, with drawing a rectangle around the estimated position:
example of images: source template
#do not forget to read your source and template images
source = cv2.imread()
template = cv2.imread()
source_gray = cv2.cvtColor(source, cv2.COLOR_BGR2GRAY)
template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
result = ZNCC_mat(template_gray, source_gray)
print(result.max())
h, w = template_gray.shape
y, x = np.unravel_index(result.argmax(), result.shape)
top_left = (x, y)
bottom_right = (x + w, y + h)
cv2.rectangle(source, top_left, bottom_right, (0, 255, 0), 2)
plt.subplot(131),plt.imshow(source)
plt.subplot(132),plt.imshow(result)
plt.subplot(133),plt.imshow(template)
plt.show()