简体   繁体   English

Tkinter window 中 cv2 图像上的鼠标事件

[英]Mouse events on cv2 images in Tkinter window

I'm working on a program that allows you to free-form crop an image and simultaneously show you the resultant image.我正在开发一个程序,该程序允许您自由裁剪图像并同时向您显示生成的图像。 The following code achieves this.下面的代码实现了这一点。

import numpy as np
import cv2

def crop(pts):
    global res
    pts = np.array(pts)

    mask = np.zeros((height, width), dtype=np.uint8)
    cv2.fillPoly(mask, [pts], (255))

    res = cv2.bitwise_and(img,img,mask = mask)

    rect = cv2.boundingRect(pts) # returns (x,y,w,h) of the rect
    cropped = res[rect[1]: rect[1] + rect[3], rect[0]: rect[0] + rect[2]]

    cv2.imshow('res', res)

def mouse_callback(event, x, y, flags, params):

    global selecting, pts, img

    if event == cv2.EVENT_LBUTTONDOWN:
        selecting = True
    elif event == cv2.EVENT_MOUSEMOVE:
        if selecting == True:
            pts.append((x, y))
            crop(pts)
            print((x,y))
    elif event == cv2.EVENT_LBUTTONUP:
        selecting = False

res = None

selecting = False
pts = []
img = cv2.imread("girl.png", -1)
height = img.shape[0]
width = img.shape[1]

cv2.namedWindow('image')
cv2.setMouseCallback('image', mouse_callback)

cv2.imshow('image', img)
cv2.waitKey(0)

cv2.imwrite("res.png", res)

My challenge is to encapsulate the above code into an interface as follows:我的挑战是将上述代码封装到一个接口中,如下所示:

在此处输入图像描述

So far I have followed a tutorial to achieve something similar:到目前为止,我已经按照教程来实现类似的目标:

# import the necessary packages
from tkinter import *
from PIL import Image
from PIL import ImageTk
from tkinter import filedialog as tkf
import cv2

def select_image():
    # grab a reference to the image panels
    global panelA, panelB
    # open a file chooser dialog and allow the user to select an input
    # image
    path = tkf.askopenfilename()

    # ensure a file path was selected
    if len(path) > 0:
        # load the image from disk, convert it to grayscale, and detect
        # edges in it
        image = cv2.imread(path)
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        edged = cv2.Canny(gray, 50, 100)
        # OpenCV represents images in BGR order; however PIL represents
        # images in RGB order, so we need to swap the channels
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        # convert the images to PIL format...
        image = Image.fromarray(image)
        edged = Image.fromarray(edged)
        # ...and then to ImageTk format
        image = ImageTk.PhotoImage(image)
        edged = ImageTk.PhotoImage(edged)

        # if the panels are None, initialize them
        if panelA is None or panelB is None:
            # the first panel will store our original image
            panelA = Label(image=image)
            panelA.image = image
            panelA.pack(side="left", padx=10, pady=10)
            # while the second panel will store the edge map
            panelB = Label(image=edged)
            panelB.image = edged
            panelB.pack(side="right", padx=10, pady=10)
        # otherwise, update the image panels
        else:
            # update the pannels
            panelA.configure(image=image)
            panelB.configure(image=edged)
            panelA.image = image
            panelB.image = edged

# initialize the window toolkit along with the two image panels
root = Tk()
panelA = None
panelB = None
# create a button, then when pressed, will trigger a file chooser
# dialog and allow the user to select an input image; then add the
# button the GUI
btn = Button(root, text="Select an image", command=select_image)
btn.pack(side="bottom", fill="both", expand="yes", padx="10", pady="10")
# kick off the GUI
root.mainloop()

What I have not managed to accomplish is implement the mouse event in tkinter, as the function takes in a window name - but I only want it to get applied to the image.我没有设法完成的是在 tkinter 中实现鼠标事件,因为 function 采用 window 名称 - 但我只希望它应用于图像。 How can I achieve this?我怎样才能做到这一点?

Instead of bind your command to your image, bind it to the tk.Label that contains the image:不要将命令绑定到图像,而是将其绑定到包含图像的 tk.Label:

import tkinter as tk
from PIL import Image
from PIL import ImageTk

root = tk.Tk()
ima = Image.open('test.png')
imag = ImageTk.PhotoImage(ima)
lab = tk.Label(root, image=imag)
lab.pack()
lab.bind('<Button-1>', *function)
root.mainloop()

Explaination解释

Tkinter provides a powerful mechanism to let you deal with events yourself. Tkinter 提供了强大的机制让您自己处理事件。 For each widget , you can bind Python functions and methods to events.对于每个小部件,您可以Python 函数和方法绑定到事件。

(...) (...)

Events are given as strings, using a special event syntax :事件以字符串形式给出,使用特殊的事件语法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM