From b70a3300a3f0b89535baa965caba8672f008dc19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B3=E5=BF=97=E8=BF=9C?= <14347000+guan-zhiyuan2@user.noreply.gitee.com> Date: Sat, 29 Jun 2024 05:00:26 +0000 Subject: [PATCH] update app.py. gail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 关志远 <14347000+guan-zhiyuan2@user.noreply.gitee.com> --- app.py | 62 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/app.py b/app.py index 68a8a9d..86dbcdb 100644 --- a/app.py +++ b/app.py @@ -19,33 +19,29 @@ class DocScannerApp: self.corners = None # 初始化识别出文档的四个角落为 None self.dragging_idx = -1 # 这个变量用来标记正在被拖动的角落,设置为-1表示现在没有 self.img = None # 初始化图片为 None - + self.root = tk.Tk() # 创建一个 Tkinter 窗口 - # 在窗口中创建一个宽600,高400画布 + # 在窗口中创建一个画布 # 用于把图片和裁剪框绘制上去 - self.canvas = #TODO - # 将画布添加到窗口中 - #TODO - + self.canvas = tk.Canvas(self.root, width=600, height=400) + self.canvas.pack() # 将画布添加到窗口中 # 为画布绑定鼠标事件 - # 鼠标左键按下,释放和移动事件都绑定到方法:mouse_callback 上 - # 注意绑定的事是实例方法,不要忘了self - #TODO # 鼠标按下事件 - #TODO # 鼠标释放事件 - #TODO # 鼠标移动事件 + self.canvas.bind("", self.mouse_callback) # 鼠标按下事件 + self.canvas.bind("", self.mouse_callback) # 鼠标释放事件 + self.canvas.bind("", self.mouse_callback) # 鼠标移动事件 # 创建一个 "Select Image" 按钮,点击时执行 self.select_image 函数 - btn_select = tk.Button(self.root, text="Select Image", command=self.select_image) + btn_select = tk.Button(self.root, text="Select Image", command=self.select_image) btn_select.pack(side=tk.LEFT) # 将按钮添加到窗口左侧 - self.show_mouse_move = #TODO # 创建一个 BooleanVar 实例来保存复选框的状态 - # 创建一个复选框,文本为 "Show Mouse Move",把状态与 self.show_mouse_move 绑定 - chk_show_mouse_move = #TODO + self.show_mouse_move = tk.BooleanVar() # 创建一个 BooleanVar 实例来保存复选框的状态 + # 创建一个复选框,文本为 "Show Mouse Move" + chk_show_mouse_move = tk.Checkbutton(self.root, text="Show Mouse Move", variable=self.show_mouse_move) chk_show_mouse_move.pack(side=tk.LEFT) # 将复选框添加到窗口左侧 # 创建一个 "Crop" 按钮,点击时执行 self.crop 函数 - btn_crop = tk.Button(self.root, text="Crop", command=self.crop) + btn_crop = tk.Button(self.root, text="Crop", command=self.crop) btn_crop.pack(side=tk.RIGHT) # 将按钮添加到窗口右侧 def select_image(self): @@ -54,32 +50,32 @@ class DocScannerApp: self.img, self.corners = self.doc_scanner.load_image(file_path) # 加载图片和角落 img_height, img_width, _ = self.img.shape # 获取图片的高度和宽度 if img_height > 600 or img_width > 800: # 如果图片的高度大于600或宽度大于800 - - scale = #TODO # 计算缩放比例 - self.img = #TODO # 缩放图片 - self.corners = #TODO # 缩放角落 - img_height, img_width, _ = self.img.shape # 更新图片的高度和宽度 - + scale = min(600 / img_height, 800 / img_width) # 计算缩放比例 + self.img = cv.resize(self.img, (int(img_width * scale), int(img_height * scale))) # 缩放图片 + self.corners = self.corners * scale # 缩放角落 + img_height, img_width, _ = self.img.shape # 更新图片的高度和宽度 self.canvas.config(width=img_width, height=img_height) # 调整画布的大小以适应图片 self.canvas.pack() # 更新画布 - self.root.geometry(f"{img_width+50}x{img_height+50}") # 调整窗口的大小以适应画布 + self.root.geometry(f"{img_width + 50}x{img_height + 50}") # 调整窗口的大小以适应画布 self.redraw() # 重新绘制图片和角落 def mouse_callback(self, event): """鼠标回调函数,处理鼠标按下、释放和移动事件。""" x, y = event.x, event.y # 获取鼠标位置 + # print(f"type(corners)={type(corners)}") + # print(f"corners={corners}") if event.type == tk.EventType.ButtonPress: # 如果是鼠标按下事件 print(f"鼠标在({x},{y})按下") - for idx, corner in enumerate(self.corners): # 遍历每个角落点 - #TODO: # 如果鼠标位置和角落的距离小于10 - self.dragging_idx = idx # 设置正在拖动的角落索引值为当前的角落的索引值 + for idx, corner in enumerate(self.corners): # 遍历每个角落 + if np.linalg.norm(corner - np.array([x, y])) < 10: # 如果鼠标位置和角落的距离小于10 + self.dragging_idx = idx # 设置正在拖动的角落索引 print(f"要开始拖动角落: corners[{idx}]={corner} , 所以变量: dragging_idx 别设置为 {idx}") - break # 已经找到了要拖动的点,所以跳出循环 + break # 跳出循环 elif event.type == tk.EventType.ButtonRelease: # 如果是鼠标释放事件 print(f"鼠标在({x},{y})释放") self.dragging_idx = -1 elif event.type == tk.EventType.Motion: # 如果是鼠标移动事件 - if(self.show_mouse_move.get()): + if (self.show_mouse_move.get()): print(f"鼠标在({x},{y})移动") if self.dragging_idx != -1: # 如果正在拖动一个角落 self.corners[self.dragging_idx] = np.array([x, y]) # 更新该角落的位置 @@ -91,8 +87,8 @@ class DocScannerApp: for idx, corner in enumerate(self.corners): # 遍历每个角落 # 在图片上绘制一个绿色的圆形标记角落的位置 cv.circle(img_copy, tuple(corner.astype(int)), 5, (0, 255, 0), -1) - # 在图片上绘制一个绿色的,宽度为2的多边形连接所有角落 - #TODO + # 在图片上绘制一个绿色的多边形连接所有角落 + cv.drawContours(img_copy, [self.corners.astype(int)], -1, (0, 255, 0), 2) img_tk = self.cv2image_to_tkinter_image(img_copy) # 将 OpenCV 图片转换为 Tkinter 图片 self.canvas.create_image(0, 0, anchor=tk.NW, image=img_tk) # 在画布上创建图片 self.canvas.image = img_tk # 保存图片,防止被垃圾回收 @@ -103,8 +99,8 @@ class DocScannerApp: pil_image = Image.fromarray(cv2_image_rgb) # 将数组转换为 PIL 图片 return ImageTk.PhotoImage(pil_image) # 将 PIL 图片转换为 Tkinter 图片 - def crop(self): + """裁剪图片。""" cropped_img = self.doc_scanner.crop_image(self.img, self.corners) # 调用 DocScanner 的 crop_image 方法来裁剪图片 cropped_img_tk = self.cv2image_to_tkinter_image(cropped_img) # 将裁剪后的 OpenCV 图片转换为 Tkinter 图片 @@ -112,7 +108,8 @@ class DocScannerApp: cropped_image_window.title("Cropped Image") # 设置新窗口的标题 img_label = tk.Label(cropped_image_window, image=cropped_img_tk) # 在新窗口中创建一个标签来显示裁剪后的图片 img_label.pack() # 将标签添加到新窗口中 - btn_close = tk.Button(cropped_image_window, text="Close", command=cropped_image_window.destroy) # 创建一个 "Close" 按钮,点击时关闭新窗口 + btn_close = tk.Button(cropped_image_window, text="Close", + command=cropped_image_window.destroy) # 创建一个 "Close" 按钮,点击时关闭新窗口 btn_close.pack() # 将按钮添加到新窗口中 img_label.image = cropped_img_tk # 保存图片,防止被垃圾回收 @@ -120,6 +117,7 @@ class DocScannerApp: """运行应用程序。""" self.root.mainloop() # 启动 Tkinter 事件循环 + if __name__ == "__main__": app = DocScannerApp() # 创建 DocScannerApp 类的实例 app.run() # 运行应用程序 -- Gitee