You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Matplotlib Patches实现点击两点绘矩形失败问题求助

问题描述

我正在开发一个程序,功能是显示图片,允许用户点击两个位置后在这两点间绘制矩形。目前用Matplotlib的patches模块尝试实现,能正常获取点击坐标,但添加矩形后没有任何显示效果。坐标已存在数组中供后续使用。

原代码:

import cv2
from matplotlib import pyplot as plt
from matplotlib import patches

# reads the image from the file location
img_path = 'C:\sheepdata\sheep1.png'
image = cv2.imread(img_path)
height, width, channels = image.shape
axis = plt.gca()
figure = plt.gcf()
plt.imshow(image)

#the function that will draw the rectangle based on the two places that the user clicks (left first, then right)
def click(event):
    X1 = 0
    X2 = 0
    Y1 = 0
    Y2 = 0
    
    x1.clear()
    y1.clear()
    x2.clear()
    y2.clear()
    #if they click left it will run this statement
    if event.button == 1:
        #cords used to check what was the last button the user pressed, makes sure it they dont click left twice
        if len(cords) == 0:
            #stores the data in the according array
            x1.append(event.xdata)
            y1.append(event.ydata)
            X1 = event.xdata
            Y1 = event.ydata
            print(x1[0], y1[0])
            #changes the value of len(cords) so it now expects the user to press the right mouse button
            cords.append(1)
    #checks for right mouse button press
    if event.button == 3:
        #checks what button it should be expecting
        if len(cords) > 0:
            #stores the cooardinates of the second cooardinates
            x2.append(event.xdata)
            y2.append(event.ydata)
            X2 = event.xdata
            Y2 = event.ydata
            print(x2[0], y2[0])

            rect = patches.Rectangle((X1, Y1), X2 - X1, Y2 - Y1, linewidth=1, edgecolor='r',
                                     facecolor='none')
            axis.add_patch(rect)
            cords.clear()


def draw_rectangle(x1, y1, x2, y2):
    axis.plot(x1[0], y1[0], 'blue')
    axis.plot(x1[0], y2[0], 'blue')
    axis.plot(x2[0], y1[0], 'blue')
    axis.plot(x2[0], y2[0], 'blue')


cords = []
x1 = [1]
y1 = [1]
x2 = [1]
y2 = [1]

cid = figure.canvas.mpl_connect('button_press_event', click)

# shows the image
plt.show()
问题原因及修复方案

核心问题

  1. 画布未刷新:添加矩形patch后,Matplotlib不会自动刷新画布,新元素无法显示。
  2. 变量作用域错误:click函数内的X1、Y1是局部变量,右键点击时无法保留左键点击的坐标值(每次进入函数都会重置为0)。
  3. 图片颜色通道不匹配:OpenCV读取的图片是BGR格式,Matplotlib默认用RGB显示,会导致图片颜色失真。
  4. 矩形参数合法性:如果第二次点击的坐标在第一次的左上方,矩形的宽度/高度会是负数,Matplotlib无法绘制。

修改后的代码

import cv2
from matplotlib import pyplot as plt
from matplotlib import patches

# 读取图片并转换颜色通道
img_path = r'C:\sheepdata\sheep1.png'  # 用原始字符串避免转义问题
image = cv2.imread(img_path)
# 转换BGR到RGB匹配Matplotlib显示格式
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

axis = plt.gca()
figure = plt.gcf()
plt.imshow(image_rgb)

# 全局变量存储点击坐标,避免局部变量重置丢失数据
cords = []
x1 = []
y1 = []
x2 = []
y2 = []

def click(event):
    # 只处理图片区域内的点击,避免空坐标错误
    if not event.inaxes:
        return
    
    if event.button == 1:
        if len(cords) == 0:
            x1.clear()
            y1.clear()
            x1.append(event.xdata)
            y1.append(event.ydata)
            print(f"左键点击坐标: {x1[0]}, {y1[0]}")
            cords.append(1)
    elif event.button == 3:
        if len(cords) > 0:
            x2.clear()
            y2.clear()
            x2.append(event.xdata)
            y2.append(event.ydata)
            print(f"右键点击坐标: {x2[0]}, {y2[0]}")
            
            # 计算合法的矩形参数:左上角坐标、非负宽高
            left = min(x1[0], x2[0])
            bottom = min(y1[0], y2[0])
            width = abs(x2[0] - x1[0])
            height = abs(y2[0] - y1[0])
            
            rect = patches.Rectangle((left, bottom), width, height, 
                                     linewidth=2, edgecolor='r', facecolor='none')
            axis.add_patch(rect)
            # 刷新画布,让新矩形立即显示
            figure.canvas.draw()
            cords.clear()

cid = figure.canvas.mpl_connect('button_press_event', click)

plt.show()

关键修改点说明

  • 颜色通道转换:用cv2.cvtColor把BGR转成RGB,确保图片显示颜色正常。
  • 全局变量存储坐标:把x1、y1等变量移到函数外,避免局部变量重置导致坐标丢失。
  • 矩形参数修正:计算左上角坐标和非负的宽高,解决反向点击无法绘制的问题。
  • 画布刷新:添加figure.canvas.draw(),触发画布重绘显示新添加的矩形。
  • 点击区域判断:增加event.inaxes判断,只处理图片区域内的点击,避免无效点击导致的错误。

内容的提问来源于stack exchange,提问作者rialluty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 10:32:20