如何显示图片并获得鼠标点击坐标

时间:2022-11-28 20:52:00

I am wondering if it is possible in Python (Windows) to show some picture, then click with the mouse on this picture and get the coordinates of this click relative to picture edges.

我想知道在Python(Windows)中是否可以显示一些图片,然后在这张图片上单击鼠标并获得相对于图片边缘的此点击的坐标。

Thanks!

6 个解决方案

#1


31  

Yes it is possible and pretty easy once you understand tkinter, here's a quick script:

是的,一旦你理解了tkinter,这是可能的,非常简单,这是一个快速的脚本:

from Tkinter import *
from tkFileDialog import askopenfilename
import Image, ImageTk

if __name__ == "__main__":
    root = Tk()

    #setting up a tkinter canvas with scrollbars
    frame = Frame(root, bd=2, relief=SUNKEN)
    frame.grid_rowconfigure(0, weight=1)
    frame.grid_columnconfigure(0, weight=1)
    xscroll = Scrollbar(frame, orient=HORIZONTAL)
    xscroll.grid(row=1, column=0, sticky=E+W)
    yscroll = Scrollbar(frame)
    yscroll.grid(row=0, column=1, sticky=N+S)
    canvas = Canvas(frame, bd=0, xscrollcommand=xscroll.set, yscrollcommand=yscroll.set)
    canvas.grid(row=0, column=0, sticky=N+S+E+W)
    xscroll.config(command=canvas.xview)
    yscroll.config(command=canvas.yview)
    frame.pack(fill=BOTH,expand=1)

    #adding the image
    File = askopenfilename(parent=root, initialdir="C:/",title='Choose an image.')
    img = ImageTk.PhotoImage(Image.open(File))
    canvas.create_image(0,0,image=img,anchor="nw")
    canvas.config(scrollregion=canvas.bbox(ALL))

    #function to be called when mouse is clicked
    def printcoords(event):
        #outputting x and y coords to console
        print (event.x,event.y)
    #mouseclick event
    canvas.bind("<Button 1>",printcoords)

    root.mainloop()

Unedited it will print using the default window coordinate system to the console. The canvas widget makes the top left corner the 0,0 point so you may have to mess around with the printcoords function. To get the loaded picture dimension you would use canvas.bbox(ALL), and you might want to switch to using canvasx and canvasy coords instead of how it is. If you're new to tkinter; google should be able to help you finish it from here :).

未经编辑,它将使用默认窗口坐标系统打印到控制台。画布小部件使左上角为0,0点,因此您可能不得不使用printcoords功能。要获得加载的图片尺寸,您将使用canvas.bbox(ALL),并且您可能希望切换到使用canvasx和canvasy coords而不是它的方式。如果你是tkinter的新手;谷歌应该能够帮助你从这里完成它:)。

#2


6  

Here's a version I had cobbled together a while ago using wxPython and various wxPython tutorials. This prints the mouse click coordinates to a separate output window. (Uses Python 2.6.2, wxPython 2.8.10.1)

这是我前一段时间使用wxPython和各种wxPython教程拼凑在一起的版本。这会将鼠标单击坐标打印到单独的输出窗口。 (使用Python 2.6.2,wxPython 2.8.10.1)

Enter the path to your image in the filepath variable at the bottom.

在底部的filepath变量中输入图像的路径。

import wx

class MyCanvas(wx.ScrolledWindow):
    def __init__(self, parent, id = -1, size = wx.DefaultSize, filepath = None):
        wx.ScrolledWindow.__init__(self, parent, id, (0, 0), size=size, style=wx.SUNKEN_BORDER)

        self.image = wx.Image(filepath)
        self.w = self.image.GetWidth()
        self.h = self.image.GetHeight()
        self.bmp = wx.BitmapFromImage(self.image)

        self.SetVirtualSize((self.w, self.h))
        self.SetScrollRate(20,20)
        self.SetBackgroundColour(wx.Colour(0,0,0))

        self.buffer = wx.EmptyBitmap(self.w, self.h)
        dc = wx.BufferedDC(None, self.buffer)
        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
        dc.Clear()
        self.DoDrawing(dc)

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_LEFT_UP, self.OnClick)

    def OnClick(self, event):
        pos = self.CalcUnscrolledPosition(event.GetPosition())
        print '%d, %d' %(pos.x, pos.y)

    def OnPaint(self, event):
        dc = wx.BufferedPaintDC(self, self.buffer, wx.BUFFER_VIRTUAL_AREA)

    def DoDrawing(self, dc):
        dc.DrawBitmap(self.bmp, 0, 0)

class MyFrame(wx.Frame): 
    def __init__(self, parent=None, id=-1, filepath = None): 
        wx.Frame.__init__(self, parent, id, title=filepath)
        self.canvas = MyCanvas(self, -1, filepath = filepath)

        self.canvas.SetMinSize((self.canvas.w, self.canvas.h))
        self.canvas.SetMaxSize((self.canvas.w, self.canvas.h))
        self.canvas.SetBackgroundColour(wx.Colour(0, 0, 0))
        vert = wx.BoxSizer(wx.VERTICAL)
        horz = wx.BoxSizer(wx.HORIZONTAL)
        vert.Add(horz,0, wx.EXPAND,0)
        vert.Add(self.canvas,1,wx.EXPAND,0)
        self.SetSizer(vert)
        vert.Fit(self)
        self.Layout()

if __name__ == '__main__':
    app = wx.App()
    app.SetOutputWindowAttributes(title='stdout')  
    wx.InitAllImageHandlers()

    filepath = 'ENTER FILEPATH HERE'
    if filepath:
        print filepath
        myframe = MyFrame(filepath=filepath)
        myframe.Center()
        myframe.Show()
        app.MainLoop()

#3


4  

Here's a revised version of bigjim's answer. It works in python 3.4+ (didn't test anything else). I didn't bother with the PIL part since tkinter's PhotoImage can handle gif and pgm which is enough to demo this.

这是bigjim答案的修订版。它适用于python 3.4+(没有测试任何其他内容)。我没有打扰PIL部分,因为tkinter的PhotoImage可以处理gif和pgm,足以演示这个。

The lambda function handles conversion between event (window) coordinates and image coordinates.

lambda函数处理事件(窗口)坐标和图像坐标之间的转换。

I also added support for press vs release since I had a need for that particular feature.

我还添加了对新闻与发布的支持,因为我需要该特定功能。

from tkinter import *
from tkinter.filedialog import askopenfilename

event2canvas = lambda e, c: (c.canvasx(e.x), c.canvasy(e.y))

if __name__ == "__main__":
    root = Tk()

    #setting up a tkinter canvas with scrollbars
    frame = Frame(root, bd=2, relief=SUNKEN)
    frame.grid_rowconfigure(0, weight=1)
    frame.grid_columnconfigure(0, weight=1)
    xscroll = Scrollbar(frame, orient=HORIZONTAL)
    xscroll.grid(row=1, column=0, sticky=E+W)
    yscroll = Scrollbar(frame)
    yscroll.grid(row=0, column=1, sticky=N+S)
    canvas = Canvas(frame, bd=0, xscrollcommand=xscroll.set, yscrollcommand=yscroll.set)
    canvas.grid(row=0, column=0, sticky=N+S+E+W)
    xscroll.config(command=canvas.xview)
    yscroll.config(command=canvas.yview)
    frame.pack(fill=BOTH,expand=1)

    #adding the image
    File = askopenfilename(parent=root, initialdir="M:/",title='Choose an image.')
    print("opening %s" % File)
    img = PhotoImage(file=File)
    canvas.create_image(0,0,image=img,anchor="nw")
    canvas.config(scrollregion=canvas.bbox(ALL))

    #function to be called when mouse is clicked
    def printcoords(event):
        #outputting x and y coords to console
        cx, cy = event2canvas(event, canvas)
        print ("(%d, %d) / (%d, %d)" % (event.x,event.y,cx,cy))
    #mouseclick event
    canvas.bind("<ButtonPress-1>",printcoords)
    canvas.bind("<ButtonRelease-1>",printcoords)

    root.mainloop()

#4


2  

You can use Tkinter to do this and its built in to python already.

您可以使用Tkinter执行此操作并将其内置到python中。

http://www.pythonware.com/library/tkinter/introduction/

#5


1  

A good alternative to Tkinter is using QT in Python. You can achieve that with PyQT, or PySide.

Tkinter的一个很好的替代品是在Python中使用QT。您可以使用PyQT或PySide实现这一目标。

#6


-3  

Perheps it help you.

Perheps它可以帮助你。

http://jqueryui.com/demos/position/default.html

#1


31  

Yes it is possible and pretty easy once you understand tkinter, here's a quick script:

是的,一旦你理解了tkinter,这是可能的,非常简单,这是一个快速的脚本:

from Tkinter import *
from tkFileDialog import askopenfilename
import Image, ImageTk

if __name__ == "__main__":
    root = Tk()

    #setting up a tkinter canvas with scrollbars
    frame = Frame(root, bd=2, relief=SUNKEN)
    frame.grid_rowconfigure(0, weight=1)
    frame.grid_columnconfigure(0, weight=1)
    xscroll = Scrollbar(frame, orient=HORIZONTAL)
    xscroll.grid(row=1, column=0, sticky=E+W)
    yscroll = Scrollbar(frame)
    yscroll.grid(row=0, column=1, sticky=N+S)
    canvas = Canvas(frame, bd=0, xscrollcommand=xscroll.set, yscrollcommand=yscroll.set)
    canvas.grid(row=0, column=0, sticky=N+S+E+W)
    xscroll.config(command=canvas.xview)
    yscroll.config(command=canvas.yview)
    frame.pack(fill=BOTH,expand=1)

    #adding the image
    File = askopenfilename(parent=root, initialdir="C:/",title='Choose an image.')
    img = ImageTk.PhotoImage(Image.open(File))
    canvas.create_image(0,0,image=img,anchor="nw")
    canvas.config(scrollregion=canvas.bbox(ALL))

    #function to be called when mouse is clicked
    def printcoords(event):
        #outputting x and y coords to console
        print (event.x,event.y)
    #mouseclick event
    canvas.bind("<Button 1>",printcoords)

    root.mainloop()

Unedited it will print using the default window coordinate system to the console. The canvas widget makes the top left corner the 0,0 point so you may have to mess around with the printcoords function. To get the loaded picture dimension you would use canvas.bbox(ALL), and you might want to switch to using canvasx and canvasy coords instead of how it is. If you're new to tkinter; google should be able to help you finish it from here :).

未经编辑,它将使用默认窗口坐标系统打印到控制台。画布小部件使左上角为0,0点,因此您可能不得不使用printcoords功能。要获得加载的图片尺寸,您将使用canvas.bbox(ALL),并且您可能希望切换到使用canvasx和canvasy coords而不是它的方式。如果你是tkinter的新手;谷歌应该能够帮助你从这里完成它:)。

#2


6  

Here's a version I had cobbled together a while ago using wxPython and various wxPython tutorials. This prints the mouse click coordinates to a separate output window. (Uses Python 2.6.2, wxPython 2.8.10.1)

这是我前一段时间使用wxPython和各种wxPython教程拼凑在一起的版本。这会将鼠标单击坐标打印到单独的输出窗口。 (使用Python 2.6.2,wxPython 2.8.10.1)

Enter the path to your image in the filepath variable at the bottom.

在底部的filepath变量中输入图像的路径。

import wx

class MyCanvas(wx.ScrolledWindow):
    def __init__(self, parent, id = -1, size = wx.DefaultSize, filepath = None):
        wx.ScrolledWindow.__init__(self, parent, id, (0, 0), size=size, style=wx.SUNKEN_BORDER)

        self.image = wx.Image(filepath)
        self.w = self.image.GetWidth()
        self.h = self.image.GetHeight()
        self.bmp = wx.BitmapFromImage(self.image)

        self.SetVirtualSize((self.w, self.h))
        self.SetScrollRate(20,20)
        self.SetBackgroundColour(wx.Colour(0,0,0))

        self.buffer = wx.EmptyBitmap(self.w, self.h)
        dc = wx.BufferedDC(None, self.buffer)
        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
        dc.Clear()
        self.DoDrawing(dc)

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_LEFT_UP, self.OnClick)

    def OnClick(self, event):
        pos = self.CalcUnscrolledPosition(event.GetPosition())
        print '%d, %d' %(pos.x, pos.y)

    def OnPaint(self, event):
        dc = wx.BufferedPaintDC(self, self.buffer, wx.BUFFER_VIRTUAL_AREA)

    def DoDrawing(self, dc):
        dc.DrawBitmap(self.bmp, 0, 0)

class MyFrame(wx.Frame): 
    def __init__(self, parent=None, id=-1, filepath = None): 
        wx.Frame.__init__(self, parent, id, title=filepath)
        self.canvas = MyCanvas(self, -1, filepath = filepath)

        self.canvas.SetMinSize((self.canvas.w, self.canvas.h))
        self.canvas.SetMaxSize((self.canvas.w, self.canvas.h))
        self.canvas.SetBackgroundColour(wx.Colour(0, 0, 0))
        vert = wx.BoxSizer(wx.VERTICAL)
        horz = wx.BoxSizer(wx.HORIZONTAL)
        vert.Add(horz,0, wx.EXPAND,0)
        vert.Add(self.canvas,1,wx.EXPAND,0)
        self.SetSizer(vert)
        vert.Fit(self)
        self.Layout()

if __name__ == '__main__':
    app = wx.App()
    app.SetOutputWindowAttributes(title='stdout')  
    wx.InitAllImageHandlers()

    filepath = 'ENTER FILEPATH HERE'
    if filepath:
        print filepath
        myframe = MyFrame(filepath=filepath)
        myframe.Center()
        myframe.Show()
        app.MainLoop()

#3


4  

Here's a revised version of bigjim's answer. It works in python 3.4+ (didn't test anything else). I didn't bother with the PIL part since tkinter's PhotoImage can handle gif and pgm which is enough to demo this.

这是bigjim答案的修订版。它适用于python 3.4+(没有测试任何其他内容)。我没有打扰PIL部分,因为tkinter的PhotoImage可以处理gif和pgm,足以演示这个。

The lambda function handles conversion between event (window) coordinates and image coordinates.

lambda函数处理事件(窗口)坐标和图像坐标之间的转换。

I also added support for press vs release since I had a need for that particular feature.

我还添加了对新闻与发布的支持,因为我需要该特定功能。

from tkinter import *
from tkinter.filedialog import askopenfilename

event2canvas = lambda e, c: (c.canvasx(e.x), c.canvasy(e.y))

if __name__ == "__main__":
    root = Tk()

    #setting up a tkinter canvas with scrollbars
    frame = Frame(root, bd=2, relief=SUNKEN)
    frame.grid_rowconfigure(0, weight=1)
    frame.grid_columnconfigure(0, weight=1)
    xscroll = Scrollbar(frame, orient=HORIZONTAL)
    xscroll.grid(row=1, column=0, sticky=E+W)
    yscroll = Scrollbar(frame)
    yscroll.grid(row=0, column=1, sticky=N+S)
    canvas = Canvas(frame, bd=0, xscrollcommand=xscroll.set, yscrollcommand=yscroll.set)
    canvas.grid(row=0, column=0, sticky=N+S+E+W)
    xscroll.config(command=canvas.xview)
    yscroll.config(command=canvas.yview)
    frame.pack(fill=BOTH,expand=1)

    #adding the image
    File = askopenfilename(parent=root, initialdir="M:/",title='Choose an image.')
    print("opening %s" % File)
    img = PhotoImage(file=File)
    canvas.create_image(0,0,image=img,anchor="nw")
    canvas.config(scrollregion=canvas.bbox(ALL))

    #function to be called when mouse is clicked
    def printcoords(event):
        #outputting x and y coords to console
        cx, cy = event2canvas(event, canvas)
        print ("(%d, %d) / (%d, %d)" % (event.x,event.y,cx,cy))
    #mouseclick event
    canvas.bind("<ButtonPress-1>",printcoords)
    canvas.bind("<ButtonRelease-1>",printcoords)

    root.mainloop()

#4


2  

You can use Tkinter to do this and its built in to python already.

您可以使用Tkinter执行此操作并将其内置到python中。

http://www.pythonware.com/library/tkinter/introduction/

#5


1  

A good alternative to Tkinter is using QT in Python. You can achieve that with PyQT, or PySide.

Tkinter的一个很好的替代品是在Python中使用QT。您可以使用PyQT或PySide实现这一目标。

#6


-3  

Perheps it help you.

Perheps它可以帮助你。

http://jqueryui.com/demos/position/default.html