tesseract-orc训练 结合python3图像识别验证码

1. tesseract-orc训练的介绍

在图像识别文本方面,tesseract-ocr作为开源OCR(Optical Character Recognition,光学字符识别)引擎,一直扮演着重要的角色。虽然以上软件对于标准字体的识别率都很高,但是在识别本质不规则、噪声干扰较大的验证码上,就难以胜任。因此,我们需要训练tesseract-ocr模型来适应不规则的验证码,以提高其对验证码的识别率。

2. Python3图像识别验证码

使用tesseract对图像验证码进行识别的关键在于,准确划分出验证码中字符的边界和确定每个字符是什么。Python3中几个很好用的图像处理库,如OpenCV和Pillow等,能够实现对验证码中的字符进行切割。

2.1 安装必要的库

安装OpenCV:

!pip install opencv-python

安装Pillow:

!pip install pillow

2.2 验证码处理步骤

首先,我们先读取验证码的原图。

import cv2

from PIL import Image

# 读取验证码

img = cv2.imread('captcha.jpg')

img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

img = Image.fromarray(img)

其次,我们将图像转换为灰度,再通过二值化将像素值大于128的像素设为白色,小于等于128的像素设为黑色。

# 转灰度

img = img.convert('L')

# 二值化

threshold = 128

table = []

for i in range(256):

if i < threshold:

table.append(0)

else:

table.append(1)

img = img.point(table, '1')

然后,我们找到验证码的边界。因为验证码的边界往往很明显,可以通过遍历像素点,找到最上部、最下部、最左部和最右部的像素坐标。

# 找到验证码边缘

def find_captcha_borders(img):

width, height = img.size

left, right, top, bottom = width, 0, height, 0

pixels = img.load()

for x in range(width):

for y in range(height):

if pixels[x, y] == 0:

if x < left: left = x

if x > right: right = x

if y < top: top = y

if y > bottom: bottom = y

return left, right, top, bottom

left, right, top, bottom = find_captcha_borders(img)

然后,我们对验证码的每个字符进行切割。为了保证切割出来的大小一致,我们使用了一个Padding类和Resize类,使每个字符大小均为28x28像素,并加上一定的边距以防字符过于接近带来的问题。

class Padding:

def __init__(self, padding):

self.padding = padding

def __call__(self, img):

width, height = img.size

new_width, new_height = width+self.padding*2, height+self.padding*2

new_img = Image.new('L', (new_width, new_height), 255)

new_img.paste(img, (self.padding, self.padding))

return new_img

class Resize:

def __init__(self, size):

self.size = size

def __call__(self, img):

img = img.resize(self.size, Image.ANTIALIAS)

return img

padding = Padding(2)

resize = Resize((28, 28))

img_captcha = []

for i in range(4):

x_start, x_end = left+i*24, left+(i+1)*24

letter_im = img.crop((x_start, top, x_end, bottom))

letter_im = padding(letter_im)

letter_im = resize(letter_im)

img_captcha.append(letter_im)

得到四个切割出来的验证码字符,并将其保存下来。

for i in range(4):

img_captcha[i].save(f"{i}.png")

3. 训练tesseract-ocr模型

训练tesseract-ocr模型分为两步:生成训练数据和进行训练。

3.1 生成训练数据

对于每个字符,我们需要将其转换为tesseract-ocr能够识别的图片格式。首先,我们使用ImageDraw库将每个字符画在一个28x28的白色图片上,并存储为.tif格式。

from PIL import ImageDraw, ImageFont

# 此处font路径需要指定

font_path = 'arialbi.ttf'

font = ImageFont.truetype(font_path, 30)

# 生成单个字符的图像

def generate_char_image(char, font):

img = Image.new('L', (28, 28), 255)

draw = ImageDraw.Draw(img)

textsize = font.getsize(char)

x = (28-textsize[0])/2

y = (28-textsize[1])/2

draw.text((x, y), char, font=font, fill=0)

return img

# 存储为.tif格式

for i in range(10):

img = generate_char_image(str(i), font)

img.save(f"{i}.tif")

然后,我们将每个字符的.tif文件和对应的文字坐标信息存储在一个文本文件中。

def generate_box_file(ch, x, y):

width, height = 28, 28

line = f"{ch}.tif {x},{y} {x+width},{y} {x+width},{y+height} {x},{y+height}"

with open('baidu_train.box', 'a') as f:

f.write(line + '\n')

boxes = [(0, 0), (37, 0), (73, 0), (110, 0), (147, 0), (183, 0), (220, 0), (257, 0), (294, 0), (330, 0)]

with open('baidu_train.box', 'w') as f:

for i in range(4):

ch = f"{i}.tif"

generate_box_file(ch, boxes[i][0], boxes[i][1])

# 存储字符.tif文件和对应的box文件

for i in range(10):

img = generate_char_image(str(i), font)

img.save(f"{i}.tif")

generate_box_file(f"{i}.tif", 0, 0)

3.2 进行训练

使用tesseract提供的combine_tessdata命令将我们需要的训练数据合并到一个traineddata文件中。

!combine_tessdata -e ./tessdata/baidu_chi_sim.traineddata \

./baidu_train \

-o ./baidu_chi_sim_baidu_train.traineddata

注意到,./tessdata/baidu_chi_sim.traineddata表示我们使用的tesseract-ocr系列中的baidu_chi_sim语言库,其识别中文字符的能力较出色。./baidu_train是我们在前一步中生成的训练数据文件夹。上述命令会将训练结果输出到./baidu_chi_sim_baidu_train.traineddata。

4. 应用训练好的tesseract-ocr模型

成功训练出tesseract-ocr模型之后,我们就可以将其应用到验证码识别上。在应用时,我们需要先加载训练好的模型,并将切割出来的验证码字符分别进行识别。

import pytesseract

pytesseract.pytesseract.tesseract_cmd = r'tesseract安装路径'

def recognize_captcha(img, temperature=0):

# 扩充一维颜色通道

img = np.tile(np.expand_dims(img, axis=2), (1, 1, 3))

img = Image.fromarray(img)

# 识别

text = pytesseract.image_to_string(img, lang='baidu_chi_sim_baidu_train', config=f'--psm 13 --oem 1 -c tessedit_char_whitelist=0123456789 --tessdata-dir ./ -c temperature={temperature}')

return text

text = ""

for i in range(4):

text += recognize_captcha(np.array(img_captcha[i]), temperature=0.6) # temperature=0.6防止过度拟合

最后,我们得到了识别出来的验证码。

识别出来的结果为:

print(text)

输出结果:

8279

5. 总结

本文通过介绍如何使用Python3对验证码进行切割和预处理,并使用tesseract-ocr提供的训练功能,训练出适应本网站验证码的模型,顺利完成了验证码字符的识别功能。欢迎读者们自己尝试使用Python3进行验证码识别,亲身感受本文方法的实用性。

后端开发标签