Issue
I am trying to make a program that displays an image, letting the user click in two places and then drawing a rectangle between those two places. I am trying to use matplotlib patches however everything works returning the coordinates of the places that I click however it doesn't draw a rectangle. I am trying to use patches however nothing happens.
PS They are stored as arrays for later use.
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()
Solution
I see two main issues with your code. The first is that even though you print out the first coordinate after the click, you are overwriting that value when you click for the second coordinate because you have X1 = 0
and Y1 = 0
at the beginning of your function. Secondly, you are missing a call to tell matplotlib to redraw the figure, i.e. figure.canvas.draw()
.
To do what you want, I used global variables to keep track of the clicked coordinates (I don't love global variables but I think they are fine for this application) and only created the rectangle after two clicks have been made. Note: my version uses two left clicks to determine the locations of the points. (I also use slightly different notation to use what is more standard.)
import matplotlib.pyplot as plt
from matplotlib.backend_bases import MouseButton
from matplotlib.patches import Rectangle
import numpy as np
plt.close("all")
rng = np.random.default_rng(42)
x = rng.random(50)
y = rng.random(50)
fig, ax = plt.subplots()
ax.scatter(x, y)
rectangle = None
rectangle_coords = []
def on_click(event):
global rectangle_coords, rectangle
if event.button is not MouseButton.LEFT:
return
# remove the previous rectangle if clicked again
if len(rectangle_coords) == 2:
rectangle_coords = []
rectangle.remove()
x = event.xdata
y = event.ydata
rectangle_coords.append((x, y))
if len(rectangle_coords) == 1:
print(rectangle_coords[0])
# plot the rectangle after two points have been saved
if len(rectangle_coords) == 2:
print(rectangle_coords[1])
width = rectangle_coords[1][0] - rectangle_coords[0][0]
height = rectangle_coords[1][1] - rectangle_coords[0][1]
rectangle = Rectangle(rectangle_coords[0], width, height,
linewidth=1,
edgecolor="r",
facecolor="none")
ax.add_patch(rectangle)
fig.canvas.draw()
plt.connect("button_press_event", on_click)
fig.show()
Answered By - jared
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.