HALCON示例程序bottle.hdev、bottlet.hdev瓶体字符OCR的训练和检测

示例程序源码(加注释)

1、先介绍bottlet.hdev(训练OCR识别文件)

*定义一个字符串变量FontName ,内容是bottle
FontName := ‘bottle’
*第一步分割字符,以便单独对字体进行训练
Step 1: Segmentation
*窗口显示更新关闭
dev_update_window (‘off’)
*读入图片
read_image (Bottle, ‘bottle2’)
*得到读入图片大小
get_image_size (Bottle, Width, Height)
*关闭显示窗口
dev_close_window ()
*根据刚刚获得的图片大小创建图片大小二倍的窗口
dev_open_window (0, 0, 2 * Width, 2 * Height, ‘black’, WindowID)
*设置字体显示格式
set_display_font (WindowID, 27, ‘mono’, ‘true’, ‘false’)
*对读入图片进行阈值分割
threshold (Bottle, RawSegmentation, 0, 95)
*对区域面积在1-5之间的进行孔洞填充,目的就是为了消除噪声。
fill_up_shape (RawSegmentation, RemovedNoise, ‘area’, 1, 5)
*使用半径位2.5的圆形元素进行开运算
opening_circle (RemovedNoise, ThickStructures, 2.5)
*进行孔洞填充
fill_up (ThickStructures, Solid)
*使用宽7高1的矩形元素对区域进行开运算
opening_rectangle1 (Solid, Cut, 1, 7)
*分割连通域
connection (Cut, ConnectedPatterns)
*取区域ConnectedPatterns与区域ThickStructures的交集,将字符的原本形态恢复,之前对字符也进行了填
*充是怕进行开运算的时候把字符也给干掉
intersection (ConnectedPatterns, ThickStructures, NumberCandidates)
*使用面积对区域进行筛选,筛选出面积在300-9999的区域
select_shape (NumberCandidates, Numbers, ‘area’, ‘and’, 300, 9999)
*对区域进行排序,按照列,从第一列到最后一列,按照升序进行排列。这个算子之前介绍过了哈
sort_region (Numbers, FinalNumbers, ‘first_point’, ‘true’, ‘column’)
*显示,下面的算子之前的都进行了介绍,这里就不进行细说了。
dev_display (Bottle)
dev_set_color (‘green’)
dev_set_line_width (2)
dev_set_shape (‘rectangle1’)
dev_set_draw (‘margin’)
dev_display (FinalNumbers)
*第二步进行训练前相关准备,排序与定义分割出的区域代表字符。
Step2: Training file generation
*根据上文分割出的字符区域从左到右的顺序,将他们的命名存入TrainingNames 数组变量中,其实就是你的
*字符是啥你就在这个训练数组里写入什么,让halcon知道你刚刚分割出的字符的含义。
TrainingNames := [‘0’,‘1’,‘0’,‘8’,‘9’,‘4’]
*定义训练出来的文件的路径与文件名。这里强调一下哈,这里没有路径是因为它会把训练文件存入halcon的
*默认路径中,我们想把训练文件存在我们想要的地方就得这么写:TrainingFileName := C:/ + ‘.trf’。
TrainingFileName := FontName + ‘.trf’
*对区域进行排序,按照列,从第一列到最后一列,按照升序进行排列。和上边一样
sort_region (FinalNumbers, SortedRegions, ‘first_point’, ‘true’, ‘column’)
*分别求取每一个字符的最小外接矩形
shape_trans (SortedRegions, RegionTrans, ‘rectangle1’)
*求取每个区域的面积与中心坐标
area_center (RegionTrans, Area, Row, Column)
*mean这个算子:返回数组中元素的平均值。这里MeanRow 就是字符平均行位置
MeanRow := mean(Row)
*halcon的异常处理,程序运行正常的话程序会继续运行,如果出错显示错误内容弹窗。在这里为了检查求取
*数组均值是否完成,咱们设想一下,如果咱们提取字符没提取出来,area_center 求取的Row为空,那么进
*行均值计算的时候除以0,程序就会崩溃。
dev_set_check (’~give_error’)
*删除文件TrainingFileName
delete_file (TrainingFileName)
*这里再进行异常检查,如果这个文件正在打开或者被使用,是删除不了的,所以还要进行异常检查
dev_set_check (‘give_error’)
*下边一段代码是把刚刚咱么在TrainingNames 的数字按照分割出字符的位置进行一个显示,为了什么呢,就
*是为了让我们直观的看到我们存入TrainingNames 的字符与咱们分割出的是不是一一对应,如果不对应则会
*导致训练出的文件是错的。
for i := 0 to |TrainingNames| - 1 by 1
select_obj (SortedRegions, CharaterRegions, i + 1)
append_ocr_trainf (CharaterRegions, Bottle, TrainingNames[i], TrainingFileName)
disp_message (WindowID, TrainingNames[i], ‘image’, MeanRow - 40, Column[i] - 6, ‘yellow’, ‘false’)
endfor
*第三部训练
Step3: Training
*sort按照升序对数组元素进行排列;tuple_uniq - 丢弃元组中连续相同元素。那么我们最开始的数组:
*[‘0’,‘1’,‘0’,‘8’,‘9’,‘4’]先进行升序排列得到[‘0’,‘0’,‘1’,‘4’,‘8’,‘9’]之后剔除相同元素得到[‘0’,‘1’,‘4’,‘8’,‘9’]
*最终CharNames =[‘0’,‘1’,‘4’,‘8’,‘9’]
CharNames := uniq(sort(TrainingNames))
*create_ocr_class_mlp - 使用多层感知器创建OCR分类器。
*函数原型:create_ocr_class_mlp(:: WidthCharacter,HeightCharacter,Interpolation,Features,Characters,NumHidden,Preprocessing,NumComponents,RandSeed:OCRHandle)
*WidthCharacter:字符宽度;HeightCharacter:字符高度;Interpolation:插值;Features:方式;
*Characters:字符;NumHidden:字符数量;Preprocessing:预处理;NumComponents:组件数量;
*RandSeed:随机数数量;OCRHandle:OCR训练句柄。
create_ocr_class_mlp (8, 10, ‘constant’, ‘default’, CharNames, 5, ‘none’, 10, 42, OCRHandle)
*trainf_ocr_class_mlp - 训练OCR分类器。
*函数原型:trainf_ocr_class_mlp(:: OCRHandle,TrainingFile,MaxIterations,WeightTolerance,ErrorTolerance:Error,ErrorLog)
*OCRHandle:OCR识别句柄;TrainingFile:训练文件名与路径;MaxIterations:最大迭代次数;
*WeightTolerance:错误公差;Error:错误;ErrorLog:错误日志。
trainf_ocr_class_mlp (OCRHandle, TrainingFileName, 200, 1, 0.01, Error, ErrorLog)
*将训练好的ocr文件写入指定位置。其实就是把训练文件保存下来。
write_ocr_class_mlp (OCRHandle, FontName)
*清除OCR训练句柄。
clear_ocr_class_mlp (OCRHandle)

2、介绍bottlet.hdev(OCR识别)
*定义一个字符串变量FontName ,内容是Industrial_0-9_NoRej
 FontName := ‘Industrial_0-9_NoRej’
 *第一步:分割字符
 Step 1: Segmentation
 *显示读入图片操作之前介绍过了,这里就不介绍了
 dev_update_window (‘off’)
 read_image (Bottle, ‘bottle2’)
 get_image_size (Bottle, Width, Height)
 dev_close_window ()
 dev_open_window (0, 0, 2 * Width, 2 * Height, ‘black’, WindowID)
 set_display_font (WindowID, 16, ‘mono’, ‘true’, ‘false’)
 dev_display (Bottle)
 disp_continue_message (WindowID, ‘black’, ‘true’)
 stop ()• 创建读入ocr训练文件
 create_text_model_reader (‘auto’, FontName, TextModel)• 设置文本模型的参数最小字符宽度为5
 set_text_model_param (TextModel, ‘min_stroke_width’, 5)• 文本行的结构
 set_text_model_param (TextModel, ‘text_line_structure’, ‘2 2 2’)• 在图像中查找文本
 find_text (Bottle, TextModel, TextResultID)• 显示字符分割结果
 get_text_object (Characters, TextResultID, ‘all_lines’)
 dev_display (Bottle)
 dev_display (Characters)
 stop ()• 显示识别的字符结果
 get_text_result (TextResultID, ‘class’, Classes)
 area_center (Characters, Area, Row, Column)
 for Index := 0 to |Classes| - 1 by 1
 disp_message (WindowID, Classes[Index], ‘image’, 80, Column[Index] - 3, ‘green’, ‘false’)
 endfor• 释放内存
• 清理结果句柄
 clear_text_result (TextResultID)
 *清除OCR识别句柄
 clear_text_model (TextModel)

处理思路

这个就是一个简单的OCR字符从分割到训练文本到识别的一个步骤。希望能帮助到大家。

后记

大家有什么问题可以向我提问哈,我看到了第一时间回复,希望在学习的路上多多结交良师益友。