深度学习实战之手写签名识别(100%准确率、语音播报)

您所在的位置:网站首页 手写识别是什么原理 深度学习实战之手写签名识别(100%准确率、语音播报)

深度学习实战之手写签名识别(100%准确率、语音播报)

2024-07-16 21:31:26| 来源: 网络整理| 查看: 265

手写签名在日常生活中随处可见,简单来说就是亲笔书写自己的名字,在纸质文档上使用手写签名主要用以确定签字者的身份,并表示签字者同意所签署文档中规定的内容,对文档的真实性负责,且具有法律效力。由此看见手写签名的重要性。在现实的生活中不乏有不法分子模仿其他人的字体,进而模仿他人的签名获得不发的利益。尽管会有鉴别字体的工作,但在鉴别时不仅不准确,而且还十分的消耗人力以及财力。为了解决这一客观显示存在的问题,笔者结合着人工智能的思想和并使用计算机视觉技术对手写签名进行训练,得到了高达100%的训练准确率。并将训练模型进行优化后运用实现了一套手写签名识别系统。

1.开发环境

笔者的开发环境如下,大家可以参考进行配置

python3.6或python3.7pytorch1.0.1torchvision 0.2.2.post3visomubuntu16.04和windows10 2. 准备阶段

在完成了上述的环境搭建后,即可进入到准备阶段了。这里准备的有数据集的准备、以及相关代码的主备。

数据集的准备 笔者这里的数据集是自己准备的,收集了六个人的手写签名,约4500张签名图片 在这里插入图片描述 在这里插入图片描述

数据集的划分 笔者这里将数据集进行六分类的划分,每一类约有750张图片 数据集划分为训练数据、验证数据、测试数据 其中训练数据、验证数据、测试数据的具体划分如下图所示 在这里插入图片描述

载入数据 在上述的步骤中已经准备好了相应的数据集,同时也划分好了训练数据、验证数据、测试数据的部分。在完成了理论的设计后,该怎么使用代码对数据进行划分呢,代码如下所示

class Data(Dataset): def __init__(self,root,resize,mode): super(Data,self).__init__() # 保存参数 self.root=root self.resize=resize # 给每一个类做映射 self.name2label={} # "daj":0 ,"hjj":1…… for name in sorted(os.listdir(os.path.join(root))): # 过滤掉文件夹 if not os.path.isdir(os.path.join(root,name)): continue # 保存在表中;将最长的映射作为最新的元素的label的值 self.name2label[name]=len(self.name2label.keys()) # print(self.name2label) # 加载文件 self.images,self.labels=self.load_csv('images.csv') # 裁剪数据 if mode=='train': self.images=self.images[:int(0.6*len(self.images))] # 将数据集的60%设置为训练数据集合 self.labels=self.labels[:int(0.6*len(self.labels))] # label的60%分配给训练数据集合 elif mode=='val': self.images = self.images[int(0.6 * len(self.images)):int(0.8 * len(self.images))] # 从60%-80%的地方 self.labels = self.labels[int(0.6 * len(self.labels)):int(0.8 * len(self.labels))] else: self.images = self.images[int(0.8 * len(self.images)):] # 从80%的地方到最末尾 self.labels = self.labels[int(0.8 * len(self.labels)):] # image+label 的路径

在使用上述的代码后即可将已有的数据集的60%划分为训练数据、20%划分为验证数据、20%划分为测试数据。

3. 训练阶段

在完成了上述的操作后,即可进入到训练阶段。这里笔者使用的是比较经典的神经网络结构–ResNet. 由何凯明团队所提出来的。其深度残差网络(Deep Residual Network)在2015年的ImageNet上取得冠军。具体网络的特点,读者可自行Google了解,这里笔者就不再赘述。

搭建ResNet网络结构 搭建的网络结构代码如下: class ResBlk(nn.Module): def __init__(self, ch_in, ch_out, stride=1): super(ResBlk, self).__init__() self.conv1 = nn.Conv2d(ch_in, ch_out, kernel_size=3, stride=stride, padding=1) self.bn1 = nn.BatchNorm2d(ch_out) self.conv2 = nn.Conv2d(ch_out, ch_out, kernel_size=3, stride=1, padding=1) self.bn2 = nn.BatchNorm2d(ch_out) self.extra = nn.Sequential() if ch_out != ch_in: # [b, ch_in, h, w] => [b, ch_out, h, w] self.extra = nn.Sequential( nn.Conv2d(ch_in, ch_out, kernel_size=1, stride=stride), nn.BatchNorm2d(ch_out) ) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = self.bn2(self.conv2(out)) # short cut. # extra module: [b, ch_in, h, w] => [b, ch_out, h, w] # element-wise add: out = self.extra(x) + out out = F.relu(out) return out class ResNet18(nn.Module): def __init__(self, num_class): super(ResNet18, self).__init__() self.conv1 = nn.Sequential( nn.Conv2d(3, 16, kernel_size=3, stride=3, padding=0), nn.BatchNorm2d(16) ) # followed 4 blocks # [b, 16, h, w] => [b, 32, h ,w] self.blk1 = ResBlk(16, 32, stride=3) # [b, 32, h, w] => [b, 64, h, w] self.blk2 = ResBlk(32, 64, stride=3) # # [b, 64, h, w] => [b, 128, h, w] self.blk3 = ResBlk(64, 128, stride=2) # # [b, 128, h, w] => [b, 256, h, w] self.blk4 = ResBlk(128, 256, stride=2) # [b, 256, 7, 7] self.outlayer = nn.Linear(256*3*3, num_class) def forward(self, x): x = F.relu(self.conv1(x)) # [b, 64, h, w] => [b, 1024, h, w] x = self.blk1(x) x = self.blk2(x) x = self.blk3(x) x = self.blk4(x) # print(x.shape) x = x.view(x.size(0), -1) x = self.outlayer(x) return x def main(): blk = ResBlk(64, 128) tmp = torch.randn(2, 64, 224, 224) out = blk(tmp) print('block:', out.shape) model = ResNet18(5) tmp = torch.randn(2, 3, 224, 224) out = model(tmp) print('resnet:', out.shape) p = sum(map(lambda p:p.numel(), model.parameters())) print('parameters size:', p) if __name__ == '__main__': main() 训练 在完成了网络的搭建后,即可对数据进行训练。 笔者这里设置如下 batchsz=128 lr = 1e-3 epochs = 10 batchsz = 128 lr = 1e-3 epochs = 10 device = torch.device('cuda') train_db = Data('train_data', 224, mode='train') val_db = Data('train_data', 224, mode='val') test_db = Data('train_data', 224, mode='test') train_loader = DataLoader(train_db, batch_size=batchsz, shuffle=True, num_workers=4) val_loader = DataLoader(val_db, batch_size=batchsz, num_workers=4) test_loader = DataLoader(test_db, batch_size=batchsz, num_workers=4) viz = visdom.Visdom() def evalute(model, loader): model.eval() correct = 0 total = len(loader.dataset) for x, y in loader: x, y = x.to(device), y.to(device) with torch.no_grad(): logits = model(x) pred = logits.argmax(dim=1) correct += torch.eq(pred, y).sum().float().item() return correct / total def main(): model = ResNet18(6).to(device) optimizer = optim.Adam(model.parameters(), lr=lr) criteon = nn.CrossEntropyLoss() best_acc, best_epoch = 0, 0 global_step = 0 viz.line([0], [-1], win='loss', opts=dict(title='loss')) viz.line([0], [-1], win='val_acc', opts=dict(title='val_acc')) for epoch in range(epochs): if epoch % 1 == 0: print('第 '+str(epoch+1)+' training……') val_acc = evalute(model, val_loader) if val_acc > best_acc: best_epoch = epoch best_acc = val_acc torch.save(model.state_dict(), 'best.mdl') viz.line([val_acc], [global_step], win='val_acc', update='append') print('最好的准确率:', best_acc, '最好的批次:', best_epoch) model.load_state_dict(torch.load('best.mdl')) print('正在加载模型……') test_acc = evalute(model, test_loader) print('测试准确率:', test_acc) if __name__ == '__main__': main()

训练可视化结果如下: 在这里插入图片描述 这里也许读者会想有没有过拟合呢?? 在这里插入图片描述 可以看到,也没有出现过拟合的问题。

4. 模型使用及系统实现

将训练获得的训练模型装载,并系统的使用其进行签名的识别。 这里笔者结合着计算机视觉常用的库opencv进行使用模型。 同时笔者为了能够更加符合日常的使用,这里笔者将opencv显示进行了中文化。 其代码如下:

def prediect(img_path): net=torch.load('model.pkl') net=net.to(device) torch.no_grad() img=Image.open(img_path) img=transform(img).unsqueeze(0) img_ = img.to(device) outputs = net(img_) _, predicted = torch.max(outputs, 1) print(classes[predicted[0]]) begin = Speak() begin.speak(str(classes[predicted[0]])) img = cv2.imread(img_path) # 如想读取中文名称的图片文件可用cv2.imdecode() pil_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # cv2和PIL中颜色的hex码的储存顺序不同,需转RGB模式 pilimg = Image.fromarray(pil_img) # Image.fromarray()将数组类型转成图片格式,与np.array()相反 draw = ImageDraw.Draw(pilimg) # PIL图片上打印汉字 font = ImageFont.truetype("simhei.ttf", 20, encoding="utf-8") # 参数1:字体文件路径,参数2:字体大小 draw.text((0, 0), classes[predicted[0]], (255, 0, 0), font=font) img = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR) # 将图片转成cv2.imshow()可以显示的数组格式 cv2.imshow("show", img) if cv2.waitKey(0)==ord(' '): cv2.destroyAllWindows()

并使用系统进行实际的手写签名识别,其结果图下 在这里插入图片描述 同时在识别完成后,系统还会自动的将识别结果以语音的形式播报出来。

你听:澜江全 、狄爱景、陆春宇、王雅君…… 最后申明:由于笔者知识水平有限,在问题描述上难免会有不准确的地方,还请大家谅解。希望大家多动手实践,共同进步。如若在实践的过程中出现问题,可以同我进行交流qq:1017190168 申明近期笔者接计算机视觉方面的毕业设计、比赛,有需要的欢迎联系!!!


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭