1 Star 0 Fork 197

谷思奇/doc_scanner_homework

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
app.py 9.12 KB
一键复制 编辑 原始数据 按行查看 历史
谷思奇 提交于 2023-06-11 15:19 . update app.py.
'''
- "app.py" 文件是一个文档扫描仪应用程序的主要入口点。
- 它提供了一个可视化的用户界面,用于加载图片、调整文档角落位置、裁剪文档并显示结果。
- 它的作用是提供一个简单易用的界面,使用户能够方便地进行文档扫描操作。
'''
import tkinter as tk
from tkinter import filedialog, Toplevel
from PIL import Image, ImageTk
import cv2
from doc_scanner import DocScanner
import numpy as np
class DocScannerApp:
def __init__(self):
self.doc_scanner = DocScanner()
self.corners = None
self.dragging_idx = -1
self.img = None
self.cropped_img = None
# 添加图像尺寸属性
self.img_width = 600
self.img_height = 400
self.root = tk.Tk()
self.canvas = tk.Canvas(self.root, width=600, height=400)
self.canvas.pack()
self.canvas.bind("<ButtonPress-1>", self.mouse_callback)
self.canvas.bind("<ButtonRelease-1>", self.mouse_callback)
self.canvas.bind("<B1-Motion>", self.mouse_callback)
self.canvas.bind("<Motion>", self.mouse_move_callback)
self.btn_select = tk.Button(self.root, text="Select Image", command=self.select_image)
self.btn_select.pack(side=tk.LEFT)
self.btn_confirm = tk.Button(self.root, text="Confirm", command=self.confirm_selection, state=tk.DISABLED)
self.btn_confirm.pack(side=tk.LEFT)
self.btn_reset = tk.Button(self.root, text="Reset", command=self.reset_selection, state=tk.DISABLED)
self.btn_reset.pack(side=tk.LEFT)
self.show_mouse_move = tk.BooleanVar(value=True)
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)
self.selection_complete = False
self.info = tk.Text(self.root, height=10, width=50)
self.info.pack(side=tk.BOTTOM)
def select_image(self):
file_path = filedialog.askopenfilename()
self.img, self.corners = self.doc_scanner.load_image(file_path)
# 更新窗口和画布的尺寸
self.img_height, self.img_width = self.img.shape[:2]
self.root.geometry(f"{self.img_width}x{self.img_height}")
self.canvas.config(width=self.img_width, height=self.img_height)
if self.corners is None:
self.reset_selection()
self.canvas.bind("<Button-1>", self.select_corner)
self.canvas.bind("<Motion>", self.mouse_move_callback)
else:
self.selection_complete = True
self.canvas.unbind("<Button-1>")
self.canvas.unbind("<Motion>")
self.btn_confirm.config(state=tk.NORMAL)
self.btn_reset.config(state=tk.NORMAL)
self.redraw()
self.info.insert(tk.END, f"Image selected: {file_path}\n")
self.canvas.bind("<Motion>", self.mouse_move_callback)
self.insert_info(f"Image selected: {file_path}\n")
def select_corner(self, event):
try:
x, y = event.x, event.y
self.insert_info(f"选择的角点: ({x}, {y})\n")
if self.corners is None:
self.corners = []
if len(self.corners) < 4:
self.corners.append([x, y])
self.redraw()
# 添加标签显示角点坐标
self.canvas.create_text(x, y, text=f"({x},{y})", tags="corner")
if len(self.corners) == 4:
self.selection_complete = True
self.canvas.unbind("<Button-1>")
self.canvas.unbind("<Motion>")
self.btn_confirm.config(state=tk.NORMAL)
self.btn_reset.config(state=tk.NORMAL)
self.insert_info(f"当前角点: {self.corners}\n")
except Exception as e:
self.insert_info(f"出现错误: {str(e)}\n")
def mouse_move_callback(self, event):
x, y = event.x, event.y
self.insert_info(f"Mouse position: ({x}, {y})\n")
if self.show_mouse_move.get():
self.root.title(f"Mouse Position: ({x}, {y})")
def mouse_callback(self, event):
x, y = event.x, event.y
self.insert_info(f"Mouse position: ({x}, {y})\n")
if event.type == tk.EventType.ButtonPress:
for idx, corner in enumerate(self.corners):
if np.linalg.norm(corner - np.array([x, y])) < 10:
self.dragging_idx = idx
break
# 添加临时标签显示鼠标按下的位置
self.canvas.create_text(x, y, text=f"按下位置({x},{y})", tags="temp")
elif event.type == tk.EventType.ButtonRelease:
self.dragging_idx = -1
# 添加临时标签显示鼠标释放的位置
self.canvas.create_text(x, y, text=f"释放位置({x},{y})", tags="temp")
elif event.type == tk.EventType.Motion:
if self.dragging_idx != -1:
self.corners[self.dragging_idx] = np.array([x, y])
self.redraw()
def redraw(self):
# 清除所有临时标签
self.canvas.delete("temp")
if self.corners is not None:
img_copy = self.img.copy()
for idx, corner in enumerate(self.corners):
cv2.circle(img_copy, tuple(corner.astype(int)), 5, (0, 255, 0), -1)
cv2.polylines(img_copy, [np.int32(self.corners)], True, (0, 255, 0), 2)
img_tk = self.cv2image_to_tkinter_image(img_copy)
self.canvas.create_image(0, 0, anchor=tk.NW, image=img_tk)
self.canvas.image = img_tk
if self.selection_complete:
# 重新绑定事件,限制鼠标事件的触发范围在所选择的区域内
self.canvas.bind("<ButtonPress-1>", self.mouse_callback_in_selection)
self.canvas.bind("<ButtonRelease-1>", self.mouse_callback_in_selection)
self.canvas.bind("<B1-Motion>", self.mouse_callback_in_selection)
self.canvas.bind("<Motion>", self.mouse_move_callback)
def mouse_callback_in_selection(self, event):
x, y = event.x, event.y
if event.type == tk.EventType.ButtonPress:
for idx, corner in enumerate(self.corners):
if np.linalg.norm(corner - np.array([x, y])) < 10:
self.dragging_idx = idx
break
elif event.type == tk.EventType.ButtonRelease:
self.dragging_idx = -1
elif event.type == tk.EventType.Motion:
if self.dragging_idx != -1:
self.corners[self.dragging_idx] = np.array([x, y])
self.redraw()
def cv2image_to_tkinter_image(self, cv2_image):
cv2_image_rgb = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
pil_image = Image.fromarray(cv2_image_rgb)
return ImageTk.PhotoImage(pil_image)
def confirm_selection(self):
try:
self.insert_info("确认选择,开始裁剪...\n")
self.canvas.unbind("<Button-1>")
self.canvas.unbind("<Motion>")
self.btn_confirm.config(state=tk.DISABLED)
self.btn_reset.config(state=tk.DISABLED)
self.btn_select.config(state=tk.DISABLED)
# 裁剪图像并显示在新窗口中
self.cropped_img = self.doc_scanner.transform(self.img, self.corners)
# 创建新窗口
top_level = Toplevel(self.root)
top_level.title("裁剪后的图像")
# 创建画布并显示裁剪后的图像
cropped_canvas = tk.Canvas(top_level, width=self.cropped_img.shape[1], height=self.cropped_img.shape[0])
cropped_canvas.pack()
img_tk = self.cv2image_to_tkinter_image(self.cropped_img)
cropped_canvas.create_image(0, 0, anchor=tk.NW, image=img_tk)
cropped_canvas.image = img_tk
# 添加功能操作按钮
btn_save = tk.Button(top_level, text="保存", command=self.save_image)
btn_save.pack(side=tk.LEFT)
btn_reset = tk.Button(top_level, text="重置", command=self.reset_selection)
btn_reset.pack(side=tk.LEFT)
except Exception as e:
self.insert_info(f"出现错误: {str(e)}\n")
def insert_info(self, msg):
self.info.insert(tk.END, msg)
self.info.see(tk.END)
def reset_selection(self):
self.insert_info("Selection reset\n")
self.corners = None
self.selection_complete = False
self.btn_confirm.config(state=tk.DISABLED)
self.btn_reset.config(state=tk.DISABLED)
self.btn_select.config(state=tk.NORMAL)
if self.img is not None: # 添加判断以避免在重新选择图像时出错
self.redraw()
self.canvas.bind("<Button-1>", self.select_corner)
self.canvas.bind("<Motion>", self.mouse_move_callback)
def save_image(self):
file_path = filedialog.asksaveasfilename(defaultextension=".jpg")
cv2.imwrite(file_path, self.cropped_img)
self.insert_info(f"Image saved to: {file_path}\n")
def run(self):
self.root.mainloop()
if __name__ == "__main__":
app = DocScannerApp()
app.run()
import os
print(os.getcwd())
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/gu--siqi/doc_scanner_homework.git
git@gitee.com:gu--siqi/doc_scanner_homework.git
gu--siqi
doc_scanner_homework
doc_scanner_homework
master

搜索帮助