类似于电子签名的东西
不知道是啥东西的东西
本来是打算写一个电子签名系统的作业,但是现在也不知道写成啥了。所以就叫做不知道是啥东西的东西了。
1,语言:python_3.8.5
2,编译器:pycharm
3,外部使用库:opencv_4.4.0,numpy_1.19.1,tkinter,pil
4,gui类,在该类中使用tkinter库完成画板的创建,鼠标的监控。画板的大小为480640,保存的jpg图片的分辨率为480640。
当触发保存时,关闭面板后会返回图片数据
5,coding类,包含对图像的行程编码和解码。
如:传入数据:[0,0,0,0,0,1,1,1,1,0,1,1]
行程编码:img=[0,1,0,1] num=[5,4,1,2]
解码则反向
6,在mian文件中,palette()函数会调用pattle类中函数,获取图像数据。
将图像二值化
_, src = cv2.threshold(src, 180, 1, cv2.THRESH_BINARY)
将图片二值化(大于180的置为1,小于180置为0)
(###也可使用main文件中writedata(b)函数,遍历所有像素,将其二值化。)。
将图像转形:b = src.reshape(1, -1)。
7,在main文件中的saveimg函数中,调用coding类,将数据编码,并使用pickle将数据序列化存入文件。
8,在mian文件中readimg函数,反序列化读出数据。利用coding类解码,并将数据转姓(shape=(480,640,3)。imshow函数显示图片。
import cv2
import coding as coding
import pickle
import numpy as np
import gui as GUI
def imshow(im):
'''
显示签名
:param im:图片数据
'''
#反向二值化,将1改为255
_,im=cv2.threshold(im, 0,255, cv2.THRESH_BINARY)
cv2.imshow("result", im)
# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
def saveimg(cod,b):
'''
保存图片
:param cod: 编码类coding,对象
:param b: 图片数据形状转换后,shape(1,-1)
'''
num, img = cod.code(b[0])
with open("data.dd","wb") as fb:
pickle.dump(num,fb)
pickle.dump(img,fb)
def readimg(cod):
'''
读取签名文件,并打印
:param cod: 编码类coding,对象
'''
#读取文件
with open("data.dd", "rb") as fb:
num=pickle.load(fb)
img2=pickle.load(fb)
#解码
st = cod.recode(num, img2)
#数形转化
st = np.array(st)
st = st.reshape(480, 640, 3)
#显示图片
imshow(st)
return num,img2
def writedata(b):
'''
将像素写入txt文件
'''
hight = b.shape[0]
width = b.shape[1]
channels = b.shape[2]
with open('data.txt', 'w') as f: # 设置文件对象
for i in range(hight):
for j in range(width):
for c in range(channels):
f.write(str(b[i, j, c]))
def palette(gui):
'''
签名画板
:param pal: 画板类palette的对象
:return: src(图像二值化后数据) b(数据形状转换为(1,-1)后数据)
'''
#获取签名图像
src = gui.start() #type=PIL.Image
#没有进行签名的情况
if src==None:
src=np.ones((480,640,3)) #全1
else:
src = np.array(src) # type='numpy.ndarray
_, src = cv2.threshold(src, 180, 1, cv2.THRESH_BINARY) #图像二值化(白为1,黑为0)
#形状转换
b = src.reshape(1, -1)
return src,b
if __name__ == '__main__':
gui=GUI.GUI()
cod = coding.coding()
_,b=palette(gui=gui) #执行签名
saveimg(cod=cod,b=b) #保存签名
readimg(cod=cod) #读取文件,显示签名
import tkinter as tk
from tkinter import ttk
from PIL import ImageGrab
class GUI():
'''
gui视图
'''
def __init__(self):
self.win=tk.Tk() #创建窗口
self.win.title("电子签名系统") #标题
self.win.geometry('640x540') #窗口大小
self.width=640
self.hight=540
self.img=None
def Canvas(self):
# 新建画布界面
canvas = tk.Canvas(self.win, width=self.width, height=self.hight, highlightthickness=0, bg='#FFFFFF')
canvas.pack()
#画线
canvas.create_line(0, 55, self.width, 55, fill="#000000") # 加了dash就是虚线,不加就是实线
# 创建一个可在 canvas 上手动绘图的效果,通过两点画线段的方式
draw_point = ['', ''] # 用于储存拖拉鼠标时的点
revoke = [] # 用于储存每次鼠标绘图操作的ID供撤销用[[...],[...],[...]]
recover = [] # 用于储存每次鼠标绘图的点构成的列表供恢复
clear = [] # 用于记录是否使用过清空,因为列表可变,支持全局修改,所以用列表记录
def _canvas_draw(event):
if not event: # 松开鼠标左键时执行,清空记录点
draw_point[:] = ['', ''] # [:]只改变draw_point指向的列表的内容,不是重新赋值一个新的列表所以修改值全局通用
return
point = [event.x, event.y] # 此次传递的点坐标
if draw_point == ['', '']: # 按下鼠标左键开始拖动时执行
draw_point[:] = point # 保存拖动的第一个点
if len(revoke) < len(recover):
recover[len(revoke):] = [] # 用于使用过撤销后再绘图,清除撤销点后的恢复数据
clear[:] = []
revoke.append([]) # 新建一个撤销记录列表
recover.append([]) # 新建一个恢复记录列表
recover[-1].extend(point) # 在新建的恢复记录列表里记录第一个点
else:
revoke[-1].append(
canvas.create_line(draw_point[0], draw_point[1], event.x, event.y, fill="#476042", width=3,
tags="line")
) # 绘制的线段并保存到撤销记录的末次列表
draw_point[:] = point # 保存拖动点,覆盖上一次
recover[-1].extend(point) # 保存此次传递的点坐标到恢复记录的末次列表
canvas.bind("<B1-Motion>", _canvas_draw) # 设定拖动鼠标左键画线段
canvas.bind("<ButtonRelease-1>", lambda event: _canvas_draw(0)) # 设定松开鼠标左键清除保存的点
# 添加撤销和恢复功能rev撤销,rec恢复
def _canvas_re(rev=0, rec=0):
if rev and revoke: # 撤销执行
for i in revoke.pop(-1): canvas.delete(i) # pop弹出最后一个撤销列表,删除图像
elif rec and recover and (len(revoke) != len(recover)): # 恢复执行,恢复列表需要大于撤销列表
if clear:
for i in recover: revoke.append([canvas.create_line(i, fill="#476042", width=1, tags="line")])
clear[:] = []
else:
revoke.append([canvas.create_line(recover[len(revoke)], fill="#476042", width=1, tags="line")])
# 清空功能
def _canvas_clear():
canvas.delete("line") # 清除 tags = "line"的图像
revoke[:] = []
clear.append(1)
def _canvas_save():
canvas.update()
x = self.win.winfo_rootx() + canvas.winfo_x()
y = self.win.winfo_rooty() + canvas.winfo_y()+60
x1 = x + canvas.winfo_width()
y1 = y + canvas.winfo_height()-60
self.img=ImageGrab.grab().crop((x, y, x1, y1))
bt1 = ttk.Button(canvas, text='保存', command=_canvas_save) # 创建一个Button对象,默认设置为居中对齐
canvas.create_window((50, 30), window=bt1, anchor='w') # 修改button在canvas上的对齐方式
bt2 = ttk.Button(canvas, text='恢复', command=lambda: _canvas_re(rec=1))
canvas.create_window((self.width - 150, 30), window=bt2, anchor='w')
bt3 = ttk.Button(canvas, text="清空", command=_canvas_clear)
canvas.create_window((self.width/ 2 - 43, 30), window=bt3, anchor='w')
def start(self):
'''
开始gui试图
:return: 所画图像 type=PIL.Image
'''
self.Canvas()
self.win.mainloop()
return self.img
'''形成压缩,反向解码'''
class coding():
def __init__(self):
pass
def code(self,img):
'''
行程编码
:param img: 图片像素数据(type=numpy)
:return: num:行程标识数(type=list)
:return:img2:行程标识(type=list)
'''
orimg = img
length = len(orimg)
#保存0,1标识
img2=[]
#保存形程长度
num=[]
cound=0
singe=orimg[0]
for i in range(length):
if orimg[i]==singe:
cound=cound+1
else:
num.append(cound)
img2.append(singe)
singe=orimg[i]
cound=1
num.append(cound)
img2.append(singe)
return num,img2
def recode(self,num,img2):
'''
形程解码
:param num: 行程标识数(type=list)
:param img2: 行程标识(0,1)(type=list)
:return: 图片像素数据(type=list)
'''
re_img=[]
for i in range(len(num)):
for j in range(num[i]):
re_img.append(img2[i])
return re_img
本文作者:发呆鱼
本文链接:https://www.cnblogs.com/dyiblog/articles/15929768.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步