Tesseract-OCR 4.1 提升识别率【图像二值化】

5,065 阅读3分钟

前言

Tesseract在执行OCR之前已经在内部先进行了各种图像处理操作(使用Leptonica库)。通常情况下,这样操作就已经足够了,但是OCR的识别场景复杂,不可避免的会碰到识别准确度不够的情况。
有各种原因会导致Tesseract识别率不高。这里我推荐一种方法,图像二值化 能够帮助你显著提高识别精度,但是如果你要识别的图像是一个并不常用的字体,或者是一个新的语言,那么就必须要训练才行。

简介

Python实现图像二值化的方法有很多,第三方库有 OpenCVMatlabPillow 等等,本章将浅谈使用Pillow(PIL)库 实现二值化的效果。
右图为二值化效果

sausageman.jpg binaryzation.jpg

基础知识扫盲

什么是二值化?

图像二值化( Image Binarization)就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的 黑白效果 的过程。

为什么要二值化?

因为 tesseract-ocr 识别 白底黑字 的图像,准确率是最高的!

什么是Pillow库?

PIL(Python Imaging Library) 是一个 Python 图像处理库,但已经停止更新了。Pillow 是一个对 PIL 友好的分支,Pillow 是 Python3 最常用的图像处理库,由于PIL仅支持到Python 2.7,加上年久失修,于是一群志愿者在PIL的基础上创建了兼容的版本,名字叫Pillow, 支持最新Python 3.x,又加入了许多新特性,因此,我们可以直接安装使用Pillow。如果安装了Anaconda,Pillow就已经可用了。

程序实现(Python3.x)

环境准备

  1. 安装pillow库

    打开cmd,输入安装命令。

pip install pillow

  1. 导包 Pillow库安装成功后,导包时要用PIL来导入,而不能用pillow或Pillow。
    Image 是 Pillow 最常用的类,导入 Image 模块。然后使用 Image 类中的 open、convert 等函数

from PIL import Image

代码实现

  1. 使用Image模块中的 open 函数打开一张图片

from PIL import Image
img = Image.open('sasusageman.jpg')

  1. 使用Image模块中的 convert 函数转换图片模式

Img = img.convert('L') 图片有很多模式,我们选择使用"L",参考:Pillow官方文档

image.png 3. 自定义灰度界限,调整阈值,产出二值化图片

threshold值 需要测试人员自行调整
同一张图片,不同阈值,teseract-ocr识别出来的值也是不同的。可以使用for循环range(256)查看不同阈值的识别效果,最后选取一个你认为最佳的阈值。

# 设定阈值
threshold = 69
table = []
for i in range(256):
    if i < threshold:
        table.append(1)
    else:
        table.append(0)
# 图片二值化
photo = Img.point(table, '1')
# 最后保存二值化图片
photo.save("binaryzation.jpg")
  1. 识别二值化图片

先上代码,看不懂的点这里

import pytesseract  
text = pytesseract.image_to_string(Image.open('binaryzation.jpg'),lang='eng')  
actualname = text.strip()  # 清除字符串前后空格
print(actualname)

先识别 未进行二值化 的图片,可以看到控制台输出为空,tesseract-ocr识别不出来。 sausageman.jpg image.png 再识别 二值化 图片,我这里写了个for循环,可以看到阈值为69的时候,tesseract-ocr识别出了“SAUSAGE MAN” binaryzation.jpg

image.png 5. 完整代码,仅供参考

from PIL import Image
import pytesseract
expectname='SAUSAGE MAN' # 预期值
img = Image.open('sasusageman.jpg')  # 打开图片

# 模式L”为灰色图像,它的每个像素用8个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。
Img = img.convert('L')

# 自定义灰度界限,大于这个值为白色,小于这个值为黑色
for thr in range(256):
    threshold = thr
    table = []
    for i in range(256):
        if i < threshold:
            table.append(1)
        else:
            table.append(0)
    # 图片二值化
    photo = Img.point(table, '1')
    photo.save("binaryzation.jpg")
    text = pytesseract.image_to_string(Image.open('binaryzation.jpg'),lang='eng')
    actualname = text.strip()

    if actualname == expectname:   # 如果 实际值 等于 预期值 则打印成功,跳出循环
        print(f'阈值为: {thr} 时,OCR识别成功!!结果为:',expectname)
        break
    else:
        print(f'阈值为: {thr} 时,识别失败!结果为:',actualname)