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