是我们图像处理课程的期末考试题,将报告总结一下,写成博客。
1.python、IDE、opencv的安装
2.PIL、pytesseract、ocr引擎的安装与中文库的使用
3.tesseract的字库训练
目的:在空调生产出厂时,需要将不同型号的空调机装入与表面印有空调机的型号一致的包装盒。为避免空调机型号和外包装型号不一致,需要对外包装表面字符进行检测与识别。方法:首先对外包装图像进行预处理,利用自适应阈值法对图像二值化,使用形态学操作对图像滤噪点,轮廓提取滤噪点。然后使用Tesseract对外包装进行识别,对字库进行训练,建立OCR引擎,最后验证。结果:经过验证,本文识别准确率为97.77%。结论:基于Tesseract建立的空调外包装OCR引擎可以实现生产智能化,极大提高效率,有助于数据的进一步利用。
在空调生产出厂时,需要将不同型号的空调机装入与表面印有空调机的型号一致的包装盒。为避免空调机型号和外包装型号不一致,需要对外包装表面字符进行检测与识别,为了提高工作效率,实现生产智能化。本文将使用Tesseract进行针对性的训练,设计并实现空调外包装的识别,基于Tesseract建立OCR引擎。
由于图像在拍摄时受到外界环境的影响,如光照过强、光照不足或光照不均匀,空调外包装的移动,相机本身硬件的影响,拍摄的图片,可能图片存在模糊、不清晰、光照不均匀等情况。因此,为了保证字符识别的效果,提高字符识别的准确,在识别字符之前,图像进行预处理可以尽量减少图像背景对文字区域的干扰,为之后进行字符识别做好一个很好的铺垫[1]。在对空调外包装图像进行预处理包括:读取图像、灰度化、二值化、形态学操作、轮廓提取、滤除噪点,本问的总体预处理过程如图1所示。
通过相机获取到的图像是彩色图像,将彩色图像转化为灰度图像的过程为图像灰度化处理。灰度化的方式有分量法、最大值法、平均值法、加权平均法。本文使用是OPENCV计算机计算机和视觉库中的彩色图像转灰色图像,具体用到的线性灰度变换函数是:
Gray=0.299R+0.587G+0.144*B
图像的二值化在视觉检测领域是很关键的一步,常用的二值化方法有固定阈值二值化、直方图阈值法、大津法、自适应阈值法等。空调外包装图像经常出现光照强度不同,不均匀等等情况。在使用大津法后,发现文字区域出现大量黑色区域,如图2。自适应阈值法能将文字能很好的保留下来,同时背景只留下了噪点,效果是最佳的,如图2。
自适应阈值法:它的思想不是计算全局图像的阈值,而是根据图像不同区域亮度的分布,计算其局部阈值,所以对于不同图形不同区域,能够自适应计算不同的阈值。这种局部阈值法正好解决了空调外包装图像光照不均匀影响,能很好的保留图片的信息,降低了阴影对图像的影响。
图像经过自适应二值化后,背景还留下了很多小噪点,我们可以用图像中的形态学开操作滤除一部分噪声。
开操作:先腐蚀后膨胀,它的特点是使图像的轮廓变得光滑,使狭窄的连接断开和消除毛刺、滤除噪点,同时没有明显影响图像的面积、形状,如图3。
图像经过形态学操作后,在不影响文字的形状的情况下,发现还有些许噪点无法滤掉,我们通过面积阈值法,将这些背景的噪点滤掉。
使用opencv中的findContours函数找到图像中的所有轮廓信息并进行了标记,如图4
根据轮廓的提取算的得每个轮廓的面积,再给定一个面积的阈值,将这些噪点全部变为背景,不影响字符的识别,如图5。
Tesseract是一个开源的OCR(Optical Character Recognition,光学字符识别)引擎,可以识别多种格式的图像文件并将其转换成文本,目前已支持60多种语言(包括中文)。
Tesseract最初由HP公司开发,后来由Google维护。它的精确度在1995年的测试中名列前三,其最近的目标是在准确度上再次赶超商业OCR引擎[2]。用户可以用自己的样本来训练新的字库,本文用Tesseract为基础,完成了空调外包装的字符识别。
Tesseract在识别过程中采用了集束搜索算法与K近邻算法。集束搜索是一种启发式图搜索算法, 具有较好的时间和空间复杂度。Tesseract运用集束 搜索算法对字符进行分割。K近邻算法法是计算一个点与样本空间所有点之间的距离,取出与该点最近的k个点,统计得出这k个点里面所属分类比例最大的点。Tesseract使用K近邻算法来返回最匹配的识别样本[3]。
图5展示了基于Tesseract的空调外包装字符的OCR训练步骤。
(1)制作Tiff训练样本。准备一定量的样本,本文准备了6张图片做样本,将其转为.tiff格式,使用jTessBoxEditor生成.font.exp0.tif文件
(2)生成BOX文件。使用tesseract在命令行中执行tesseract char.font.exp0.tif char.font.exp0 batch.nochop makebox
,生成char.font.exp0.box。
(3)使用jTessBoxEditor进行字符矫正。修改左侧文字识别错误的过程,并且可以通过Merge、Split、Insert、Delete来合并、分离、添加、删除识别框,如图6所示。
(4)使用tesseract生成.tr训练文件。使用tesseract在命令行中执行tesseract char.font.exp0.tif char.font.exp0 nobatch box.train
,生成char.font.exp0.tr文件。
(5)计算字符集,生成Unicharset文件。Unicharset文件包含了Tesseract引擎训练后可以识 别的每个字符的信息,它是Tesseract新字库语言的一部分。在命令行中执行unicharset_extractor char.font.exp0.box
,生成unicharset文件。
(6)生成shape文件。执行命令:shapeclustering -F font_properties -U unicharset -O char.unicharset char.font.exp0.tr
生成shapetable 和 char.unicharset 两个文件
(7)生成聚字符特征文件。执行命令:
mftraining -F font_properties -U unicharset -O char.unicharset char.font.exp0.tr
。生成inttemp、pffmtable、shapetable和char.unicharset四个文件。
(8)生成字符正常化特征文件。执行命令:
cntraining char.font.exp0.tr
。
(9)合并训练文件生成的.traineddata。通过命令combine_tessdata char
合并所有文件生成字典文件。
(1)python3.6。Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的、大型项目的开发。
(2)python-opencv。OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
(3)Pytesseract模块。是使用python语言封装,以光学字符识别引擎Tesseract-OCR为底层接口模块。Pytesseract模块应用十分灵活,支持PIL读取各种传统的图像文件,同时Pytesseract还支持OPENCV图像或者Numpy数组对象,使得图像处理和识别的过程更加灵活。
(1)采用Tesseract-OCR官方给的中文库,直接进行识别的效果并不好,很多字符误识别、、多识别、漏识别的情况比较严重,测试结果如图7。
(2)首先在python环境下使用opencv将图像预处理后,得到一张图像字符明显,背景干净的图片。再通过Pytesseract调用训练好的字典文件进行字符的识别。训练结果,如图8所示。
为验证该方法的有效性和准确率,本文使用了45张字符角度不同,光照不均匀等图片进行识别测试。实验结果显示44张图能识别完全正确,另有1张图片识别结果有误。准确率为97.77%
。
识别结果有误的图像的测试结果如图9所示。将在‘内’与‘机’之间多识别了一个‘室’。出现这种情况的原因(1)相机未将字符拍摄完整。(2)Tesseract软件本身对字体的判断有不准确性。(3)本文所采用的训练样本不足,导致的识别判断率低。
本文通过读取图像,经过灰度化、二值化、形态学操作、去噪点后使用Tesseract将空调外包装的字符较干净的提取出来。
从识别效果,最后的准确率来看,本引擎经过词典以及模糊字 校正之后,总体识别率为97.77%。识别率相对较高,但是仍然有误识别的情况,在不改变其他情况,通过增加样本的训练,识别率会逐渐增加。
import cv2 as cv
import numpy as np
from PIL import Image
import pytesseract as tess
# 传入二值化的图像
def contour_demo(image):
image = cv.bitwise_not(image)
contour_image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
contours, heriachy = cv.findContours(image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for i, contour in enumerate(contours):
# cv.drawContours(contour_image, contours, i, (0, 0, 255), 2) # 2->-1 填充
x, y, w, h, = cv.boundingRect(contour)
area = cv.contourArea(contour)
rect = cv.boundingRect(contour)
cv.rectangle(contour_image, (x, y), (x+w, y+h), (0, 0, 255), 2)
print(area)
print(rect)
if area < 35:
# roi = contour_image[y:y+h, x:x+w]
roi = 0
# contour_image[y:y+h, x:x+w] = roi
image[y:y+h, x:x+w] = roi
print(i)
cv.imshow("contour_image", contour_image)
image = cv.bitwise_not(image)
cv.imshow("image", image
textImage = Image.fromarray(image)
# 识别
txt = tess.image_to_string(textImage, lang='char')
print("识别结果为:\n", txt)
def image_handle():
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
cv.imshow("grayscale", gray)
ret, bin = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow("OTSU", bin)
adapt_bin = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 255, 30)
cv.imshow("adaptive threshold", adapt_bin)
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (2, 2))
dilate_image = cv.dilate(adapt_bin, kernel)
cv.imshow("dilate_image", dilate_image)
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (2, 2))
erode_image = cv.erode(dilate_image, kernel)
cv.imshow("erode_image", erode_image)
contour_demo(erode_image)
print("外包装表面字符:")
src_image = cv.imread("G:\\Python\\lesson_test\\6.jpg") # 6 15 20 22
cv.imshow("src", src_image)
src = src_image[100:800, 0:1280]
image_handle()
cv.waitKey(0)
cv.destroyAllWindows()