#!usr/bin/python3 # -*- coding:utf-8 -*- import random import tkinter as tk import tkinter.filedialog as filedialog import tkinter.messagebox as msg import PIL.Image as Img import PIL.ImageTk as Imgtk import cv2 import numpy as np import img_util.gui_util as gu root = tk.Tk() con: tk.Label = None sc_th: tk.Scale = None start = False trans = False isave = True radi_n = tk.IntVar() thresh = tk.IntVar(value=125) img_path = '' img_o = None img_tk = None img_o_not = None SCREEN_W, SCREEN_H = root.winfo_screenwidth(), root.winfo_screenheight() WIN_W = 1280 INI_H = int(SCREEN_H * 3/4) img = None out_img = None img_not = None temp_out, use_temp = None, False def resizeImg(w, h, wb, hb, p_image): f = min(wb/w, hb/h) return p_image.resize((int(f*w), int(f*h))) def resizeImgAuto(wb, hb, p_image: Img.Image): return resizeImg(p_image.width, p_image.height, wb, hb, p_image) def selectFile(): global img_path, img_tk, img_o, img, img_not, img_o_not, out_img, con, start, isave img_path = filedialog.askopenfilename() if len(img_path) == 0: return img_o = resizeImgAuto(WIN_W-2, SCREEN_H*2/3-2, Img.open(img_path)) img_tk = Imgtk.PhotoImage(img_o) img_o_not = img_o.copy() # img = cv2.imread(img_path) img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), cv2.IMREAD_COLOR) out_img = img.copy() img_not = img.copy() con.config(image=img_tk) radi_n.set(0) start = True isave = True def saveFile(): global isave if not start: return save_path = filedialog.asksaveasfilename(filetypes=gu.SUPPORT_FILETYPE, defaultextension=gu.SUPPORT_FILETYPE) if len(save_path) == 0: return # cv2.imwrite(save_path, out_img) ext = str() for i in range(len(save_path)-1, -1, -1): if save_path[i] == '.': ext = save_path[i:] if len(ext) == 0: msg.showerror('错误', '请输入文件后缀名') try: cv2.imencode(ext, out_img)[1].tofile(save_path) isave = True except: msg.showerror('错误', '未受支持的文件后缀名') def changePer(): global img, img_o, img_tk, out_img, trans, isave if not start: return newp = gu.changePerspGui(img, str(random.random())) if newp is None: return img_o = resizeImgAuto(WIN_W-2, SCREEN_H*2/3-2, Img.fromarray(newp)) img_tk = Imgtk.PhotoImage(img_o) img = newp out_img = img.copy() con.config(image=img_tk) radi_n.set(0) trans = True isave = False def unPer(): global img, img_o, img_tk, out_img, img_not, img_o_not, trans, isave if not start or not trans or not msg.askyesno('撤回', '您确定要撤销所有的透视矫正操作吗? '): return img = img_not.copy() out_img = img.copy() img_o = img_o_not.copy() img_tk = Imgtk.PhotoImage(img_o) con.config(image=img_tk) trans = False isave = False radi_n.set(0) def changeThresh(pos): global out_img, img_tk, temp_out, use_temp, isave if not use_temp: print('Error') return binary, out_img = cv2.threshold(temp_out, thresh.get(), 255, cv2.THRESH_BINARY) img_tk = Imgtk.PhotoImage(resizeImgAuto(WIN_W - 2, SCREEN_H * 2 / 3 - 2, Img.fromarray(out_img))) con.config(image=img_tk) isave = False def selectRadio(): global img_tk, out_img, img, img_o, use_temp, temp_out, isave if not start: return rg = radi_n.get() if rg == 3: temp_out = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) binary, out_img = cv2.threshold(temp_out, thresh.get(), 255, cv2.THRESH_BINARY) img_tk = Imgtk.PhotoImage(resizeImgAuto(WIN_W - 2, SCREEN_H * 2 / 3 - 2, Img.fromarray(out_img))) elif rg == 2: out_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) binary, out_img = cv2.threshold(out_img, 0, 255, cv2.THRESH_OTSU) img_tk = Imgtk.PhotoImage(resizeImgAuto(WIN_W-2, SCREEN_H*2/3-2, Img.fromarray(out_img))) elif rg == 1: out_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_tk = Imgtk.PhotoImage(resizeImgAuto(WIN_W-2, SCREEN_H*2/3-2, Img.fromarray(out_img))) else: out_img = img.copy() img_tk = Imgtk.PhotoImage(img_o) use_temp = (rg == 3) if use_temp: sc_th.config(state='normal', takefocus=True) else: sc_th.config(state='disabled', takefocus=False) con.config(image=img_tk) isave = False def versionInfo(): msg.showinfo('版本信息', '简单扫描 --- By 姜业恒 10205101498 \n 版本: Alpha v0.01 \n \ 此版本仅用于华东师范大学《数字图像处理》课程期末作业 \n\ (课程代码: SOFT0031132210.02) \n\ 暂不开放未经作者允许对此软件进行修改或售卖的权利') def onclose(): global isave if isave or msg.askokcancel('简单扫描', '您还有未保存的修改, 确定退出吗?'): root.destroy() def main(): global con, sc_th root.title('简单扫描 -- By 姜业恒 10205101498') root.geometry('x'.join([str(WIN_W), str(INI_H)])+'+10+10') fr_top = tk.Frame(root) fr_med = tk.Frame(root) sep_line = tk.Canvas(root, background='#dddddd', width=WIN_W, height=1) con = tk.Label(root, text='\n图像预览处\n\n\n\n\n\n') bt_choose = tk.Button(fr_top, text='选择图片', command=lambda: selectFile()) bt_save = tk.Button(fr_top, text='保存', command=lambda: saveFile()) bt_changeP = tk.Button(fr_top, text='透视矫正', command=changePer) bt_unP = tk.Button(fr_top, text='撤销透视矫正', command=unPer) bt_info = tk.Button(fr_top, text='版本信息', command=versionInfo) rd_ori = tk.Radiobutton(fr_med, text='原图', variable=radi_n, value=0, command=selectRadio) rd_gr = tk.Radiobutton(fr_med, text='灰度', variable=radi_n, value=1, command=selectRadio) rd_bw = tk.Radiobutton(fr_med, text='黑白(自动)', variable=radi_n, value=2, command=selectRadio) rd_th = tk.Radiobutton(fr_med, text='黑白(手动)', variable=radi_n, value=3, command=selectRadio) sc_th = tk.Scale(fr_med, variable=thresh, from_=0, to=255, orient='horizontal', length=int(WIN_W/2), command=changeThresh, state='disabled', takefocus=False) fr_top.pack() fr_med.pack() # sc_th.pack() sep_line.pack() bt_choose.grid(row=0, column=0) bt_save.grid(row=0, column=1) bt_changeP.grid(row=0, column=2) bt_unP.grid(row=0, column=3) bt_info.grid(row=0, column=4) rd_ori.grid(row=0, column=0) rd_gr.grid(row=0, column=1) rd_bw.grid(row=0, column=2) rd_th.grid(row=0, column=3) sc_th.grid(row=0, column=4) con.pack() root.protocol('WM_DELETE_WINDOW', onclose) root.mainloop() if __name__ == '__main__': main()