python - Tkinter 图像裁剪工具:使用多个矩形裁剪图像,添加滚动条会使矩形中的位置错误
问题描述
我只是 Python 和 Tkinter 的初学者,我正在尝试编写一个应用程序来裁剪图像中的多个区域并将它们保存为单独的图像,我可以通过绘制多个矩形来裁剪图像,但是在添加滚动条之后使用鼠标指针绘制矩形时鼠标位置出错,由于滚动效果,它被放置在不远处。
我也在尝试添加放大和缩小功能,请您建议我如何实现这一点。
import os
import tkinter as tk
import tkinter.filedialog as filedialog
from PIL import Image, ImageTk, ImageGrab
WIDTH, HEIGHT = 1200, 800
topx, topy, botx, boty = 0, 0, 0, 0
rect_id = None
path = "test.jpg"
rect_list = list()
rect_main_data = list()
ImageFilePath = ""
ImgOpen = None
prodDir = ""
ImageFound = False
window = tk.Tk()
window.title("Image Croping Tool")
window.geometry('%sx%s' % (WIDTH, HEIGHT))
window.configure(background='grey')
ImageFrame = tk.Frame(window, width=WIDTH,height=HEIGHT - 70, borderwidth=1)
ImageFrame.pack(expand=True, fill=tk.BOTH)
ImageFrame.place(x=0,y=71)
rawImage = Image.open("test.jpg")
img = ImageTk.PhotoImage(rawImage)
canvasWidth, canvasHeight = rawImage.size
canvas = tk.Canvas(ImageFrame, width=canvasWidth, height=canvasHeight - 70, borderwidth=2, highlightthickness=2,scrollregion=(0,0,canvasWidth,canvasHeight))
def get_mouse_posn(event):
global topy, topx
topx, topy = event.x, event.y
def update_sel_rect(event):
global rect_id
global topy, topx, botx, boty
botx, boty = event.x, event.y
canvas.coords(rect_id, topx, topy, botx, boty) # Update selection rect.
def draw_rect(self):
draw_data = canvas.create_rectangle(topx,topy,botx,boty,outline="green", fill="")
rect_list.append((topx,topy,botx,boty))
rect_main_data.append(draw_data)
def GetImageFilePath():
global ImageFilePath
global ImageFound
global img
global canvas
global ImageFrame
test = False
if (ImageFound):
canvas.destroy()
canvas = tk.Canvas(ImageFrame, width=canvasWidth, height=canvasHeight - 70, borderwidth=2, highlightthickness=2,scrollregion=(0,0,canvasWidth,canvasHeight))
ImageFilePath = filedialog.askopenfilename()
ImgOpen = Image.open(ImageFilePath)
if len(ImageFilePath) > 0:
test = True
img = ImageTk.PhotoImage(Image.open(ImageFilePath))
ImageFound = True
canvas.create_image(0, 0, image=img, anchor=tk.NW)
canvas.pack(side=tk.LEFT,expand=False,fill=tk.BOTH)
rect_id = canvas.create_rectangle(topx, topy, topx, topy, dash=(2,2), fill='', outline='red')
canvas.bind('<Button-1>', get_mouse_posn)
canvas.bind('<B1-Motion>', update_sel_rect)
canvas.bind('<ButtonRelease-1>',draw_rect)
canvas.update()
if (test):
window.mainloop()
def testPrint():
print("Hello")
def cropImages():
im = Image.open(ImageFilePath)
mainDir = os.path.dirname(ImageFilePath)
global prodDir
prodDir = os.path.splitext(ImageFilePath)[0]
if not os.path.exists(prodDir):
os.makedirs(prodDir)
i=0
for po in rect_list:
i= i +1
img1 = im.crop((po[0], po[1], po[2], po[3]))
print(os.path.join(prodDir,"img" + str(i) + ".jpg"))
img1.save(os.path.join(prodDir,"img" + str(i) + ".jpg"))
tk.messagebox.showinfo("Completed ", "Croped all the images")
def clearRectangles():
global rect_main_data
global rect_list
if (len(rect_main_data) > 0):
for rect in rect_main_data:
canvas.delete(rect)
rect_main_data.clear()
rect_list.clear()
canvas.pack()
window.mainloop()
TitleBar = tk.LabelFrame(window,width=2000,height=70, borderwidth=1)
TitleBar.pack(expand = 'yes', fill = 'both')
TitleBar.place(x=0,y=0)
tiletest = tk.Label(window,text="Image Cropping Tool", anchor=tk.NE)
tiletest.pack()
openFile = tk.Button(TitleBar,text = "Open Image",command = GetImageFilePath,width=10, height=2)
openFile.place(x=10,y=10)
cropImages = tk.Button(TitleBar,text = "Crop Images",command = cropImages,width=10, height=2)
cropImages.place(x=140,y=10)
clearImages = tk.Button(TitleBar,text = "Clear",command = clearRectangles,width=10, height=2)
clearImages.place(x=270,y=10)
if (ImageFound):
canvas.delete(img)
canvas.update()
canvas.create_image(0, 0, image=img, anchor=tk.NW)
rect_id = canvas.create_rectangle(topx, topy, topx, topy, dash=(2,2), fill='', outline='red')
canvas.bind('<Button-1>', get_mouse_posn)
canvas.bind('<B1-Motion>', update_sel_rect)
canvas.bind('<ButtonRelease-1>',draw_rect)
hbar=tk.Scrollbar(ImageFrame,orient=tk.HORIZONTAL)
hbar.pack(side=tk.BOTTOM,fill=tk.X)
hbar.config(command=canvas.xview)
vbar=tk.Scrollbar(ImageFrame,orient=tk.VERTICAL)
vbar.pack(side=tk.RIGHT,fill=tk.Y)
vbar.config(command=canvas.yview)
canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
canvas.pack(side=tk.LEFT,expand=False,fill=tk.BOTH)
window.mainloop()
解决方案
因为event.x
和event.y
总是相对于画布的左上角。如果画布没有滚动,它们与真实坐标匹配。但不是在画布滚动时。
但是,您可以使用canvas.canvasx()
和canvas.canvasy()
函数将鼠标位置转换为画布中的真实坐标:
def get_mouse_posn(event):
global topy, topx
topx, topy = canvas.canvasx(event.x), canvas.canvasy(event.y) # convert to real canvas coordinates
def update_sel_rect(event):
global botx, boty
botx, boty = canvas.canvasx(event.x), canvas.canvasy(event.y) # convert to real canvas coordinates
canvas.coords(rect_id, topx, topy, botx, boty) # Update selection rect.
推荐阅读
- mongodb - MongoDB - 无法在 Mongo Shell 中获取对象的键值
- vba - 文本替换后添加文件打开和文件另存为对话框
- reactjs - 如何使用反应将模态对话框置于全屏模式?
- aerospike - 使用 vagrant 安装的 aerospike 无法正常工作
- sorting - 'NoneType' 对象在 python 中不可下标
- java - 如何使用 java 在 PostgreSQL 中使用事务类型快照
- mysql - 我想知道是否有人知道如何找到最小值和最大值并找到它们之间的时间范围?
- java - UnsatisfiedLinkError libcrypto.so.1.0.0
- javascript - TypeError:无法读取未定义的属性“年份”
- c - 通过循环将数据复制到整数指针数组?