嗨!我正在尝试使用 Python 在 OpenCV 中的模板匹配上添加一个具有半透明填充和实心笔画的矩形。我正在使用的材料来自 Pixel Sprout Studios 的一款名为 Sun Haven 的游戏,可在 Steam 上找到。
操作系统:Microsoft Windows 11
Python版本:3.10.4
OpenCV版本:4.7.0
目前,我有一个脚本可以解决这个问题,但我不喜欢它的实现方式,因为我目前必须循环遍历模板结果两次:
import cv2 as cv
import numpy as np
# Load the haystack and needle images in OpenCV.
haystack_image = cv.imread('sun_haven_14.jpg', cv.IMREAD_UNCHANGED)
needle_image = cv.imread('sun_haven_beecube.jpg', cv.IMREAD_UNCHANGED)
# Haystack image with drawings on.
scribble_image = haystack_image.copy()
# Grab the dimensions of the needle image.
needle_width = needle_image.shape[1]
needle_height = needle_image.shape[0]
# Match the needle image against the the haystack image.
result = cv.matchTemplate(haystack_image, needle_image, cv.TM_CCOEFF_NORMED)
# Define a standard to which a result is assumed positive.
threshold = 0.5
# Filter out image locations where OpenCV falls below the confidence threshold.
locations = np.where(result >= threshold)
# Convert the locations from arrays to X/Y-coordinate tuples.
locations = list(zip(*locations[::-1]))
# Debug-print the locations to the console.
#print(locations)
rectangles = []
# For all the locations found...
for location in locations:
# Define a rectangle to draw around the location.
rectangle = [int(location[0]), int(location[1]), needle_width, needle_height]
# Append the rectangle to the rectangle collection.
rectangles.append(rectangle)
# Group duplicate rectangles from overlapping results.
rectangles, weights = cv.groupRectangles(rectangles, 1, 1)
# If we have any rectangles at all...
if len(rectangles):
print('Found needle(s)!')
for rectangle in rectangles:
# Determine the location position.
top_left = (rectangle[0], rectangle[1])
bottom_right = (rectangle[0] + rectangle[2], rectangle[1] + rectangle[3])
# Draw a transparent, filled rectangle over the detected needle image.
cv.rectangle(scribble_image, top_left, bottom_right, color = (0, 255, 0), thickness = -1)
result_image = cv.addWeighted(scribble_image, 0.25, haystack_image, 1 - 0.25, 0)
for rectangle in rectangles:
# Determine the location position.
top_left = (rectangle[0], rectangle[1])
bottom_right = (rectangle[0] + rectangle[2], rectangle[1] + rectangle[3])
# Draw a solid line around the detected needle image.
cv.rectangle(result_image, top_left, bottom_right, color = (0, 255, 0), thickness = 2, lineType = cv.LINE_4)
# Display the image in a window.
cv.imshow('Result', result_image)
else:
print('No needle found...')
# Pause the script.
cv.waitKey()
# Destroy all the OpenCV 2 windows.
cv.destroyAllWindows()
我更喜欢将两个“矩形中的矩形”循环组合成一个循环,但如果我这样做,我只会得到填充,而不是结果周围的描边。
如您所见,这会检测并突出显示原始图像中的四个蜂立方,但我宁愿合并两个循环,以免重复矩形迭代并提高性能。
我尝试将两个循环合并到此中:
for rectangle in rectangles:
# Determine the location position.
top_left = (rectangle[0], rectangle[1])
bottom_right = (rectangle[0] + rectangle[2], rectangle[1] + rectangle[3])
# Draw a transparent, filled rectangle over the detected needle image.
cv.rectangle(scribble_image, top_left, bottom_right, color = (0, 255, 0), thickness = -1)
# Draw a solid line around the detected needle image.
cv.rectangle(scribble_image, top_left, bottom_right, color = (0, 255, 0), thickness = 2, lineType = cv.LINE_4)
result_image = cv.addWeighted(scribble_image, 0.25, haystack_image, 1 - 0.25, 0)
# Display the image in a window.
cv.imshow('Result', result_image)
但是,这不会产生我正在寻找的结果,因为它只会绘制透明填充,而不是描边:
那么我是否陷入了两个几乎相同的 for 循环,或者有没有办法在单个循环中做到这一点? 我真的不想重复那些只需要做一次的事情,但如果必须这样做,我就必须这样做。
期待反馈,干杯!
感谢@Grismar的反馈,我现在避免在与透明填充矩形相同的图层上绘制实线矩形,而是直接在干草堆图像上绘制:
for rectangle in rectangles:
# Determine the location position.
top_left = (rectangle[0], rectangle[1])
bottom_right = (rectangle[0] + rectangle[2], rectangle[1] + rectangle[3])
# Draw a transparent, filled rectangle over the detected needle image.
cv.rectangle(scribble_image, top_left, bottom_right, color = (0, 255, 0), thickness = -1)
# Draw a solid line around the detected needle image.
cv.rectangle(haystack_image, top_left, bottom_right, color = (0, 255, 0), thickness = 2, lineType = cv.LINE_4)
result_image = cv.addWeighted(scribble_image, 0.25, haystack_image, 1 - 0.25, 0)
# Display the image in a window.
cv.imshow('Result', result_image)