I have an image in a canvas. The user can draw a rectangle on this image and the image becomes cropped and resized. Here is my code:
self._root = tk.Tk()
self._rect = None
image_cv2 = cv2.imread(path_image)
self._root.minsize(height=image_cv2.shape[0], width=image_cv2.shape[1] + 150)
self._root.title("Image")
image = cv2.cvtColor(image_cv2, cv2.COLOR_BGR2RGB)
image2 = Image.fromarray(image)
image = ImageTk.PhotoImage(image2)
canvas_2 = tk.Canvas( self._root, height=image_cv2.shape[0], width=image_cv2.shape[1])
canvas_2.grid(row=0, column=1)
canvas_2.image = image
self._image_can2 = canvas_2.create_image(0, 0, anchor='nw', image=image)
canvas_2.bind("<Button-1>", lambda event: self.__on_button_press__(event, canvas_2))
canvas_2.bind("<B1-Motion>", lambda event: self.__on_move_press__(event, canvas_2))
canvas_2.bind("<ButtonRelease-1>", lambda event: self.__on_button_release__(event, canvas_2, image2))
def __on_button_press__(self, event, canvas_img):
# save mouse drag start position and display a _rectangle
if self._rect is not None:
canvas_img.delete(self._rect)
self._start_x = event.x
self._start_y = event.y
self._rect = canvas_img.create_rectangle(self._start_x, self._start_y, self._start_x + 1, self._start_y + 1, fill="", outline="green", width=5)
def __on_move_press__(self, event, canvas_img):
# expand rectangle as you drag the mouse
curX = event.x
curY = event.y
canvas_img.coords(self._rect, self._start_x, self._start_y, curX, curY)
return True
def __on_button_release__(self, event, canvas_img, image):
# save mouse drag ststopart position and display a rectangle
if self._rect is not None:
if self._start_x > event.x or self._start_y > event.y:
canvas_img.delete(self._rect)
messagebox.showwarning('Error', 'You have to draw the rectangle from the top-left to the bottom-right')
self._stop_x = event.x
self._stop_y = event.y
self.__cropped_img__(canvas_img, image)
return True
def __cropped_img__(self, canvas_img, image):
# cropped the image according to the drawn rectangle
canvas_img.delete(self._rect)
image = image.crop([self._start_x, self._start_y, self._stop_x, self._stop_y]).resize((500, 500))
image = ImageTk.PhotoImage(image)
canvas_img.itemconfig(self._image_can2, image=image)
return True
The rectangle is drawn, but the itemconfig doesn't work: the image disappears.
When at the end of the function cropped_img instead of return True
, I put something wrong like return true
, I got an error :
Exception in Tkinter callback
[...]
NameError: name 'true' is not defined
BUT the image is cropped and resized. I don't understand why it doesn't work when there is no error.
According to this link: Why does Tkinter image not show up if created in a function?, I've tried to put
global image
at the beginning of my code, I got the same error.