def get_crop_imgs(img): """ 按照图片的特点,进行切割,这个要根据具体的验证码来进行工作. # 见原理图 :param img: :return: """ child_img_list = [] for i in range(4): x = 2 + i * (6 + 4) # 见原理图 y = 0 child_img = img.crop((x, y, x + 6, y + 10)) child_img_list.append(child_img) return child_img_list
然后就能得到被切割的 原子级 的图片元素了:
9.2 内容小结
基于本部分的内容的讨论,相信大家已经了解到了,如果验证码的干扰(扭曲,噪点,干扰色块,干扰线……)做得不够强的话,可以得到如下两个结论:
4位字符和40000位字符的验证码区别不大
纯数字。分类数为10
数字和区分大小写的字母组合。分类数为64
在没有形成 指数级或者几何级 的难度增加,而只是 线性有限级 增加计算量时,意义不太大。
10 尺寸归一
本文所选择的研究对象本身尺寸就是统一状态:6*10的规格,所以此部分不需要额外处理。但是一些进行了扭曲和缩放的验证码,则此部分也会是一个图像处理的难点。
11 模型训练步骤
在前面的环节,已经完成了对单个图片的处理和分割了。后面就开始进行 识别模型 的训练了。
整个训练过程如下:
12 素材准备
本文在训练阶段重新下载了同一模式的4数字的验证图片总计:3000张。然后对这3000张图片进行处理和切割,得到12000张原子级图片。
在这12000张图片中删除一些会影响训练和识别的强干扰的干扰素材,切割后的效果图如下:
13 素材标记
由于本文使用的这种识别方法中,机器在最开始是不具备任何 数字的观念的。所以需要人为的对素材进行标识,告诉 机器什么样的图片的内容是 1……。
这个过程叫做 “标记”。
具体打标签的方法是:
为0~9每个数字建立一个目录,目录名称为相应数字(相当于标签)
人为判定 图片内容,并将图片拖到指定数字目录中
一般情况下,标记的素材越多,那么训练出的模型的分辨能力和预测能力越强。例如本文中,标记素材为十多张的时候,对新的测试图片识别率基本为零,但是到达100张时,则可以达到近乎100%的识别率
14 特征选择
对于切割后的单个字符图片,像素级放大图如下:
从宏观上看,不同的数字图片的本质就是将黑色按照一定规则填充在相应的像素点上,所以这些特征都是最后围绕像素点进行。
字符图片 宽6个像素,高10个像素 ,理论上可以最简单粗暴地可以定义出60个特征:60个像素点上面的像素值。但是显然这样高维度必然会造成过大的计算量,可以适当的降维。
通过查阅相应的文献 ,给出另外一种简单粗暴的特征定义:
最后得到16维的一组特征,实现代码如下:
def get_feature(img): """ 获取指定图片的特征值, 1. 按照每排的像素点,高度为10,则有10个维度,然后为6列,总共16个维度 :param img_path: :return:一个维度为10(高度)的列表 """ width, height = img.size pixel_cnt_list = [] height = 10 for y in range(height): pix_cnt_x = 0 for x in range(width): if img.getpixel((x, y)) == 0: # 黑色点 pix_cnt_x += 1 pixel_cnt_list.append(pix_cnt_x) for x in range(width): pix_cnt_y = 0 for y in range(height): if img.getpixel((x, y)) == 0: # 黑色点 pix_cnt_y += 1 pixel_cnt_list.append(pix_cnt_y) return pixel_cnt_list
然后就将图片素材特征化,按照 libSVM 指定的格式生成一组带特征值和标记值的向量文件。内容示例如下:
说明如下:
对此文件格式有兴趣的同学,可以到 libSVM 官网搜索更多的资料。
15 模型训练
到这个阶段后,由于本文直接使用的是开源的 libSVM 方案,属于应用了,所以此处内容就比较简单的。只需要输入特征文件,然后输出模型文件即可。
可以搜索到很多相关中文资料 。
主要代码如下: