一、介绍
光学字符识别OCR(Optical Character Recognition)是指用计算机图像处理的方法将字符图像“翻译”成计算机文字的过程,包括图像采集、预处理(二值化、噪声去除、倾斜校正)、字符定位、字符分割、特征提取、字符分类等步骤。
二、常用方法
①统计特征字符识别:这类方法先从字符图像中提取字形,将其与事先存储的字形进行比较,将相似度最高的匹配结果作为分类结果。这类方法的匹配算法简单,具有较快的匹配速度和较高的识别率。但是这类方法对于变形、选择等改变方向字符的识别能力较弱。
②结构字符识别:该类方法首先对待识别字体进行字体结构识别,利用字符的轮廓结构特征和统计特征来确定字符的模式、基元等特征,并通过基元的排序、组合形成字符特征。该类方法需要较高的图像分辨率,以便获得清晰的图像特征结构,但是这会影响图像识别的速度。
③神经网络的识别:该类方法将提取到的字符特征向量输入神经网络进行识别。该类方法能够有效地对各种模糊字符进行正确判断,但是学习速度慢,泛化能力较弱。
④深度学习的方法:这类方法通常用深度神经网络来充当字符的特征提取器和分类器,不需要人为设计字符特征,从而减少了人为设计特征造成的不完备性,提高识别的准确率。它的缺点是要达到很好的精度,需要大数据支撑,以及更多更好的硬件支持。
三、步骤
OCR的检测分为离线训练和在线检测两个部分。
1、离线训练
离线部分一般指的是字符的训练过程,包括以下几个步骤:
①读取样本图像,并对样本中的已知字符进行区域分割,分割的单位是单个字符的包围区域。这时可以使用draw_rectangle1等算子选择出单个字符的区域。
②将分割出的区域和对应的字符名称存储在训练文件中。可以使用append_ocr_trainf算子,将字符区域存在指定的以“.trf”结尾的训练文件中。
③检查训练文件中的对应关系,即图像与字符的名称应一一对应。
④训练分类器。首先创建一个分类器,然后进行训练。可以使用create_ocr_class_mlp算子训练基于MLP的分类器,使用trainf_ocr_class_mlp算子训练基于“.trf”训练文件的分类器,得到分类器句柄OCRHandle。
⑤保存分类器。使用write_ocr_class_mlp算子保存句柄为OCRHandle的分类器,分类器的名称为以“.omc”结尾的文件。
⑥清楚分类器。
2、在线检测
在线部分的OCR指的是对字符进行检测,即分类,一般流程如下:
①读取分类器。使用read_ocr_class_mlp算子读取以“.omc”结尾的分类器文件。
②对待检测的字符进行区域分割,提取出独立的字符区域。
③使用分类器对字符区域进行分类。MLP分类器使用do_ocr_multi_class_mlp算子进行分类,返回对应的分类结果,结果形式为类别名称class和confidence。
④清除分类器。
提示:Halcon目录下的OCR文件夹中内置了许多针对数字、字母、和喷码等字符的分类器,包含对多种标准的、非中文的字符类的识别,有时可以直接调用这些分类器文件,以省去自己训练的步骤。如果要识别的字符不属于这些情况,如中文字符或者手写等特殊情况,则需要自己训练。
三、Halcon中OCR相关算子
OCR / Training Files 将字符(元组)添加到一个训练文件中 append_ocr_trainf(Character, Image : : Class, TrainingFile : ) Character:输入参数,需要训练的字符,也就是输入对应的字符的图像区域。 Image:输入参数,输入对应的字符图像,一般就是用来抠出Character的图像区域所用的原图像。 Class:输入参数,输入字符的类名(数组)(比如抠出来的区域对应的字符、数字或文字等可以作为这个图像的类名)。 TrainingFile:输入参数,输入需要保存的训练文件名,默认'train_ocr',后缀为【 .trf, .otr】。 |
OCR / Neural Nets【神经网络】 使用MLP(多层感知器)创建一个OCR分类器。 create_ocr_class_mlp( : : WidthCharacter, HeightCharacter, Interpolation, Features, Characters, NumHidden, Preprocessing, NumComponents, RandSeed : OCRHandle) WidthCharacter:输入参数,输入被分割的字符缩放到指定的宽度。默认8,建议值【1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20】,典型值范围【 4 ≤ WidthCharacter ≤ 20】。 HeightCharacter:输入参数,输入被分割的字符缩放到指定的高度。默认10,建议值【1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20】,典型值范围【4 ≤ HeightCharacter ≤ 20】。 Interpolation:输入参数,设置缩放的字符纂改模式。默认【'constant'】,列表【 'bicubic', 'bilinear'双线性, 'constant'不变, 'nearest_neighbor'邻近, 'weighted'有利的】。 Features:输入参数,默认'default' ,列表【 'anisometry'字符的不等轴(参考椭圆,单一特征); 'chord_histo'每一排运动的频率(字符高度特性); 'compactness'字符的紧凑型(单一特性); 'convexity'字符的凹凸特性(单一特性); 'cooc'点阵(参考gen_cooc_matrix一个区域中同时出现的矩阵,八个特征); 'default'等于选择了'ratio' 和 'pixel_invar'; 'foreground'在前景中的部分像素(单一特性); 'foreground_grid_16'字符像素占4×4个小方格,十六个特征; 'foreground_grid_9'字符像素占3×3个小方格,九个特征; 'gradient_8dir'字符图像的倾斜度,即对字符图像进行梯度计算。将梯度方向离散为8个方向。根据这些离散方向,将振幅图像分解为8个通道。每个通道在一个5x5的网格中提取25个样本。这些样本被用作特征(200个特征) ; 'height'字符的原始高度(参考smallest_rectangle1单一特征); 'moments_central'字符的某一时刻对应中心的矩特性,四个特征; 'moments_gray_plane'字符的某一时刻对应角度的矩特性,四个特征; 'moments_region_2nd_invar'字符的某一时刻对应的矩特性(参考moments_region_2nd_invar; 三个特征); 'moments_region_2nd_rel_invar'字符的某一时刻对应的矩特性(参考moments_region_2nd_rel_invar; 两个特征); 'moments_region_3rd_invar'字符的某一时刻对应的矩特性(参考moments_region_3rd_invar; 四个特征); 'num_connect'相连接部分的数量(参考connect_and_holes单一特征); 'num_holes'孔的数量(参考connect_and_holes连接部分和中断的数目,单一特征); 'num_runs'在某一区域高度运动的数量(单一特征); 'phi'字符方位(参考eliptic_axis椭圆的长轴对应的角度,两个特征); 'pixel'识别字符对应的灰度像素(字符宽度乘以字符高度特性); 'pixel_binary'字符(高宽)占有区域对应的灰度像素(字符宽度乘以字符高度特性); 'pixel_invar'识别(最大缩放比)字符对应的灰度像素(字符宽度乘以字符高度特性); 'projection_horizontal' 依水平方向投影所对应的灰度值,参考gray_projections; 'projection_horizontal_invar'依水平方向的最大投影比例所对应的灰度值(字符高度特征); 'projection_vertical'依垂直方向投影所对应的灰度值,参考gray_projections; 'projection_vertical_invar'依垂直方向的最大投影比例所对应的灰度值(字符高度特征); 'ratio'字符的纵横比(1个特征); 'width'字符的原始宽度(参考smallest_rectangle1单一特征)); 'zoom_factor'宽高比值(介于宽度和高度之间的特性,单一特性) 】 Characters:输入参数,设置需要匹配的字符查阅表,如(0~9、A~Z、+-*/=<>#$%&()等)默认【 ['0','1','2','3','4','5','6','7','8','9']】 NumHidden:输入参数,隐藏的MLP单元数目。默认80,建议值【1, 2, 3, 4, 5, 8, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 150】,范围【 NumHidden >= 1】。 Preprocessing:输入参数,矢量特征转换的预处理类型。默认 'none',列表【'canonical_variates', 'none', 'normalization', 'principal_components'】。 NumComponents:输入参数,预处理参数:变换特征个数,即匹配字符的数量(当Preprocessing='none', 'normalization'时此参数无效)。默认10,建议值【 1, 2, 3, 4, 5, 8, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100】,范围【NumComponents >= 1】。 RandSeed:输入参数,随机数生成器的种子值,用于用随机值初始化MLP。默认42。 OCRHandle:输出参数,输出OCR_mlp分类器的句柄。 |
OCR / Neural Nets【神经网络】 训练OCR分类器 trainf_ocr_class_mlp( : : OCRHandle, TrainingFile, MaxIterations, WeightTolerance, ErrorTolerance : Error, ErrorLog) OCRHandle:输入参数,输入OCR_mlp分类器的句柄。 TrainingFile:输入参数,输入示范样品文件,后缀为.trf。默认 'ocr.trf',可导入的文件后缀名有【trf, .otr】。 MaxIterations:输入参数,优化算法的最大迭代次数。默认200,建议值【20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300】。 WeightTolerance:输入参数,为两次迭代优化算法之间MLP权值的差异设定阈值。默认1.0,建议值【 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001】,范围【WeightTolerance >= 1.0e-8】。 ErrorTolerance:输入参数,优化算法对训练数据的MLP平均误差在两次迭代之间的差异阈值。默认0.01,建议值【1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001】,范围【ErrorTolerance >= 1.0e-8】。 Error:输出参数,输出MLP的训练数据的平均误差。 ErrorLog:输出参数,MLP对训练数据的平均误差作为优化算法迭代次数的函数,一次重复MLP最佳运算法则的平均错误数据。 |
OCR / Neural Nets【神经网络】 写入一个OCR分类器到一个文件 write_ocr_class_mlp( : : OCRHandle, FileName : ) OCRHandle:输入参数,输入OCR_mlp分类器的句柄。 FileName:输入参数,输入文件名称(保存的文件扩展名默认为.omc)。 |
OCR / Neural Nets【神经网络】 使用OCR分类器对多个字符进行实例分类 do_ocr_multi_class_mlp(Character, Image : : OCRHandle : Class, Confidence) 输入参数,输入需要辨认的字符区域。 输入参数,输入需要辨认字符的灰度值图像。 输入参数,OCR_mlp分类器的句柄。 输出参数,输出MLP识别对应的结果,该值保存的值为识别出来的字母或者数字或者符号等(数组)。Class == Character。 输出参数, 输出对应的特征相似值(数组),该值≤1.0,Confidence == Character。 |
OCR / Training Files 在训练的文件中查询 read_ocr_trainf_names( : : TrainingFile : CharacterNames, CharacterCount) TrainingFile:输入参数,输入要查询的文件的位置+名称+后缀,后缀一般为.trf。 CharacterNames:输出参数,读取字符的名称。 CharacterCount:输出参数,读取字符图像的个数。 |
dev_close_window()
read_image (Image, 'data/机器视觉')
get_image_size(Image,width,height)
dev_open_window (0, 0, width, height, 'black', WindowHandle)
rgb1_to_gray (Image, GrayImage)
***创建一个EmptyObject空元组
gen_empty_obj (EmptyObject)
for Index := 1 to 4 by 1
disp_message (WindowHandle, '请框选单个汉字区域,右键确认:','window', 12, 12, 'yellow', 'false')
***手动画一个矩形,输出其左上和右下的坐标
draw_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
**根据画的矩形生成对应的矩形Rectangle
gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)
***GrayImage为底,以Rectangle为区域,提取出ImageReduced1区域
reduce_domain (GrayImage, Rectangle, ImageReduced1)
*阈值处理
threshold (ImageReduced1, Region1, 128, 255)
*将元组EmptyObject和Region1区域合并
concat_obj (EmptyObject, Region1, EmptyObject)
endfor
words:=['机','器','视','觉']
*排序
***按区域的相对位置排序
sort_region (EmptyObject, SortedRegions1, 'character', 'true', 'row')
for Index1:=1 to 4 by 1
***在元组SortedRegions1中,选择单独某一个对象
select_obj (SortedRegions1, ObjectSelected1, Index1)
*将选择的对象字符添加到一个训练文件中
append_ocr_trainf (ObjectSelected1, Image, words[Index1-1], 'data/jqsj.trf')
endfor
***从训练文件中查询有哪些字符
read_ocr_trainf_names ('data/jqsj.trf', CharacterNames, CharacterCount)
stop()
***创建一个OCR分类器
create_ocr_class_mlp (50, 60, 'constant', 'default', CharacterNames, 80, 'none', 10, 42, OCRHandle)
***从训练文件中开始训练
trainf_ocr_class_mlp (OCRHandle, 'data/jqsj.trf', 200, 1, 0.01, Error, ErrorLog)
***输出训练后的文件
write_ocr_class_mlp (OCRHandle, 'data/jqsj.omc')
*读取一张测试图
read_image (ImageTest, 'data/机器视觉.png')
rgb1_to_gray (ImageTest, Image1)
threshold (Image1, T1, 128, 255)
*对符合条件的字符区域进行分割
connection (T1, T2)
*------------------------------------
closing_circle(T1, RegionClosing, 15)
connection(RegionClosing, ConnectedRegions)
intersection(ConnectedRegions,T2,T11)
*------------------------------------
*筛选符合条件的字符形状区域
select_shape (T11, SelectedwordRegions, 'area', 'and', 200, 2500)
*从左到右,排序
sort_region (SelectedwordRegions, SortedRegions2, 'upper_left', 'true', 'column')
count_obj(SortedRegions2, Number)
*开始字符识别
read_ocr_class_mlp ('data/jqsj.omc', OCRHandle1)
do_ocr_multi_class_mlp (SortedRegions2, Image1, OCRHandle1, Class, Confidence)
*显示结果
dev_clear_window()
dev_display(SortedRegions2)
disp_message(WindowHandle, '识别结果:', 'image', 10, 10, 'white', 'false')
for i:=1 to 4 by 1
disp_message(WindowHandle, Class[i-1], 'image', 230, i*140, 'green', 'false')
endfor