上一部分(OCR初步letters_mlp例程分析)讲了创建分类器进行OCR识别并生成自己的训练文件,这一部分我们着重分析利用模板进行OCR识别。主要分析两个例程bottle、bottlet。
主要是分割并读取酒瓶上的数字
第一步:具体化酒瓶上需要识别的数字字体,一般采用提前训练好的'Universal_0-9_NoRej'
FontName := 'Universal_0-9_NoRej'
第二步:识别
首先读取图片并显示,在之前的学习笔记中都详细阐述过,这里不多加赘述。得到酒瓶图像显示结果
然后创建文本模板create_text_model_reader
,输入是上一步确定的字体FontName
,输出是文本模板句柄TextModel
;
接下来设置模板参数set_text_model_param
,GenParamName
的允许参数值列表不同,具体取决于使用create_text_model_reader
创建文本模型时设置的模式。这里设置字符尺寸的min_stroke_width
(像素中字符的最小笔划宽度)为6
,线性结构text_line_structure
主要是为了简化对分段文本内特定结构(例如日期或序列号)的搜索从而定义行结构,对于每个文本行,计算字符之间的距离,并且基于这些距离,文本行被分成文本块。在此过程中忽略诸如“。”,“_”和“ - ”之类的短字符并将其视为空格。例如,如果要查找的文本是包含月,日和年两个字符的日期,则结构将为“2 2 2”。如果年份可能包含两个或四个字符,则结构将为“2 2 2-4”,表示最后一个字符块由2到4个字符组成。由于这里日期的格式已知,所以此处定义为2 2 2
。
之后读取酒瓶上的日期find_text
。实现对输入图片Image
根据刚刚创建的文本模板TextModel
查找,返回值为TextResultID
句柄;
最后获取文本内容get_text_object
,all_lines
表示返回所有分段文本行中的所有字符。
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 ()
create_text_model_reader ('auto', FontName, TextModel)
* The printed date has a significantly higher stroke width
set_text_model_param (TextModel, 'min_stroke_width', 6)
* The "best before" date has a particular and known structure
set_text_model_param (TextModel, 'text_line_structure', '2 2 2')
*
* Read the "best before" date
find_text (Bottle, TextModel, TextResultID)
get_text_object (Characters, TextResultID, 'all_lines')
第三步:显示结果并读取
着重讲一下get_text_result (TextResultID, 'class', Classes)
,表示从句柄中得到名为'class'
的结果,返回值为Classes
,当然也可以返回其他参数的结果,设置对应的ResultName
,例如'num_lines'
返回一共找到的行数等,最后计算字符的行列,并显示识别结果。
dev_display (Bottle)
dev_display (Characters)
stop ()
* Display the reading results
get_text_result (TextResultID, 'class', Classes)
area_center (Characters, Area, Row, Column)
disp_message (WindowID, Classes, 'image', 80, Column - 3, 'green', 'false')
形成独立的omc训练文件
第一步:定义字体名称,并读取图片显示等,略过
FontName := 'bottle'
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')
第二步:Blob分析得到排序好的各个字符独立的连通域。
这里着重提一下思路,由于已经是灰度图片了,所以利用灰度直方图直接阈值化得到感兴趣区域,这一部分在halcon学习笔记(二)实现相机物体抓取第三步详细说明,然后在区域内根据给定形状特征填充孔洞fill_up_shape
,这里选用了area
特征,其他常用特征还有convexity
(凸性)等。进一步做开运算opening_rectangle1
去除其他部分,再填充区域内所有孔洞fill_up
(主要是为了防止在开运算时被腐蚀掉导致连通域断开),对经过再次开运算后的区域(此时干扰区域明显减少)进行打散,再求全部填充前的区域与打散之后区域的交集,恢复数字的基本形状,最后通过area
面积特征选择出感兴趣的区域并排序,并绘制FinalNumbers
的边界矩形。
threshold (Bottle, RawSegmentation, 0, 95)
fill_up_shape (RawSegmentation, RemovedNoise, 'area', 1, 5)
opening_circle (RemovedNoise, ThickStructures, 2.5)
fill_up (ThickStructures, Solid)
opening_rectangle1 (Solid, Cut, 1, 7)
connection (Cut, ConnectedPatterns)
intersection (ConnectedPatterns, ThickStructures, NumberCandidates)
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)
第三步:生成训练文件
具体化训练数据TrainingNames := ['0','1','0','8','9','4']
创建对应的训练文件TrainingFileName := FontName + '.trf'
排序
形状转换,将选择区域转变为rectangle1
删除原训练文件delete_file (TrainingFileName)
通过append_ocr_trainf
的方式向训练文件中逐个追加字符,文件不存在时创建新文件(变量还是在的)
* Step2: Training file generation
TrainingNames := ['0','1','0','8','9','4']
TrainingFileName := FontName + '.trf'
sort_region (FinalNumbers, SortedRegions, 'first_point', 'true', 'column')
shape_trans (SortedRegions, RegionTrans, 'rectangle1')
area_center (RegionTrans, Area, Row, Column)
MeanRow := mean(Row)
dev_set_check ('~give_error')
delete_file (TrainingFileName)
dev_set_check ('give_error')
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
如此循环,直至所有的字符追加完毕,此时TrainingFileName
文件与需要训练的字符一一关联,与我们Halcon学习笔记(八)——OCR初步letters_mlp例程分析中第四步结果一样,只是方式不一样。
第四步:生成训练文件
对训练的字符进行排序,然后删除重复的部分uniq
;
创建基于MLP的OCR分类器,create_ocr_class_mlp
;
训练基于MLP的OCR分类器,trainf_ocr_class_mlp
;
导出训练文件,write_ocr_class_mlp
CharNames := uniq(sort(TrainingNames))
create_ocr_class_mlp (8, 10, 'constant', 'default', CharNames, 10, 'none', 10, 42, OCRHandle)
trainf_ocr_class_mlp (OCRHandle, TrainingFileName, 200, 1, 0.01, Error, ErrorLog)
write_ocr_class_mlp (OCRHandle, FontName)
此时我们就可以使用bottle
字体了,比如在上例bottle
中使用bottle
字体
只需要将bottle
例程中的第一句话FontName := 'Universal_0-9_NoRej'
改为FontName := 'bottle'
即可以得到相同的结果,感兴趣的可以去试一下。
至此,OCR初步的例程分析就结束了,接下来我们将在下一篇博客分析当字符呈现圆形排列或字体倾斜的处理。