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进行验证码识别,亲身感受本文方法的实用性。