我想比较两个图像,并找到模板内第二个图像的位置,所以第一个图像是这样的:

template

这是我们的模板图像,应该与下面的图像进行比较:

original image

但是当我运行代码时,我得到了以下结果:

enter image description here

如何提高成绩?

import cv2
import numpy as np
from imutils.object_detection import non_max_suppression
import matplotlib.pyplot as plt
template =cv2.imread("euro.jpg",cv2.IMREAD_COLOR)
template =cv2.resize(template,(99,99))
img =cv2.imread("euro_2024.jpg",cv2.IMREAD_COLOR)
img2 = img.copy()
# image =cv2.resize(image,(700,700))
h,w =template.shape[:2]

# All the 6 methods for comparison in a list
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
            'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']

for meth in methods:
    img = img2.copy()
    method = eval(meth)

    # Apply template Matching
    res = cv2.matchTemplate(img,template,method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

    # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)

    cv2.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()

推荐答案

This would mean the matching function focuses only on the ball and not on any background noise.
But you should also convert the template to grayscale to make it more distinguishable. You can see this done in "OpenCV-Python Tutorials / Image Processing in OpenCV /Template Matching": template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY).
Then manually determine the bounding box of the ball and crop the template: cropped_template = template_gray[y:y+h, x:x+w].

OpenCV's matchTemplate可以取mask as an optional argument,它告诉它在匹配过程中只考虑蒙版的白色部分.

So you can create a mask for the cropped template, and pass it to matchTemplate to only consider the ball during the matching process: mask = np.zeros(cropped_template.shape, dtype=np.uint8)
Use numpy.zeros: `` It will create an array of zeros with the same dimensions as template_gray (which represents the template image converted to grayscale).

Draw a white circle on the mask where the ball is located:
cv2.circle(mask, (mask.shape[1]//2, mask.shape[0]//2), radius, 255, -1)

radius应该被设置为与模板图像中感兴趣对象的大小相匹配的值,circle函数将用值255填充圆,从而在蒙版中创建一个白色区域.

你的代码是:

import cv2
import numpy as np
import matplotlib.pyplot as plt

template = cv2.imread("path_to_cropped_template.jpg")
template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)

x, y, w, h = 100, 100, 50, 50  # Replace with actual values
cropped_template = template_gray[y:y+h, x:x+w]

# Create a mask for the cropped template
mask = np.zeros(cropped_template.shape, dtype=np.uint8)
cv2.circle(mask, (w//2, h//2), w//2, (255), -1)

search_img = cv2.imread("path_to_search_image.jpg")
search_img_gray = cv2.cvtColor(search_img, cv2.COLOR_BGR2GRAY)

res = cv2.matchTemplate(search_img_gray, cropped_template, cv2.TM_CCOEFF_NORMED, mask=mask)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(search_img, top_left, bottom_right, 255, 2)

plt.imshow(cv2.cvtColor(search_img, cv2.COLOR_BGR2RGB))
plt.show()

同样,裁剪部分中的x, y, w, h应该是实际模板图像中球的坐标和大小.


如果模板在搜索图像中多次出现,则可以添加non_max_suppression:

import cv2
import numpy as np
import matplotlib.pyplot as plt
from imutils.object_detection import non_max_suppression

template = cv2.imread('path_to_cropped_template.jpg', cv2.IMREAD_COLOR) 
img = cv2.imread('path_to_search_image.jpg', cv2.IMREAD_COLOR)

template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

mask = np.zeros(template_gray.shape, dtype=np.uint8)
cv2.circle(mask, (mask.shape[1] // 2, mask.shape[0] // 2), mask.shape[1] // 2, 255, -1)

h, w = template_gray.shape[:2]

# Match template using the mask
res = cv2.matchTemplate(img_gray, template_gray, cv2.TM_CCOEFF_NORMED, mask=mask)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
top_left = min_loc if res.min() == min_val else max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)

cv2.rectangle(img, top_left, bottom_right, (255, 0, 0), 2)

# Apply non-maximum suppression to the bounding boxes
rects = [[*top_left, *bottom_right]]
pick = non_max_suppression(np.array(rects))

for (startX, startY, endX, endY) in pick:
    cv2.rectangle(img, (startX, startY), (endX, endY), (0, 255, 0), 2)

plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('Detected Point')
plt.show()

这不能通过模板匹配来解决.你可以看到不同的3D物体.

I agree: template matching is generally well-suited for 2D image patterns that do not change perspective or shape. It would assume the template and the portion of the image being searched are similarly oriented and scaled.
When the object in question is three-dimensional, like a soccer ball, and the images capture it from different angles or under different lighting conditions, the template's appearance might change due to perspective distortion, lighting changes, and occlusions.

您可以try 多尺度模板匹配和蒙版的组合,这将比简单的模板匹配更强大,但仍然不是匹配3D对象图像的包罗万象的解决方案,这些图像可能由于旋转、透视偏移和其他因素而显得非常不同.

import cv2
import numpy as np
import matplotlib.pyplot as plt

def multi_scale_template_matching_with_mask(search_img, template, template_mask, scale_steps=20, method=cv2.TM_CCOEFF_NORMED):
    h, w = template.shape[:2]
    # keep track of the most accurate matching
    found = None

    search_img_gray = cv2.cvtColor(search_img, cv2.COLOR_BGR2GRAY)
    template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)

    for scale in np.linspace(0.2, 1.0, scale_steps)[::-1]:
        # Resize the image according to the scale, and keep track of the ratio of the resizing
        resized = cv2.resize(search_img_gray, None, fx=scale, fy=scale, interpolation=cv2.INTER_AREA)
        r = search_img_gray.shape[1] / float(resized.shape[1])

        # If the resized image is smaller than the template, then break from the loop
        if resized.shape[0] < h or resized.shape[1] < w:
            break

        # Apply template Matching with the mask
        result = cv2.matchTemplate(resized, template_gray, method, mask=template_mask)

        _, max_val, _, max_loc = cv2.minMaxLoc(result)

        if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
            matchLoc = min_loc
        else:
            matchLoc = max_loc

        # If we have found a new maximum correlation value, then update the bookkeeping variable
        if found is None or max_val > found[0]:
            found = (max_val, matchLoc, r)

    # Unpack the bookkeeping variable and compute the (x, y) coordinates of the bounding box
    _, max_loc, r = found
    start_x, start_y = int(max_loc[0] * r), int(max_loc[1] * r)
    end_x, end_y = int((max_loc[0] + w) * r), int((max_loc[1] + h) * r)

    cv2.rectangle(search_img, (start_x, start_y), (end_x, end_y), (255, 0, 0), 2)

    plt.imshow(cv2.cvtColor(search_img, cv2.COLOR_BGR2RGB))
    plt.show()

search_img = cv2.imread('path_to_search_image.jpg')
template = cv2.imread('path_to_template.jpg')
template_mask = cv2.imread('path_to_template_mask.jpg', 0)  # Assuming the mask is a grayscale image

multi_scale_template_matching_with_mask(search_img, template, template_mask)

multi_scale_template_matching_with_mask将try 跨不同尺度在搜索图像中找到模板,同时使用掩模将匹配集中在模板的特定特征上(例如,球).

Python相关问答推荐

LAB中的增强数组

在函数内部使用eval(),将函数的输入作为字符串的一部分

点到面的Y距离

Pytest两个具有无限循环和await命令的Deliverc函数

如何制作10,000年及以后的日期时间对象?

Mistral模型为不同的输入文本生成相同的嵌入

大小为M的第N位_计数(或人口计数)的公式

如何在类和classy-fastapi -fastapi- followup中使用FastAPI创建路由

在Python中管理打开对话框

运输问题分支定界法&

Python—从np.array中 Select 复杂的列子集

用砂箱开发Web统计分析

使用Python和文件进行模糊输出

使用特定值作为引用替换数据框行上的值

在Python中计算连续天数

在Docker容器(Alpine)上运行的Python应用程序中读取. accdb数据库

GPT python SDK引入了大量开销/错误超时

在电影中向西北方向对齐""

提取数组每行的非零元素

关于数字S种子序列内部工作原理的困惑