使用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()
问题原因及修复方案
核心问题
- 画布未刷新:添加矩形patch后,Matplotlib不会自动刷新画布,新元素无法显示。
- 变量作用域错误:
click函数内的X1、Y1是局部变量,右键点击时无法保留左键点击的坐标值(每次进入函数都会重置为0)。 - 图片颜色通道不匹配:OpenCV读取的图片是BGR格式,Matplotlib默认用RGB显示,会导致图片颜色失真。
- 矩形参数合法性:如果第二次点击的坐标在第一次的左上方,矩形的宽度/高度会是负数,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
相关产品推荐
相关产品推荐

