近来有朋友让老山帮忙识别验证码。在github上查看了下,目前开源社区中主要流行以下几种验证码识别方式:

  1. tesseract-ocr模块:

    这是HP实验室开发由Google 维护的开源 OCR引擎,内置传统模式识别方法和现代深度神经网络算法
  2. 采用深度学习网络

    通常是基于CNN网络,通过captcha等验证码生产器自动生产训练集,通常对生成器内置的验证码类型有极高的识别度。

需求中需要识别的验证码来自特定网站 http://fota.redstone.net.cn/,使用通用的验证码识别模块识别准确率比较低,因此很可能需要自己创建数据集进行训练。

查看数据

无论如何,都必须看到数据才能处理数据。因此我们通过对网站进行请求生成验证码集:

import os, requests
from time import sleep
# 文件保存路径
path = 'images'
# 验证码网站
url = 'http://fota.redstone.net.cn/index.php/home/index/get_verify.html'
# 图片数目
number = 100 os.makedirs(path, exist_ok=True) # 请求并保存图片
for i in range(number):
sleep(0.1)
r = requests.get(url)
with open(f'{path}/{i}.jpg', 'wb') as f:
f.write(r.content)

观察数据:

通过观察数据,发现这些验证码基本有这几个特点:

  1. 需要识别的是4个数字;
  2. 数字字体有多种风格,数字有一定旋转,数字之间有可能交叉;
  3. 背景中有许多小字;
  4. 与数字相同的颜色的间断粗线穿过数字,对数字识别造成影响。

标注

按通常的图像处理方式,可以通过形态学去除小字,然后转换成灰度图进行后期训练处理。但老山正好最近涉及些图像识别的深度学习方法,于是在想,是否能直接通过yolov3,faster-rcnn等物体检测模型来识别验证码呢?

要按物体检测方式识别验证码,首先要有标注数据集,这里采用modelarts内置的标注进行标注。

  1. 先将图像传到obs中

2. 在modelarts上点击创建数据集

3. 按要求填写列表,选择物体检测,(标签可以在此处添加,也可以在标注的时候添加),然后创建数据集

4. 点击进入已创建的数据集,然后就可以进行图片标注了

5. 这里不得不提的是智能标注,这也成为后面老山深深的怨念;在标注图片超过20的时候,就可以启用智能标注,可以自动识别物体,减少标注时间

运行10多分钟后,标注就完成了,可以看到,标注的效果是真好

在已标注集仅为20的情况下,虽然还有不少需要更改的地方,但效果还是可用的;但标注集达到100时,效果就可以达到95%以上的准确率;由于智能标注使用的算法无非是常见的物体检测方法的一种,如此好的效果让我一度产生“标注数据集100就可以得到很好的训练效果“的幻觉。

训练

1. 标注完成后,点击数据集右侧的发布按钮,然后你在数据集输出路径里很深的路径里找到生成的标注的xml文件

2. 如果需要追加待标注数据集,可以对输入位置对应的obs路径中添加图像,然后在标注页面里点击”同步数据源“

3. 第一期标注了200张已标注图片,于是老山自信满满的打开训练作业,创建了faster-rcnn的训练作业

话说训练作业不用写代码还是很方便的,尤其适合前期尝试模型,让大家对模型能达到的准确率做个初步的判断,避免在一个不适合的模型中花费太多的时间。

在目前物体检测中,faster-rcnn、yolov3还有retinanet都是比较主流的模型。先尝试了faster-rcnn,mAP值只有0.2,然后是yolov3,mAP是0.29,用了retinanet,mAP值到了0.58。

老山于是便有了怨念,智能标注用啥模型啊,不还得是主流目标检测模型吗,为什么标注20张图就能有如此高的准确率,老山200张图训练的模型效果都不如他。尤其是前面faster-rcnn和yolov3的mAP值都如此的低,让老山一度很灰心,还好retinanet的效果还不错,可以继续调×教。

虽然老山调不出智能标注使用的模型,但模型复制嘛,不只是复制模型一种方法而已,把模型的结果集作为老山模型的训练集,只要数量足够大,也可以训练出相近的模型。于是就一口气又生成了800张图片,然后用已标注的200张图片做智能标注。由于标注结果十分准确,大部分标注结果就直接确认了,标注了800张图片,只花了1个多小时,效率可以说是杠杠的!

然后使用这1000个样本的数据集杀了回来,mAP值达到了0.96!看来数据集的大小非常重要,这还只是用了默认参数。

在观察日志的时候,发现右上角有个修改,点进去发现可以基于训练模型基础继续训练,同时发现预制算法旁边有个算法详情,里面描述了算法的运行参数。考虑到上次运行早停了,看了一通参数的含义,最后只改了decay_patience这个参数。

又跑了一遍,这次mAP又小小的提高到了0.97!但这些都只是个摸不着的结果,老山决定部署下看下结果

先在训练作业结果中点击创建模型,把名称改成有意义的,其他参数保持不变就好,

部署

等待模型状态正常后,点击右边的部署

等到部署完成后,点击部署任务中的预测,并上传图片,查看结果

许多结果看起来还可以

但也有不少结果没有预测正确

为此统计下这1000张图片的预测结果(老山这里比较懒,并没有单独准备测试集),我们需要对这些图片进行预测。由于不可能人工上传预测,为此老山祭出了大杀器,python。

首先,我们要获取X-Auth-Token认证

import requests
import json
url = "https://iam.cn-north-1.myhuaweicloud.com/v3/auth/tokens"
headers = {"Content-Type":"application/json"}
data = {
"auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "your-username",
"password": "your-password",
"domain": {
"name": "your-domainname:normally equal to your-username"
}
}
}
},
"scope": {
"project": {
"name": "cn-north-1"
}
}
}
} data = json.dumps(data) r = requests.post(url, data = data, headers = headers)
print(r.headers['X-Subject-Token'])

data具体参数填写可网址详见https://support.huaweicloud.com/api-modelarts/modelarts_03_0004.html

程序最后获得的便是X-Auth-Token认证码。

接下来我们开始预测

config.py

X_Auth_Token = "MIIZpAYJKoZIhvcNAQcCoIIZlTCC..." # 前面获取的X-Auth-Token值
url = "https://39ae62200d7f439eaae44c7cabccf5de.apigw.cn-north-1.huaweicloud.com/v1/infers/55d5..." #在调用指南页面获取的url值

predict.py

import os
import json
from lxml import etree as ET
import requests
from config import url, X_Auth_Token
import logging
logging.basicConfig(level=logging.INFO,
format="%(asctime)s %(name)s %(levelname)s %(message)s",
handlers = [
logging.FileHandler(f"log.txt"), #生成日志文件
logging.StreamHandler()
]) # 图片(jpg文件)和标注文件(xml文件)所在位置,注意jpg和xml文件一一对应
path = 'images1000' def requestImage(filename):
'''根据图片文件利用在线服务预测结果, jsonStr'''
files = {'images':open(filename,'rb')}
headers2 = {'X-Auth-Token': X_Auth_Token}
response = requests.request("POST", url, files=files, headers=headers2)
return response.text def getImageFile(xml_file):
'''根据xml文件返回对应的图片文件'''
return os.path.splitext(xml_file)[0]+'.jpg' def getFileList(folder):
'''folder下的同名xml和jpg组成tuple,并以list返回 [(xml_file, jpeg_file), ...]'''
return [(os.path.join(folder, filename), os.path.join(folder, getImageFile(filename))) for filename in os.listdir(folder) iffilename.endswith('.xml')] def json2text(jsonStr):
'''根据预测结果jsonStr返回预测的数字'''
obj = json.loads(jsonStr)
boxes = []
for className, box in zip(obj["detection_classes"], obj["detection_boxes"]):
boxes.append([className]+[float(pos) for pos in box])
# 注意预测的box以[top, left, bottom, right]进行排序,与xml文件有点不同
boxes.sort(key = lambda x: x[2])
return ''.join([className for className, *_ in boxes]) def xml2text(xml_file):
'''根据xml_file里所有box生成list [(class_name, left, top, right, bottom), ...]'''
tree = ET.parse(xml_file)
root = tree.getroot()
boxes = []
for obj in root.findall('object'):
name = obj.find('name').text
xmlbox = obj.find('bndbox')
b = (round(float(xmlbox.find('xmin').text)), round(float(xmlbox.find('ymin').text)),
round(float(xmlbox.find('xmax').text)), round(float(xmlbox.find('ymax').text)))
boxes.append((name, *b))
boxes.sort(key = lambda x: x[1])
return ''.join([className for className, *_ in boxes]) if __name__ == "__main__":
fileList = getFileList(path)
count = 0 # 预测数目
sameCount = 0 # 预测正确数目
for xml_file, jpg_file in fileList:
# 根据图片文件在线预测结果
jsonStr = requestImage(jpg_file)
text_image = json2text(jsonStr)
# 根据标注文件获得正确结果
text_xml = xml2text(xml_file)
# 对比输出
count += 1
if text_image==text_xml:
sameCount+=1
logging.info(f"count:{count}, sameCount:{sameCount}, \
text_image:{text_image}, text_xml:{text_xml}, percent:{sameCount/count}")

运行程序结果如下

可以看到,由于在线服务使用的是CPU,预测的结果比较慢,大概5~6秒出一个结果,准确率一直不高,最后定格在75.6%。对于这个结果,老山只能说,还好是用于预测验证码,可以反复预测,预测正确的期望次数是1.3次,算是可堪一用把。

总结

当然,本文算是使用modelarts对使用物体检测算法来识别验证码做了个试探,总体结果说明这种识别验证码的方法完全是可以用的,如果后续需要继续进展的话,完全可以在以下方面进行展开:

  1. 数据集生成:

    数据集仍可以继续扩大。此时就不需要在手动标注了,老山想到一个很好的办法。生成数据集后,用智能标注的方式生成标注结果,将标注结果利用网站去验证正确与否,这样就可以无需手动,生成很好的数据集,现在智能标注免费,完全是白嫖,数据集够大时,至少能达到智能标注的水平(无限怨念)。
  2. 模型参数调节

预置模型很省心,但却看不到细节,如果想自己把握模型,可以使用开源模型来运行,老老实实的写代码调参数。如果没有GPU环境,可以使用开发环境的notebook进行开发;

3. 在本地开启服务

用在线服务功能当然省心,但如果只是为了识别验证码,这性价比就不是太高了。我们可以在预置模型的输出路径找到模型生成文件,这样就可以把模型布置在本地了。

作者:山找海味

利用modelarts和物体检测方式识别验证码的更多相关文章

  1. OpenCV学习 物体检测 人脸识别 填充颜色

    介绍 OpenCV是开源计算机视觉和机器学习库.包含成千上万优化过的算法.项目地址:http://opencv.org/about.html.官方文档:http://docs.opencv.org/m ...

  2. 人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型

    人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型 经过前面稍显罗嗦的准备工作,现在,我们终于可以尝试训练我们自己的卷积神经网络模型了.CNN擅长图像处理,keras库的te ...

  3. 如何利用AI识别未知——加入未知类(不太靠谱),检测待识别数据和已知样本数据的匹配程度(例如使用CNN降维,再用knn类似距离来实现),将问题转化为特征搜索问题而非决策问题,使用HTM算法(记忆+模式匹配预测就是智能),GAN异常检测,RBF

    https://www.researchgate.net/post/How_to_determine_unknown_class_using_neural_network 里面有讨论,说是用rbf神经 ...

  4. [Xcode 实际操作]七、文件与数据-(20)CoreML机器学习框架:检测和识别图片中的物体

    目录:[Swift]Xcode实际操作 本文将演示机器学习框架的使用,实现对图片中物体的检测和识别. 首先访问苹果开发者网站关于机器学习的网址: https://developer.apple.com ...

  5. 利用opencv进行移动物体检测

    进行运动物体检测就是将动态的前景从静态的背景中分离出来.将当前画面与假设是静态背景进行比较发现有明显的变化的区域,就可以认为该区域出现移动的物体.在实际情况中由于光照阴影等因素干扰比较大,通过像素直接 ...

  6. 第十八节、基于传统图像处理的目标检测与识别(HOG+SVM附代码)

    其实在深度学习中我们已经介绍了目标检测和目标识别的概念.为了照顾一些没有学过深度学习的童鞋,这里我重新说明一次:目标检测是用来确定图像上某个区域是否有我们要识别的对象,目标识别是用来判断图片上这个对象 ...

  7. 物体检测之FPN及Mask R-CNN

    对比目前科研届普遍喜欢把问题搞复杂,通过复杂的算法尽量把审稿人搞蒙从而提高论文的接受率的思想,无论是著名的残差网络还是这篇Mask R-CNN,大神的论文尽量遵循著名的奥卡姆剃刀原理:即在所有能解决问 ...

  8. yolo回归型的物体检测

    本弱又搬了另外一个博客的讲解: 缩进YOLO全称You Only Look Once: Unified, Real-Time Object Detection,是在CVPR2016提出的一种目标检测算 ...

  9. 转-------基于R-CNN的物体检测

    基于R-CNN的物体检测 原文地址:http://blog.csdn.net/hjimce/article/details/50187029 作者:hjimce 一.相关理论 本篇博文主要讲解2014 ...

随机推荐

  1. p1594(巨坑题!!!)

    护卫车队在一条单行的街道前排成一队,前面河上是一座单行的桥.因为街道是一条单行道,所以任何车辆都不能超车.桥能承受一个给定的最大承载量.为了控制桥上的交通,桥两边各站一个指挥员.护卫车队被分成几个组, ...

  2. 持续集成Gitlab CICD Runner&Jenkins

    目录 使用Gitlab Runner实现 再要部署的服务器上安装 gitlab runner 下载可执行文件 设置可执行权限权限 创建用户 运行服务 注册 Runner 到gitlab上找到需要用的U ...

  3. Oracle 数据库基础:数据查询与操作

    SELECT uname FROM TUser WHERE uname=‘admin’ SELECT 字段名列表 FROM 表名 WHERE 条件; 在Oracle数据库中,对象是属于模式的,每个账户 ...

  4. Feign 调用丢失Header的解决方案

    问题 在 Spring Cloud 中 微服务之间的调用会用到Feign,但是在默认情况下,Feign 调用远程服务存在Header请求头丢失问题. 解决方案 首先需要写一个 Feign请求拦截器,通 ...

  5. kafka线上滚动升级方案记录

    kafka升级方案 为什么进行kafka升级 一.修改unclean.leader.election.enabled默认值Kafka社区终于下定决心要把这个参数的默认值改成false,即不再允许出现u ...

  6. 用PHP+Redis实现延迟任务,实现自动取消订单

    简单定时任务解决方案:使用redis的keyspace notifications(键失效后通知事件) 需要注意此功能是在redis 2.8版本以后推出的,因此你服务器上的reids最少要是2.8版本 ...

  7. 极·Java速成教程 - (1)

    序言 众所周知,程序员需要快速学习新知识,所以就有了<21天精通C++>和<MySQL-从删库到跑路>这样的书籍,Java作为更"高级"的语言也不应该落后, ...

  8. 百度全景地图使用时提示flash版本过低 如何处理?

    从Chrome 69.0 版本起,Flash权限受到进一步限制,默认仅在当前浏览器会话有效.关闭Enable Ephemeral Flash Permissions ,才能看到 “Add”按钮.解决方 ...

  9. ENS中文文档系列之一 [ ENS介绍 ]

    前言 ENS中文文档是由我照ENS英文官方文档翻译而来,其中的一些内容和细节得到了ENS官方团队的指导.文档中包含 “LBB译注” 的地方是译者为了便于读者理解而进行的注释. 未来一段时间,我会在该博 ...

  10. Docker从入门到掉坑(三):容器太多,操作好麻烦

    前边的两篇文章里面,我们讲解了基于docker来部署基础的SpringBoot容器,如果阅读本文之前没有相关基础的话,可以回看之前的教程. Docker 从入门到掉坑 Docker从入门到掉坑(二): ...