You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
6.6 KiB

#!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()