深度学习应用于图像处理领域应该说有很长一段时间了,相关的研究成果也有很多的积累了,从项目和实践入手是我觉得的最好最快速有效的学习手段,当下很多主流的验证码识别系统大都是基于神经网络设计开发而来的,在处理图像数据方面,神经网络有着无与伦比的优势,本人最开始接触到卷积神经网络也是从验证码是被项目开始入手的。本项目从零开始介绍整体的实践思路,以我们熟知的12306网站验证码为例进行分析实战,从数据采集、图像处理、模型搭建、预测识别、界面开发几个节点进行针对性的设计开发,实现了验证码识别的完整流程,达到了很高的精度要求和速度要求,能够满足基本的调用需求。在模型方面,对比使用了多种经典的神经网络模型来进行实验,选取最优的实验结果来用于界面开发和调用识别。

整个项目基于python3.6开发实现,项目中包含整体项目所使用到的数据、代码脚本、模型文件和界面文件的所有数据文件。项目文件截图如下所示:

上述文件解释说明如下表所示:

文件名称 文件说明
screenshot/ 软件截图目录
getData.py 图像验证码数据采集模块
imageCut.py 图像验证码数据切分处理模块
dataHelper.py 模型数据加载预处理模块
myModel.py 模型训练模块
resnetModel.py Resnet模块
predict.py 离线模块预测识别模块
guiDemo.py 界面可视化模块
texts.txt 文本标签集合
valid_ip_all.json IP代理池数据,避免爬虫被封禁
imageModel.h5 训练好的图像识别模型文件
textModel.h5 训练好的文本识别模块文件

接下来针对整个建模流程的各个节点进行详细说明。

一、数据采集

做深度学习的,基础条件就是:数据+算力,想要建模实践,首先就需要把所需的数据给准备好了,下面我们开始本文的第一步工作:源站验证码数据采集,这就是一个单纯地数据爬虫工作,详细的实现原理本来也就没什么,我也就不多讲解了,核心代码部分如下:

#!usr/bin/env python
#encoding:utf-8
from __future__ import division'''
__Author__:沂水寒城
功能: 网络验证码数据采集模块
'''def buildProxy():'''构建代理信息'''header_list=generateRandomUA(num=500)header={'User-Agent':random.choice(header_list)}ip_proxy=random.choice(ip_list)one_type,one_ip,one_port=ip_proxy[0],ip_proxy[1],ip_proxy[2]proxy={one_type:one_type+'://'+one_ip+':'+one_port}return header,proxydef getPageHtml(url,header,proxy,num_retries=3):'''多代理形式、超时重试机制,获取数据'''try:response=requests.get(url,headers=header,proxies=proxy,timeout=5)return responseexcept Exception as e:time.sleep(random.randint(3,8))while num_retries:num_retries-=1print('Left tring number is:  ', num_retries)return getPageHtml(url,header,proxy,num_retries)def getVCPics(img_url,start,end,saveDir):'''下载验证码数据'''if not os.path.exists(saveDir):os.makedirs(saveDir)for i in range(start,end):print("Downloading",i+1,"......")header,proxy=buildProxy()try:img=getPageHtml(img_url,header,proxy,num_retries=3)pic_name=saveDir+str(i+1)+'.jpg'file_pic=open(pic_name,'ab')file_pic.write(img.content)file_pic.close()time.sleep(random.randint(0.1,1))except:passif __name__ == '__main__':print('captchaDataCollection!!!')url="要爬取的验证码链接"#验证码数据采集getVCPics(url,0,500,'originalData/play/')

为了避免被源站检测到我们固定的IP地址在频繁地发送数据请求导致的被拉黑的情况出现,这里我采用了随机UA伪装+动态IP代理的方式来进行了规避处理,buildProxy函数是整个具体的实现,任何场合里面,这个方法都可以直接拿去使用的,尽可能地提升爬虫的工作效率。

二、图像切分处理

原始采集到的验证码数据是没有办法去直接使用的,需要进行切分处理,这样就转化为了单个子图识别的问题了,相对于原始大图来说识别的难度就小了很多了,当然了这里也不是说所有的图像验证码数据都是可以这样去操作的,12306的验证码数据是很规整的类型,可以基于一定的阈值对其进行划分切割处理,很方便就可以得到单个的子图数据了,下面是一些原始验证码数据样例:

可以看到:每幅图片里面均包含了8张子图,在第一行上面是文本标签数据,也就是说12306一张验证码数据我们要完成两种类型图像数据的识别工作。分析到这一步,接下来的工作就比较清晰了,我们首先要编写图像切割方法,完成对原始图像数据的切割处理,下面是切割部分的核心代码:

def singleCut(img_path,row,col,cutDir):'''单张验证码图像数据切割处理'''img=Image.open(img_path)print('image_shape: ', img.size)name=img_path.split('/')[-1].strip().split('.')[0].strip()if not os.path.exists(cutDir):os.makedirs(cutDir)w,h=img.sizeif row<=h and col<=w:print('Original image info: %sx%s, %s, %s' % (w,h,img.format,img.mode))rowheight=h//rowcolwidth=w//colfor r in range(row):for c in range(col):box=(c*colwidth,r*rowheight,(c+1)*colwidth,(r+1)*rowheight)if not os.path.exists(cutDir+name+'/'):os.makedirs(cutDir+name+'/')num=len(os.listdir(cutDir+name+'/'))img.crop(box).save(cutDir+name+'/'+str(num)+'.png')print('Total: ',num)else:print('Wrong Parameters!!!')

下面是实际切割的样例数据,原图如下:

上面的代码能做的是对输入的下半部分【也就是主体图像数据】部分进行切割,在调用上面的代码之前,需要的操作如下:

#截取文字
box=(120,3,177,22)  #(左上角坐标,右下角坐标)
res=img.crop(box)
res.save('text.jpg')
res.show()
#截取主体图像数据
box=(0,33,293,190)  #(左上角坐标,右下角坐标)
res=img.crop(box)
res.save('image.jpg')
res.show()

其中里面的切割参数是经过我的尝试之后得出来的,不是绝对固定的,坐标偏差1、2都是可以的,可以根据自己的喜好进行实际的调整,经过上面的切割结果如下。

文本数据部分:

图像数据部分:

之后,我们就可以针对image.jpg也就是主体的图像数据内容进行切割处理,结果如下所示:

之后就可以对自己爬取得到的所有数据按照上面的切割处理方式进行同样的处理操作了。完成上述工作之后,我们就可以着手创建自己的数据集了,验证码的识别其实本质上只是一个图像的分类任务,既然是分类,我们就需要知道一开始一共有多少个类别,这里我们搜集出来了一共有 80 个类别,具体类别名称如下所示:

打字机
调色板
跑步机
毛线
老虎
安全帽
沙包
盘子
本子
药片
双面胶
龙舟
红酒
拖把
卷尺
海苔
红豆
黑板
热水袋
烛台
钟表
路灯
沙拉
海报
公交卡
樱桃
创可贴
牌坊
苍蝇拍
高压锅
电线
网球拍
海鸥
风铃
订书机
冰箱
话梅
排风机
锅铲
绿豆
航母
电子秤
红枣
金字塔
鞭炮
菠萝
开瓶器
电饭煲
仪表盘
棉棒
篮球
狮子
蚂蚁
蜡烛
茶盅
印章
茶几
啤酒
档案袋
挂钟
刺绣
铃铛
护腕
手掌印
锦旗
文具盒
辣椒酱
耳塞
中国结
蜥蜴
剪纸
漏斗
锣
蒸笼
珊瑚
雨靴
薯条
蜜蜂
日历
口哨

整理创建好的数据集如下所示:

一共有80个子文件夹,每个子文件夹里面存放的是一个类别的数据,为了方便模型的计算,这里使用数字【文本类别对应的索引值】来标识不同的类别,下面简单看几个类别的数据。

0类:

5类:

52类:

等。。。。。。

三、模型搭建

完成了基础数据集的准备和处理工作后就可以进行神经网络模型的搭建工作了,这里我们主要使用了lenet、vgg、resnet几种模型,其他的模型也可以按照同样的形式进行组织,代码设计的很灵活,可以自主地进行替换处理。下面是建模部分核心代码:

def resnetModel(num_classes,deep=18,h=16,w=10,way=1):'''resnet 模型'''if deep==18:model=ResnetBuilder.build_resnet_18((way, h, w), num_classes)elif deep==34:model=ResnetBuilder.build_resnet_34((way, h, w), num_classes)elif deep==50:model=ResnetBuilder.build_resnet_50((way, h, w), num_classes)model.compile(optimizer='sgd',loss='categorical_crossentropy',metrics=['accuracy'])print(model.summary()) return modeldef vggModel(num_classes,epochs,x_train,h=16,w=10,way=1):'''VGG-16模型'''print('x_train.shape: ',x_train.shape)input_shape=(h,w,way) model=Sequential()  model.add(Conv2D(64,(3,3),strides=(1,1),input_shape=input_shape,padding='same',activation='relu',kernel_initializer='uniform'))  model.add(Conv2D(64,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))  model.add(MaxPooling2D(pool_size=(2,2)))  model.add(Conv2D(128,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))  model.add(Conv2D(128,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))  model.add(MaxPooling2D(pool_size=(2,2)))  model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))  #512model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))  model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))  model.add(MaxPooling2D(pool_size=(2,2))) model.add(Flatten())  model.add(Dense(1024,activation='relu'))  #4096model.add(Dropout(0.5))  model.add(Dense(1024,activation='relu'))  model.add(Dropout(0.5))  model.add(Dense(num_classes,activation='softmax'))  model.compile(loss='categorical_crossentropy',optimizer='sgd',metrics=['accuracy'])  print(model.summary()) return modeldef selfModel(num_classes,epochs,x_train,h=16,w=10,way=1):'''自定义基础模型 sparse_categorical_crossentropy'''print('x_train.shape: ',x_train.shape)input_shape=(h,w,way) model = models.Sequential([layers.Conv2D(64, (3, 3), padding='same', activation='relu', input_shape=input_shape),layers.MaxPooling2D(),  # 19 -> 9layers.Conv2D(64, (3, 3), padding='same', activation='relu'),layers.MaxPooling2D(),  # 9 -> 4layers.Conv2D(64, (3, 3), padding='same', activation='relu'),layers.MaxPooling2D(),  # 4 -> 2layers.GlobalAveragePooling2D(),layers.Dropout(0.25),layers.Dense(256, activation='relu'),layers.Dense(num_classes, activation='softmax'),])model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['accuracy'])print(model.summary())return modeldef main(dataDir='dataset/',nepochs=100,h=66,w=66,way=3,deep=18,flag='self',resDir='result/self/'):'''主函数'''if not os.path.exists(resDir):os.makedirs(resDir)X,y=dataHelper.loadDataset(dataDir=dataDir,h=h,w=w)X=preProcess(X)y,num_classes=oneHotEncode(y)#数据集分割X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.30,random_state=7)#模型定义初始化if flag=='self':model=selfModel(num_classes,nepochs,X_train,h=h,w=w,way=way)elif flag=='vgg':model=vggModel(num_classes,nepochs,X_train,h=h,w=w,way=way)else:model=resnetModel(num_classes,deep=deep,h=h,w=w,way=way)# 当标准评估停止提升时,降低学习速率reduce_lr = ReduceLROnPlateau(verbose=1)history = model.fit(X_train,y_train,epochs=nepochs,validation_data=(X_test, y_test),callbacks=[reduce_lr])resHandle(history,resDir,model,X_test,y_test)print('Finished.....................................................')

我们的模型训练工作在GPU上进行,下面是部分训练输出截图:

基于GPU的训练速度还是非常快的,我尝试在CPU环境里面跑一下,发现真的是很慢,而且电脑卡到了爆炸,我们接下来看一下对应模型的实验结果。每个模型对应的结果文件示例图如下所示:

以resnet-34为例,展示其训练过程可视化曲线:

我们原始采集的数据量并不大,对于模型的训练有一定的影响,这个主要是考虑到不想对12306网站造成过大的压力,这里可以根据自己的需要尽心调整。

四、模型识别预测与可视化调用

完成了模型的训练工作后,我们就得到了可以使用的离线模型文件,之后想要对图像进行识别就可以直接加载离线模型文件进行识别预测了,为了使得我们的使用更加直观方便,这里编写了简单的界面工具来辅助进行预测分析,核心代码如下:

def upload_image():'''上传图像'''try:file_path=filedialog.askopenfilename()uploaded=Image.open(file_path)uploaded.thumbnail(((top.winfo_width()/2.25),(top.winfo_height()/2.25)))im=ImageTk.PhotoImage(uploaded)sign_image.configure(image=im)sign_image.image=imlabel.configure(text='')executeButton(file_path)except:passupload=Button(top,text=u"点击上传图像",command=upload_image,padx=10,pady=5)
upload.configure(background='#63B8FF', foreground='#364156',font=('arial',20,'bold'))
upload.pack(side=BOTTOM,pady=50)
sign_image.pack(side=BOTTOM,expand=True)
label.pack(side=BOTTOM,expand=True)
heading = Label(top, text=u"12306验证码识别机器人",pady=20, font=('arial',30,'bold'))
heading.configure(background='#40E0D0',foreground='#364156')
heading.pack()
top.mainloop()

使用样例如下:

后台输出如下:

自己本地测试了几百张图片,识别的精度还是很高的,能够满足自动识别的需求。

作者:沂水寒城,CSDN博客专家,个人研究方向:机器学习、深度学习、NLP、CV

Blog: http://yishuihancheng.blog.csdn.net

赞 赏 作 者

更多阅读

2020 年最佳流行 Python 库 Top 10

2020 Python中文社区热门文章 Top 10

5分钟快速掌握 Python 定时任务框架

特别推荐

点击下方阅读原文加入社区会员

基于深度学习的图标型验证码识别系统相关推荐

  1. 基于深度学习的图标型验证码识别系统(包含完整代码、界面)

    深度学习应用于图像处理领域应该说有很长一段时间了,相关的研究成果也有很多的积累了,从项目和实践入手是我觉得的最好最快速有效的学习手段,当下很多主流的验证码识别系统大都是基于神经网络设计开发而来的,在处 ...

  2. 基于深度学习的花卉检测与识别系统(YOLOv5清新界面版,Python代码)

    摘要:基于深度学习的花卉检测与识别系统用于常见花卉识别计数,智能检测花卉种类并记录和保存结果,对各种花卉检测结果可视化,更加方便准确辨认花卉.本文详细介绍花卉检测与识别系统,在介绍算法原理的同时,给出 ...

  3. 基于深度学习的水果检测与识别系统(Python界面版,YOLOv5实现)

    摘要:本博文介绍了一种基于深度学习的水果检测与识别系统,使用YOLOv5算法对常见水果进行检测和识别,实现对图片.视频和实时视频中的水果进行准确识别.博文详细阐述了算法原理,同时提供Python实现代 ...

  4. 【camera】基于深度学习的车牌检测与识别系统实现(课程设计)

    基于深度学习的车牌检测与识别系统实现(课程设计) 代码+数据集下载地址:下载地址 用python3+opencv3做的中国车牌识别,包括算法和客户端界面,只有2个文件,surface.py是界面代码, ...

  5. 【毕业设计_课程设计】基于深度学习网络模型训练的车型识别系统

    文章目录 0 项目说明 1 简介 2 模型训练精度 3 扫一扫识别功能 4 技术栈 5 模型训练 6 最后 0 项目说明 基于深度学习网络模型训练的车型识别系统 提示:适合用于课程设计或毕业设计,工作 ...

  6. 《智能步态识别门禁系统》,基于深度学习的多人步态识别系统

    本文章仅仅提供一种自认为比较科学的方式去实现多人步态识别,如果对多人步态识别感兴趣,却又不知道如何实现的话,这篇文章将会有莫大的帮助.以下方法作者皆实验过是可行的方案.(训练集124人,准确率96%, ...

  7. 基于深度学习的高精度交警检测识别系统(PyTorch+Pyside6+YOLOv5模型)

    摘要:基于深度学习的高精度交警检测识别系统可用于日常生活中检测与定位交警目标,利用深度学习算法可实现图片.视频.摄像头等方式的交警目标检测识别,另外支持结果可视化与图片或视频检测结果的导出.本系统采用 ...

  8. 基于深度学习的高精度苹果检测识别系统(Python+Pyside6)

    摘要:基于深度学习的高精度苹果检测识别系统可用于日常生活中来检测与定位苹果目标,利用深度学习算法可实现图片.视频.摄像头等方式的苹果目标检测识别,另外支持结果可视化与图片或视频检测结果的导出.本系统采 ...

  9. 基于深度学习的高精度塑料瓶检测识别系统(PyTorch+Pyside6+YOLOv5模型)

    摘要:基于深度学习的高精度塑料瓶检测识别系统可用于日常生活中或野外来检测与定位塑料瓶目标,利用深度学习算法可实现图片.视频.摄像头等方式的塑料瓶目标检测识别,另外支持结果可视化与图片或视频检测结果的导 ...

最新文章

  1. 常州一院有全消化道的机器人的_【商务对接】昆山智能机器人及成套装备协会链接京东和智能制造...
  2. 马斯克公布火星太空船最新照片:施工已达最后一步,10月有望正式推出
  3. altium designer 去掉原理图右下角的标签栏
  4. 多个服务器数据互通_5月23日部分服务器数据互通公告!
  5. Java日期格式转换
  6. puppet(1.1-1.6)
  7. HeadFirst设计模式之观察者模式学习
  8. 流量管理的7大技术流派
  9. 利用IDLE对 dem进行批量拼接处理
  10. atitit.java给属性赋值方法总结and BeanUtils 1.6.1 .copyProperty的bug
  11. 土壤因子-中国和世界土壤因子数据说明和下载链接
  12. 线性代数-向量空间-基向量定义
  13. Java使用iTextPDF生成PDF文件
  14. 一篇文章搞懂数据仓库:四种常见数据模型(维度模型、范式模型等)
  15. 第十三届蓝桥杯模拟赛第二期JAVA组个人题解
  16. python 筛选重复数据和不重复数据_[Python] Pandas 对数据进行查找、替换、筛选、排序、重复值和缺失值处理...
  17. String求求你别秀了
  18. redis入门教程详解
  19. 与虫子尾交3d动画网站_这六款好用的3D建模软件,总有一款是你想要的!
  20. unturned服务器修改物品,不一样的批处理-用批处理做的Unturned服务器部署工具(开服器)!...

热门文章

  1. 写给学生看的系统分析与验证笔记(七)——线性时间属性(Linear-Time Properties)
  2. 测试游戏战地1配置软件,《战地1》显卡横向测试:良心真优化
  3. 李开复谷歌最后告别:遭同事难题“拷问”(图)
  4. Menu控件(Android设置选项菜单和快捷菜单)
  5. Movist Pro for mac(高清媒体播放器)
  6. FPGA 视频拼接器的输入卡
  7. 北斗三号b1c频点带宽_北斗三号导航信号的创新设计(二)
  8. XFire调用WebService接口(全国人口信息NCIIC)
  9. 人工智能:遗传算法稀布阵列天线
  10. 智能小区计算机网络系统,浅谈计算机网络系统在智能小区实现与运用.doc