简易验证码识别

前言

日常生活中有的时候会需要用到脚本来进行一些便利的操作,比如抢购某些东西之类的。而商家为了防范用脚本来进行操作,一般会使用一些防范措施。其中最常见的应该就是验证码了。

全自动区分计算机和人类的公开图灵测试(英语:Completely Automated Public Turing test to tell Computers and Humans Apart,简称CAPTCHA),俗称验证码,是一种区分用户是计算机的公共全自动程序。

现在的验证码越来越多,比如滑动滑块让你拼图的、直接给你手机发短信的等,这篇博客并不打算涉及这些比较复杂的,只是简单介绍一下简单的验证码以及如何去使用代码来实现简单的验证码识别。

验证码处理

验证码的处理一般分成去噪、灰度化、二值化这几步。接下来的步骤中使用Python进行举例,并且使用Python的PIL的Image模块来进行处理。

去噪

计算机大多采用RGB三原色,而一般的验证码会用到8位来代表颜色,也就是有28=256种可能。在这一步,我们对每个像素进行这样的处理:取以它为中心的3x3的区域中所有点的RGB均值作为它的值,当然也可以用别的规则。

灰度化

这个是直接有公式的,我在网上看到比较流行的是这样的:Gray = (R*299 + G*587 + B*114 + 500) / 1000

二值化

这个就更简单了,默认情况下,值大于127的像素点被设置为白色,其余像素点设置为黑色。当然你也可以通过统计的数据来得出应该取什么值比较好。

Python代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from PIL import Image

img = Image.open('test.jpg')
# 灰度化
image = img.convert('L')
# 二值化
standard = 127
pixels = image.load()
for x in range(image.width):
for y in range(image.height):
if pixels[x, y] > standard:
pixels[x, y] = 255
else:
pixels[x, y] = 0

这样一张符合要求的黑白图片我们就准备好了。

验证码识别

这里我用的是著名的tesseract库,一个OCR识别库。在Mac上只需要brew install tesseract就安装好了。在linux上需要三条命令:

1
2
3
sudo apt-get update
sudo apt-get install tesseract-ocr
sudo apt-get install libtesseract-dev

而Windows上你需要手动去下载,然后在写代码的时候还需要加入特别的路径。

安装完了这个库之后,需要去下载Python对这个库的封装,好在这里比较简单:pip3 install pytesseract。接下来只需要一句话代码就可以实现了:

1
2
3
4
pytesseract.image_to_string(image)

# for windows
pytesseract.pytesseract.tesseract_cmd = 'C:\Program Files (x86)\Tesseract-OCR\tesseract.exe

如果你是Windows用户,记得指定位置,否则会报不存在的错。

然后我这边用了这个并不能识别,识别出来的结果是一个空字符串,然后我上网查阅了一下资料,发现其实这个库还使用了不同的分页模式,所以只需要指定一下模式即可。

1
2
testdata_dir_config = '--psm 13'
result = pytesseract.image_to_string(img, config=testdata_dir_config)

到这里,最简单的图像识别就完成了。

自主训练

其实我之前的只需要一句话就可以得到结果,然后我写完脚本的第二天网站就把验证码换掉了…..这次的验证码在二值化之后大概长这样:

image-20200211194554947

也就是需要我们输入“8”来作为答案。显然对于这种tesseract也束手无策了,这个时候就需要我们自主去训练了。

自主训练的简单步骤如下:

  1. 先准备好你需要其训练的图片,比如上面的那张图片。
  2. 让tesseract自动识别
  3. 识别完成后你需要告知它正确结果
  4. 生成数据库,之后根据这个数据库就可以来提高准确率了。

首先进行第一步,准备好图片。我这里准备了大概200张图片,但是很遗憾的是,tesseract不直接支持jpg图片,只支持tiff格式的,也就是我们需要首先把这200张图片合成为一张大的tiff图片。这里提供一个工具来进行合并tiff这个操作:https://sourceforge.net/projects/vietocr/,是用Java写的,所以需要本机有Java环境。我们还需要一个办法来把图片从jpg转化成tiff,这里提供一个方法:

1
2
3
4
5
6
7
from PIL import Image
import os

for filename in os.listdir():
if filename.endswith(".jpg"):
image = Image.open(filename)
image.save(filename[:-4] + ".tif")

这样我们就把这200张图片完成了第一步操作。

接下来的操作因为有了网格线,失败了,详情可以参照下面这个博客

https://www.cnblogs.com/xpwi/p/9604567.html