Python lf.width=self.canvas.cget('width') self.height=self.canvas.cget('height')) #矩形选择之外区域的选项。 选择_opts1=self。选择_opts1.copy()#避免修改传递的参数。 选择_opts1.update(state=tk.HIDDEN)#初始隐藏。 #矩形选择内区域的单独选项。 选择_opts2=dict(破折号=(2,2),填充=“”,轮廓=“”,白色,状态=tk.HIDDEN) #内外矩形的初始极值。 imin_x,imin_y,imax_x,imax_y=0,0,1,1 omin_x,omin_y,omax_x,omax_y=0,0,self.width,self.height self.rects=( #区域*外部*选择(内部)矩形。 self.canvas.create_矩形(omin_x,omin_y,omax_x,imin_y,**选择选项1), 创建矩形(omin_x,imin_y,imin_x,imax_y,**选择选项1), self.canvas.create_矩形(imax_x,imin_y,omax_x,imax_y,**选择_选项1), self.canvas.create_矩形(omin_x,imax_y,omax_x,omax_y,**选择选项1), #内部矩形。 self.canvas.create_矩形(imin_x,imin_y,imax_x,imax_y,**选择_选项2) ) def更新(自我、开始、结束): #内外矩形的当前极值。 imin_x,imin_y,imax_x,imax_y=self.\u获取坐标(开始,结束) omin_x,omin_y,omax_x,omax_y=0,0,self.width,self.height #根据这些极值更新所有矩形的坐标。 self.canvas.coords(self.rects[0],omin_x,omin_y,omax_x,imin_y), self.canvas.coords(self.rects[1],omin_x,imin_y,imin_x,imax_y), self.canvas.coords(self.rects[2],imax_x,imin_y,omax_x,imax_y), self.canvas.coords(self.rects[3],omin_x,imax_y,omax_x,omax_y), self.canvas.coords(self.rects[4],imin_x,imin_y,imax_x,imax_y), 对于self.rects中的rect:#确保所有内容现在都可见。 self.canvas.itemconfigure(rect,state=tk.NORMAL) 定义获取坐标(自、开始、结束): “”“确定由起点和终点定义的多边形的坐标” 端点矩形区域的对角线之一。 """ 返回(最小值((开始[0],结束[0])),最小值((开始[1],结束[1])), 最大值((开始[0],结束[0])),最大值((开始[1],结束[1])) def隐藏(自我): 对于self.rects中的rect: self.canvas.itemconfigure(rect,state=tk.HIDDEN) 类应用程序(tk.Frame): #默认选择对象选项。 选择_OPTS=dict(破折号=(2,2),点画为灰色,填充为红色, 大纲=“”) 定义初始化(自、父、*args、**kwargs): super() path=“Books.jpg” img=ImageTk.PhotoImage(Image.open(path)) self.canvas=tk.canvas(根,宽度=img.width(),高度=img.height(), borderwidth=0,highlightthickness=0) self.canvas.pack(expand=True) self.canvas.create_image(0,0,image=img,anchor=tk.NW) self.canvas.img=img#保留引用。 #创建选择对象以显示当前选择边界。 self.selection\u obj=SelectionObject(self.canvas,self.SELECT\u OPTS) #回调函数来更新给定其对角线的两点。 拖动时的def(开始、结束、**kwarg):#必须接受这些参数。 自选择对象更新(开始、结束) #创建使用该功能的鼠标位置跟踪器。 self.posn_tracker=MousePositionTracker(self.canvas) self.posn_tracker.autodraw(命令=拖动)#启用回调。 如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu': 宽度,高度=900900 背景=‘灰色’ 标题='图像裁剪器' root=tk.tk() root.title(title) 几何体(“%sx%s%”(宽度、高度)) root.configure(后台=后台) 应用程序=应用程序(根,背景=背景) app.pack(side=tk.TOP,fill=tk.BOTH,expand=tk.TRUE) app.mainloop()

Python lf.width=self.canvas.cget('width') self.height=self.canvas.cget('height')) #矩形选择之外区域的选项。 选择_opts1=self。选择_opts1.copy()#避免修改传递的参数。 选择_opts1.update(state=tk.HIDDEN)#初始隐藏。 #矩形选择内区域的单独选项。 选择_opts2=dict(破折号=(2,2),填充=“”,轮廓=“”,白色,状态=tk.HIDDEN) #内外矩形的初始极值。 imin_x,imin_y,imax_x,imax_y=0,0,1,1 omin_x,omin_y,omax_x,omax_y=0,0,self.width,self.height self.rects=( #区域*外部*选择(内部)矩形。 self.canvas.create_矩形(omin_x,omin_y,omax_x,imin_y,**选择选项1), 创建矩形(omin_x,imin_y,imin_x,imax_y,**选择选项1), self.canvas.create_矩形(imax_x,imin_y,omax_x,imax_y,**选择_选项1), self.canvas.create_矩形(omin_x,imax_y,omax_x,omax_y,**选择选项1), #内部矩形。 self.canvas.create_矩形(imin_x,imin_y,imax_x,imax_y,**选择_选项2) ) def更新(自我、开始、结束): #内外矩形的当前极值。 imin_x,imin_y,imax_x,imax_y=self.\u获取坐标(开始,结束) omin_x,omin_y,omax_x,omax_y=0,0,self.width,self.height #根据这些极值更新所有矩形的坐标。 self.canvas.coords(self.rects[0],omin_x,omin_y,omax_x,imin_y), self.canvas.coords(self.rects[1],omin_x,imin_y,imin_x,imax_y), self.canvas.coords(self.rects[2],imax_x,imin_y,omax_x,imax_y), self.canvas.coords(self.rects[3],omin_x,imax_y,omax_x,omax_y), self.canvas.coords(self.rects[4],imin_x,imin_y,imax_x,imax_y), 对于self.rects中的rect:#确保所有内容现在都可见。 self.canvas.itemconfigure(rect,state=tk.NORMAL) 定义获取坐标(自、开始、结束): “”“确定由起点和终点定义的多边形的坐标” 端点矩形区域的对角线之一。 """ 返回(最小值((开始[0],结束[0])),最小值((开始[1],结束[1])), 最大值((开始[0],结束[0])),最大值((开始[1],结束[1])) def隐藏(自我): 对于self.rects中的rect: self.canvas.itemconfigure(rect,state=tk.HIDDEN) 类应用程序(tk.Frame): #默认选择对象选项。 选择_OPTS=dict(破折号=(2,2),点画为灰色,填充为红色, 大纲=“”) 定义初始化(自、父、*args、**kwargs): super() path=“Books.jpg” img=ImageTk.PhotoImage(Image.open(path)) self.canvas=tk.canvas(根,宽度=img.width(),高度=img.height(), borderwidth=0,highlightthickness=0) self.canvas.pack(expand=True) self.canvas.create_image(0,0,image=img,anchor=tk.NW) self.canvas.img=img#保留引用。 #创建选择对象以显示当前选择边界。 self.selection\u obj=SelectionObject(self.canvas,self.SELECT\u OPTS) #回调函数来更新给定其对角线的两点。 拖动时的def(开始、结束、**kwarg):#必须接受这些参数。 自选择对象更新(开始、结束) #创建使用该功能的鼠标位置跟踪器。 self.posn_tracker=MousePositionTracker(self.canvas) self.posn_tracker.autodraw(命令=拖动)#启用回调。 如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu': 宽度,高度=900900 背景=‘灰色’ 标题='图像裁剪器' root=tk.tk() root.title(title) 几何体(“%sx%s%”(宽度、高度)) root.configure(后台=后台) 应用程序=应用程序(根,背景=背景) app.pack(side=tk.TOP,fill=tk.BOTH,expand=tk.TRUE) app.mainloop(),python,python-3.x,tkinter,python-imaging-library,Python,Python 3.x,Tkinter,Python Imaging Library,下面的一些图片显示了它的作用: 更新………非常感谢!我将如何更改它,使画布大小固定,图像大小也固定,而不考虑其实际尺寸(基本上,缩放图像以适应画布大小)。此外,是否有任何方法可以对选择矩形外的图像区域进行着色(如添加红色,或至少默认的蓝色选择着色)?还有——这不是离题——但既然您似乎精通Python,那么您可以特别推荐任何书籍/教程(我以前从未用Python编写过代码,我想学习它)。再次感谢你!InfiniteLoop:我在评论中回答的后续问题太多了,但我会给你一些提示。请参见wrt调整图像大

下面的一些图片显示了它的作用:


更新………非常感谢!我将如何更改它,使画布大小固定,图像大小也固定,而不考虑其实际尺寸(基本上,缩放图像以适应画布大小)。此外,是否有任何方法可以对选择矩形外的图像区域进行着色(如添加红色,或至少默认的蓝色选择着色)?还有——这不是离题——但既然您似乎精通Python,那么您可以特别推荐任何书籍/教程(我以前从未用Python编写过代码,我想学习它)。再次感谢你!InfiniteLoop:我在评论中回答的后续问题太多了,但我会给你一些提示。请参见wrt调整图像大小以适应。如果调整图像大小,则需要先“取消调整”选择矩形中的坐标,然后再使用这些坐标裁剪原始图像。我不确定用什么最好的方法来遮盖图像的各个部分。PIL可以做这样的事情,但速度可能太慢了……Python和tkinter都有很多在线教程。我个人使用作为tkinter参考,尽管它有点过时,并且没有涵盖模块的几个方面。然而,它组织得相当好。典型的tkinter参考文献由其作者Fredrik Lundh撰写。还有。我还强烈建议你阅读(并开始遵循)接受答案中的建议,以及更新:这里有一个工作链接,我在前面的评论中提到过。
import tkinter as tk
from PIL import ImageTk, Image

#This creates the main window of an application
window = tk.Tk()
window.title("Join")
window.geometry("900x900")
window.configure(background='grey')

path = "Book.jpg"

#Creates a Tkinter-compatible photo image, which can be used everywhere Tkinter expects an image object.
img = ImageTk.PhotoImage(Image.open(path))

#The Label widget is a standard Tkinter widget used to display a text or image on the screen.
panel = tk.Label(window, image = img)

#The Pack geometry manager packs widgets in rows or columns.
panel.pack(side = "bottom", fill = "both", expand = "yes")

#Start the GUI
window.mainloop()
import tkinter as tk
from PIL import Image, ImageTk


class MousePositionTracker(tk.Frame):
    """ Tkinter Canvas mouse position widget. """

    def __init__(self, canvas):
        self.canvas = canvas
        self.canv_width = self.canvas.cget('width')
        self.canv_height = self.canvas.cget('height')
        self.reset()

        # Create canvas cross-hair lines.
        xhair_opts = dict(dash=(3, 2), fill='white', state=tk.HIDDEN)
        self.lines = (self.canvas.create_line(0, 0, 0, self.canv_height, **xhair_opts),
                      self.canvas.create_line(0, 0, self.canv_width,  0, **xhair_opts))

    def cur_selection(self):
        return (self.start, self.end)

    def begin(self, event):
        self.hide()
        self.start = (event.x, event.y)  # Remember position (no drawing).

    def update(self, event):
        self.end = (event.x, event.y)
        self._update(event)
        self._command(self.start, (event.x, event.y))  # User callback.

    def _update(self, event):
        # Update cross-hair lines.
        self.canvas.coords(self.lines[0], event.x, 0, event.x, self.canv_height)
        self.canvas.coords(self.lines[1], 0, event.y, self.canv_width, event.y)
        self.show()

    def reset(self):
        self.start = self.end = None

    def hide(self):
        self.canvas.itemconfigure(self.lines[0], state=tk.HIDDEN)
        self.canvas.itemconfigure(self.lines[1], state=tk.HIDDEN)

    def show(self):
        self.canvas.itemconfigure(self.lines[0], state=tk.NORMAL)
        self.canvas.itemconfigure(self.lines[1], state=tk.NORMAL)

    def autodraw(self, command=lambda *args: None):
        """Setup automatic drawing; supports command option"""
        self.reset()
        self._command = command
        self.canvas.bind("<Button-1>", self.begin)
        self.canvas.bind("<B1-Motion>", self.update)
        self.canvas.bind("<ButtonRelease-1>", self.quit)

    def quit(self, event):
        self.hide()  # Hide cross-hairs.
        self.reset()


class SelectionObject:
    """ Widget to display a rectangular area on given canvas defined by two points
        representing its diagonal.
    """
    def __init__(self, canvas, select_opts):
        # Create attributes needed to display selection.
        self.canvas = canvas
        self.select_opts1 = select_opts
        self.width = self.canvas.cget('width')
        self.height = self.canvas.cget('height')

        # Options for areas outside rectanglar selection.
        select_opts1 = self.select_opts1.copy()  # Avoid modifying passed argument.
        select_opts1.update(state=tk.HIDDEN)  # Hide initially.
        # Separate options for area inside rectanglar selection.
        select_opts2 = dict(dash=(2, 2), fill='', outline='white', state=tk.HIDDEN)

        # Initial extrema of inner and outer rectangles.
        imin_x, imin_y,  imax_x, imax_y = 0, 0,  1, 1
        omin_x, omin_y,  omax_x, omax_y = 0, 0,  self.width, self.height

        self.rects = (
            # Area *outside* selection (inner) rectangle.
            self.canvas.create_rectangle(omin_x, omin_y,  omax_x, imin_y, **select_opts1),
            self.canvas.create_rectangle(omin_x, imin_y,  imin_x, imax_y, **select_opts1),
            self.canvas.create_rectangle(imax_x, imin_y,  omax_x, imax_y, **select_opts1),
            self.canvas.create_rectangle(omin_x, imax_y,  omax_x, omax_y, **select_opts1),
            # Inner rectangle.
            self.canvas.create_rectangle(imin_x, imin_y,  imax_x, imax_y, **select_opts2)
        )

    def update(self, start, end):
        # Current extrema of inner and outer rectangles.
        imin_x, imin_y,  imax_x, imax_y = self._get_coords(start, end)
        omin_x, omin_y,  omax_x, omax_y = 0, 0,  self.width, self.height

        # Update coords of all rectangles based on these extrema.
        self.canvas.coords(self.rects[0], omin_x, omin_y,  omax_x, imin_y),
        self.canvas.coords(self.rects[1], omin_x, imin_y,  imin_x, imax_y),
        self.canvas.coords(self.rects[2], imax_x, imin_y,  omax_x, imax_y),
        self.canvas.coords(self.rects[3], omin_x, imax_y,  omax_x, omax_y),
        self.canvas.coords(self.rects[4], imin_x, imin_y,  imax_x, imax_y),

        for rect in self.rects:  # Make sure all are now visible.
            self.canvas.itemconfigure(rect, state=tk.NORMAL)

    def _get_coords(self, start, end):
        """ Determine coords of a polygon defined by the start and
            end points one of the diagonals of a rectangular area.
        """
        return (min((start[0], end[0])), min((start[1], end[1])),
                max((start[0], end[0])), max((start[1], end[1])))

    def hide(self):
        for rect in self.rects:
            self.canvas.itemconfigure(rect, state=tk.HIDDEN)


class Application(tk.Frame):

    # Default selection object options.
    SELECT_OPTS = dict(dash=(2, 2), stipple='gray25', fill='red',
                          outline='')

    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)

        path = "Books.jpg"
        img = ImageTk.PhotoImage(Image.open(path))
        self.canvas = tk.Canvas(root, width=img.width(), height=img.height(),
                                borderwidth=0, highlightthickness=0)
        self.canvas.pack(expand=True)

        self.canvas.create_image(0, 0, image=img, anchor=tk.NW)
        self.canvas.img = img  # Keep reference.

        # Create selection object to show current selection boundaries.
        self.selection_obj = SelectionObject(self.canvas, self.SELECT_OPTS)

        # Callback function to update it given two points of its diagonal.
        def on_drag(start, end, **kwarg):  # Must accept these arguments.
            self.selection_obj.update(start, end)

        # Create mouse position tracker that uses the function.
        self.posn_tracker = MousePositionTracker(self.canvas)
        self.posn_tracker.autodraw(command=on_drag)  # Enable callbacks.


if __name__ == '__main__':

    WIDTH, HEIGHT = 900, 900
    BACKGROUND = 'grey'
    TITLE = 'Image Cropper'

    root = tk.Tk()
    root.title(TITLE)
    root.geometry('%sx%s' % (WIDTH, HEIGHT))
    root.configure(background=BACKGROUND)

    app = Application(root, background=BACKGROUND)
    app.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.TRUE)
    app.mainloop()