全国服务热线:

15861139266

字符的训练与识别--青岛机器视觉培训苏州上位机培训
时间:2022-11-09 08:27:09 点击:1918 标签:

OCR:(Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程;即,针对印刷体字符,采用光学的方式将纸质文档中的文字转换成为黑白点阵的图像文件,并通过识别软件将图像中的文字转换成文本格式,供文字处理软件进一步编辑加工的技术。如何除错或利用辅助信息提高识别正确率,是OCR最重要的课题,ICR(Intelligent Character Recognition)的名词也因此而产生。衡量一个OCR系统性能好坏的主要指标有:拒识率、误识率、识别速度、用户界面的友好性,产品的稳定性,易用性及可行性等。


一个典型的创建OCR分类器的过程通常是:

append_ocr_trainf → create_ocr_class_mlp → trainf_ocr_class_mlp → write_ocr_class_mlp 


主要算子如下:

① append_ocr_trainf(Character, Image : : Class, TrainingFile : )

四个参数分别是:字符Region、字符Image、字符文本、OCR训练的.trf文件路径。

 

如果该路径下不存在.trf文件,那么它会自动生成该文件。


该算子作用是将单个字符区域、单个字符图像和对应的字符文本写入TrainingFile 文件。

 

② read_ocr_trainf_names( : : TrainingFile : CharacterNames, CharacterCount)

查询.trf训练文件中存储有哪些字符,以及每个字符在训练器中的数量。

 

③ create_ocr_class_mlp(WidthCharacter, HeightCharacter, 'constant', 'default', CharacterNames, NumHidden, 'none', 10, 42, OCRHandle)

最前面的两个参数分别指字符的宽度和高度。NumHidden指隐藏层的层数,一般不宜过低。

1)如何确定字符的宽度和高度?

同一种字体不同字符的宽度、高度是不一样的(例如字母A和I),如何确定这两个值?

有两种方式:一是直接测量字符中较宽字符的宽度和高度,把它们作为 WidthCharacter和HeightCharacter ;二是使用OCR助手(助手——打开新的OCR)来分析得出这两个值(推荐这种方式)。


image.png

转到“分割”页面即可看到自动分析得出的“字符宽度”和“字符高度”等信息。


image.png


 2)使用自己训练的OCR分类器,还是使用Halcon自带的分类器?

 

如果字体恰好合适的话,使用Halcon自带的分类器,通常效果是极好的。但是缺点也很明显:一是选择有限,如果需要OCR的字体比较特殊,可能选不好合适的分类器;二是你很难对Halcon自带的分类器进行优化,因为它只提供.omc文件,而不提供训练用的.trf文件。

      自己训练的分类器也有优缺点。

如果自己训练分类器的话可以用本算子create_ocr_class_mlp创建分类器,然后往下去训练识别

缺点一是需要自己切割字符收集字库,我们马上要讲的案例就是这样

缺点二是可能自己训练的分类器不如Halcon自带的分类器效果好。(原因一方面因为字库不够丰富,另一方面可能对OCR的理解不够深刻,导致训练分类器时有些细节考虑不周全)

不过自己训练分类器也有优点,最大的的优点是训练过程可控,而且自己可以添加字符图片,丰富字库,即分类器可以不断得到优化。这一点是Halcon自带的分类器所不具备的。

3)如果使用Halcon自带的分类器,如何选择合适的?

       点击OCR助手中的下图中的红框中的图标即可。

image.png

先加载“训练文件”(letters.trf),再加载“分类器”(.omc),即可看到识别结果及其把握度。当所有字符均识别正确,且把握度很高的时候,就说明这个分类器很合适。

4)提高字符区域分割效果的技巧。

分割字符区域的思路有两种:① 用形态学阈值分割;② 用find_text系列算子。

形态学分割算子大家比较熟悉,不需要多说,但是算子之间的组合比较灵活,思路比较重要。

分割字符区域这一步,建议如下:

 

(1)尽量把需要OCR的文字图像转正。

(2)可以用reduce_domain算子把需要OCR的图像区域挖出来,排除图像其他区域的干扰。

(3)分割之前可以增强图像的对比度,例如使用scale_image_max和emphasize算子。

(4)改变图像中字符笔画宽度的算子gray_erosion_rect可尝试使用,但是如果字符本身比较小,这个算子就不建议使用了,因为此时它对字符笔画的宽度改变会很大。

(5)如果图像光照情况基本一致,尽量使用threshold而不是binary_threshold这类自动阈值算子。因为threshold的结果是可预测的,而自动阈值的分割结果通常较难预测。

(6)阈值分割以后,可以使用select_shape算子限定一些筛选条件,筛选出真正的字符部分。


5)对于识别错的“相似”字符的补救措施。

有些字符是很相似的,例如字母“Q”和“O”,字母“I”和数字“1”。

image.png


对于上图的Q和O,如果容易识别混淆,那么如何判断到底是Q还是O呢?

 

提供一种思路:可以求字母内部的空白区域,调用算子:convexity (CharRegion, Convexity)

这个算子可以获得Q或者O内部区域的“凸度”,凸度极高的,说明这个字符是O,反之就是Q。

其他字符也可以用其他方法分别个性化判断。

 

另外,对于OCR,可以观察图中字符的分布,例如某一块区域只可能出现数字,但是识别出了形如“058I”这样的结果,那么很可能就是把数字“1”错判为了字母“I”。这时可以人为把字母“I”改成数字“1”作为后续补救措施。



④ trainf_ocr_class_mlp( : : OCRHandle, TrainingFile, MaxIterations, WeightTolerance, ErrorTolerance : Error, ErrorLog)

训练神经网络,通常参数用默认值即可。

OCRHandle  OCR分类器的句柄

TrainingFile   培训文件名称 

MaxIterations  优化算法的最大迭代次数

WeightTolerance   优化算法两次迭代中MLP权重差的阈值 

ErrorTolerance   优化算法两次迭代训练数据上MLP平均误差的阈值。 

Error  训练数据中MLP的平均误差

ErrorLog   训练数据上的MLP的平均误差作为优化算法迭代次数的函数。 

 

⑤  write_ocr_class_mlp( : : OCRHandle, FileName : )

保存OCR的的.omc分类器到文件。

 

⑥  read_ocr_class_mlp( : : FileName : OCRHandle)

从文件中读取OCR的.omc分类器。

 



其他算子:

1)tuple_gen_const(: : Length, Const : Newtuple)


作用:

生成特定长度的元组及初始化元素,参数Length为新元组的元素个数,如果输入Length是浮点型,只取其整数部分。

新元组生成的个数及值是由输入参数Const决定的,Const只由一个元素组成。元组中所有的元素的数据类型和值同于参数Const。

 

参数列表:

Length(in):要生成特定元组的长度

Const(in):初始化元组元素的常量

Newtuple(out):新元组

2)dev_set_check( : : Mode : )   指定HDevelop中的错误处理方式。

dev_set_check指定在发生错误时HDevelop如何应对,即如果算子的返回状态不是H_MSG_TRUE(2)。

  如果Mode的值是'give_error'---这是系统默认值---则一个错误的算子调用会抛出一个异常,这个异常在HDevelop程序中可以被catch语句捕获到。 但是,如果在HDevelop程序中没有周围的try-catch块,而且程序在HDevelop中运行,则程序在错误的算子处停止运行,并且打开错误消息框以显示错误文本。 另外,相应的调用的算子被输入到“算子窗口”中,使得用户可以容易地编辑并且可能修正错误的算子调用的参数。 如果该程序是从HDevEngine调用的,并且该异常未在HDevelop程序中捕获,则会抛出一个HDevEngineException对象,并退出该程序。

如果Mode设置为'〜give_error',则错误将被忽略,程序继续运行下一个算子。 dev_set_check('〜give_error')旨在与dev_error_var一起使用,dev_error_var可以检查算子调用返回的结果状态。


案例代码


* 第一步:读取图片和显示图片,并获取图片参数,主要是长和宽,

*这里dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)

*表示打开一个适应图像尺寸的窗口,并设置颜色,

*获取图片路径之后定义训练文件名。

dev_update_off ()

read_image (Image, 'letters')

get_image_size (Image, Width, Height)

dev_close_window ()

dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)

dev_set_colored (12)

set_display_font (WindowHandle, 16, 'mono', 'true', 'false')

*获取生成一个存储路径,执行后可以在控制变量中看到结果,此为本地函数

get_tmp_dir (TmpDir)

*定义一个训练文件名称并创建存储路径

TrainFile := TmpDir + '/letters.trf'


*第二步:形成训练数据。

*生成一个矩形区域,即从原图中分割出这个区域的内容作为训练数据

dev_display (Image)

gen_rectangle1 (Rectangle, 0, 0, Height - 1, 400)

reduce_domain (Image, Rectangle, Image)



* 第三步:对训练数据分割并排序,对分割下来的部分进行处理。


*首先进行快速二值化binary_threshold,(快速二值化一般用于背景简单的内容)

*需要注意的是,快速二值化的参数dark表示需要处理的部分为黑色。

binary_threshold (Image, Region, 'max_separability', 'dark', UsedThreshold)

*由于字母i和j为两个部分组成,所以需要先进行膨胀dilation_circle,使其成为一个连通域

dilation_circle (Region, RegionDilation, 3.5)

*之后再进行打散操作connection,

connection (RegionDilation, ConnectedRegions)

*然后通过求交集intersection的方式将膨胀后的字母还原成原来的大小。

*注意,在求交集运算中,即使最终i和j上的点没有与下面连接,依然是一个连通域,

intersection (ConnectedRegions, Region, RegionIntersection)

*进行排序操作sort_region,这里选用按字符行排列。

sort_region (RegionIntersection, Characters, 'character', 'true', 'row')

dev_display (Characters)

disp_message (WindowHandle, 'Training characters', 'window', 12, 12, 'black', 'true')

disp_continue_message (WindowHandle, 'black', 'true')

stop ()



* 第四步:建立图片字符与理论字符的关联文件


*先计算字符个数

count_obj (Characters, Number)

*计算训练数据每一行的字符数量

Length := Number / 27

*定义数组Classes,用于存储字母a ~ .

Classes := []

*ord('a') + j表示将a转成ASCII编码后加j表示其他字母的ASCII编码,

*chr(ord('a') + J))表示将ASCII编码转化为字符,

*gen_tuple_const(Length,chr(ord('a') + J))表示生成Length长的该字符tuple

for J := 0 to 25 by 1

    *chr(ord('a'))表示返回字符a,chr(ord('a') + 1)表示返回字符b

    Classes := [Classes,gen_tuple_const(Length,chr(ord('a') + J))]

endfor

*生成10个‘.’,放入数组中,形成新的数组

Classes := [Classes,gen_tuple_const(Length,'.')]

*表示将Image中的训练字符characters与Classes一一关联,存储在文件TrainFile中。

write_ocr_trainf (Characters, Image, Classes, TrainFile)

*至此,Classes数组与图片中的字符建立关联,关联文件为TrainFile。


*第五步:训练OCR分类器


*读取训练文件TrainFile

*返回训练文件中存储有哪些字符,以及每个字符在训练器中的数量。

read_ocr_trainf_names (TrainFile, CharacterNames, CharacterCount)

*使用多层感知器创建一个OCR分类器create_ocr_class_mlp

create_ocr_class_mlp (8, 10, 'constant', 'default', CharacterNames, 20, 'normalization', 26, 42, OCRHandle)

* 使用MLP训练一个OCR分类器

trainf_ocr_class_mlp (OCRHandle, TrainFile, 100, 0.01, 0.01, Error, ErrorLog)

* 执行至此,我们已经完成了一个OCR分类器的训练,下面进行测试。

stop ()


* 第六步:测试

*首先扩展图片,将一半的图像扩充为整个图像。

full_domain (Image, Image)


binary_threshold (Image, Region, 'max_separability', 'dark', UsedThreshold1)

dilation_circle (Region, RegionDilation, 3.5)

connection (RegionDilation, ConnectedRegions)

intersection (ConnectedRegions, Region, RegionIntersection)

sort_region (RegionIntersection, Characters, 'character', 'true', 'row')

* 使用刚刚训练的OCR分类器进行测试do_ocr_multi_class_mlp(对多个目标),do_ocr_single_class_mlp是对单个

*对Image中排好序的Characters利用刚刚训练的OCR分类器,句柄为OCRHandle进行测试,

*测试结果为Class,精度为Confidence。

do_ocr_multi_class_mlp (Characters, Image, OCRHandle, Class, Confidence)

* 完成此次OCR训练器的测试


* 第七步:显示


*首先测得每个字符的面积、行、列,设置显示字体,显示Class的内容。

area_center (Characters, Area, Row, Column)

dev_display (Image)

set_display_font (WindowHandle, 16, 'sans', 'true', 'false')

disp_message (WindowHandle, Class, 'image', Row - 16, Column + 8, 'blue', 'false')

set_display_font (WindowHandle, 16, 'mono', 'true', 'false')

disp_message (WindowHandle, 'Classification result', 'window', 12, 12, 'black', 'true')

clear_ocr_class_mlp (OCRHandle)

dev_set_check ('~give_error')

delete_file (TrainFile)

dev_set_check ('give_error')


苏州零基础学员怎样学机器视觉

苏州电工基础学员如何学机器视觉

苏州PLC基础学员如何学机器视觉

苏州C#与工业自动化培训

苏州C#高级语言培训

苏州C#上位机培训

苏州C#上位机培训

苏州上位机软件开发培训

苏州上位机培训

苏州C#与PLC通信培训


立即咨询
  • 品质服务

    服务贴心周到

  • 快速响应

    全天24小时随时沟通

  • 专业服务

    授权率高,保密性强

  • 完善售后服务

    快速响应需求,及时性服务

直播课程
电气类课程
上位机软件开发课
机器视觉软件开发课
深度学习
联系方式
电话:15861139266
邮箱:75607802@qq.com
地址:苏州吴中区木渎镇尧峰路69号
关注我们

版权所有:大林机器视觉培训所有 备案号:苏ICP备14016686号-9

本站关键词:上位机培训 机器视觉软件开发培训 上位机运动控制培训 深度学习培训 网站标签