Welcome to 发呆鱼.|

发呆鱼

园龄:3年4个月粉丝:1关注:0

类似于电子签名的东西

不知道是啥东西的东西

本来是打算写一个电子签名系统的作业,但是现在也不知道写成啥了。所以就叫做不知道是啥东西的东西了。
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 中国大陆许可协议进行许可。

posted @   发呆鱼  阅读(27)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起