近来有朋友让老山帮忙识别验证码。在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. 使用Typescript重构axios(四)——实现基础功能:处理post请求参数

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  2. 关闭redis持久化功能

    关闭redis持久化功能持久化会报如下信息 会影响硬盘写入性能 所以没什么用 就关掉吧 修改redis配置文件,redis.conf 第115行左右. 1.注释掉原来的持久化规则 <pre> ...

  3. day7-集合

    一.定义变量是为了吹处理状态的变化,定义变量名是为了获取变量值.字符串.数字.列表.元组.字典都是为了更好的描述变量的状态1.可变不可变:变量名不变时,里面内容是否可以变化# 可变:列表.字典.修改变 ...

  4. 网络编程--UDP通讯

    UTP传输 public class Send1 { public static void main(String[] args) throws Exception { Scanner sc=new ...

  5. 03-MyBatis拦截器机制

    目录 MyBatis拦截器介绍 拦截器的使用 拦截器介绍及配置 源码分析 总结 本文转载自MyBatis拦截器原理探究 MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽 ...

  6. 创建基于OData的Web API - Knowledge Builder API, Part III:Write Model

    在前两篇文章<Part I: Business Scenario> 和<Part II: Project Setup>后,可以开始真正Model的创建. 步骤如下: 1. 创建 ...

  7. sparkSQL 简介

    一.Spark SQL的特点 1.支持多种数据源:Hive.RDD.Parquet.JSON.JDBC等.2.多种性能优化技术:in-memory columnar storage.byte-code ...

  8. pat 1077 Kuchiguse(20 分) (字典树)

    1077 Kuchiguse(20 分) The Japanese language is notorious for its sentence ending particles. Personal ...

  9. 力扣(LeetCode)移除元素 个人题解

    给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成 ...

  10. 十、CSR8670的DFU功能[补充]

    前一篇转载的博文很清楚,全面的介绍了DFU功能的实现步骤.关于DFU功能,你还需要知道以下信息: 一.image.fs,firmware,loader,psr之间的关系 图1-1 image.fs示意 ...