0

I am trying to get the percent chance that an image is in another image in OpenCV.

Here are the images that I am comparing:

Small image

Large image]2

Here is my code:

import cv2
import numpy as np

large_image = cv2.imread(r'Directory here')

#Cropping the image so that it's easier to compare
height = large_image.shape[0]
width = large_image.shape[1]
large_image = large_image[5:height-173,260:width-25]

small_image = cv2.imread(r'Directory here')

method = cv2.TM_SQDIFF_NORMED

# Read the images from the file

result = cv2.matchTemplate(small_image, large_image, method)

#BELOW IS ONLY IF YOU WANT TO SEE A RECTANGLE AROUND THE IMAGE
# We want the minimum squared difference
mn,_,mnLoc,_ = cv2.minMaxLoc(result)

# Draw the rectangle:
# Extract the coordinates of our best match
MPx,MPy = mnLoc

# Get the size of the template. This is the same size as the match.
trows,tcols = small_image.shape[:2]

# Draw the rectangle on large_image
cv2.rectangle(large_image, (MPx,MPy),(MPx+tcols,MPy+trows),(0,0,255),2)

# Display the original image with the rectangle around the match.
cv2.imshow('output',large_image)
cv2.waitKey(0)

Is this even possible with OpenCV?

HansHirse
  • 18,010
  • 10
  • 38
  • 67
  • Use TM_CCOEFF_NORMED and follow what HansHirse said below about masking. This method theoretically should produce a float image that should range between -1 and 1 with 1 being a perfect match, though typically between 0 and 1. Find the maximum value in the image and multiply by 100 to get the percent match. – fmw42 Aug 20 '21 at 15:13
  • Can you include code, I don't know where to put "cv2.TM_CCOEFF_NORMED". Sorry if this sounds stupid, but I'm not that good at OpenCV. – pythonuser1 Aug 21 '21 at 04:22
  • Replace `method = cv2.TM_SQDIFF_NORMED` with `method = cv2.TM_CCOEFF_NORMED` See https://docs.opencv.org/4.1.1/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d – fmw42 Aug 21 '21 at 15:09
  • I tried replacing "cv2.TM_CCOEFF_NORMED" with "cv2.TM_SQDIFF_NORMED" using HansHirse's code, but it isn't working the same as "cv2.TM_SQDIFF_NORMED". – pythonuser1 Aug 22 '21 at 19:31
  • I wanted you to use `method = cv2.TM_CCOEFF_NORMED` That has a perfect match at 1. The other has a perfect match at 0. So they do not work the same. If you want to get a percentage. Use what I said and multiply by 100. – fmw42 Aug 22 '21 at 21:04
  • See https://martin-thoma.com/zero-mean-normalized-cross-correlation/ and https://www.ocean.washington.edu/courses/ess522/lectures/08_xcorr.pdf – fmw42 Aug 22 '21 at 21:22

1 Answers1

2

In general, your approach and code is correct. What's missing: Please notice, that your template (small image) has some transparency, thus an alpha channel. To preserve that one, use the cv2.IMREAD_UNCHANGED flag in the corresponding cv2.imread call. Right now, the background of your template is filled with black and white pixels, which lead to false result when matching the pixels with the actual image (large image).

Fortunately, cv2.matchTemplate has a mask parameter. Thus, the pixels to be matched are limited to the pixels described by the that mask. Great, that's exactly what we get from the alpha channel of your template.

Here's some (heavily) modified and shortened code:

import cv2

# Read images; preserve alpha channel in template
image = cv2.imread('image.png')
templ = cv2.imread('template.png', cv2.IMREAD_UNCHANGED)

# Actual template matching; use alpha channel of template as mask
result = cv2.matchTemplate(image, templ[..., :3], cv2.TM_SQDIFF_NORMED,
                           mask=templ[..., 3])

# Get location of best match, and draw rectangle
mpx, mpy = cv2.minMaxLoc(result)[2]
h, w = templ.shape[:2]
cv2.rectangle(image, (mpx, mpy), (mpx + w, mpy + h), (0, 0, 255), 2)

# Output
cv2.imshow('image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

And, that's the result, which should be the expected, I guess:

Output

By the way: Be careful with the parameters of cv2.matchTemplate. The first parameter is the actual image (large image), the second one is the template (small image). That's switched in your code! When not using a mask, the order has no effect, but when providing a mask, the shape must be the same as the template, and is automatically checked against the shape of the second parameter!

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.19042-SP0
Python:        3.9.6
PyCharm:       2021.2
OpenCV:        4.5.3
----------------------------------------
HansHirse
  • 18,010
  • 10
  • 38
  • 67