Python 中的 OpenCV:在一个循环中填充和描边的矩形

问题描述 投票:0回答:1

单循环中的 OpenCV 矩形填充和描边

简介

嗨!我正在尝试使用 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()

我更喜欢将两个“矩形中的矩形”循环组合成一个循环,但如果我这样做,我只会得到填充,而不是结果周围的描边。

图片

干草堆图片 (sun_haven_14.jpg)

针图像 (sun_haven_beecube.jpg)

OpenCV 脚本结果(期望的结果)

如您所见,这会检测并突出显示原始图像中的四个蜂立方,但我宁愿合并两个循环,以免重复矩形迭代并提高性能。

想要的改变

我尝试将两个循环合并到此中:

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 循环,或者有没有办法在单个循环中做到这一点? 我真的不想重复那些只需要做一次的事情,但如果必须这样做,我就必须这样做。

期待反馈,干杯!

python opencv graphics drawing game-automation
1个回答
0
投票

问题解决了

感谢@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)
© www.soinside.com 2019 - 2024. All rights reserved.