关于halcon的OCR字符识别

上面的图片是一块芯片的信息,我们通过halcon软件里面的OCR助手将这张图片上面的信息进行字符识别。
一、训练OCR字符库
为了识别图像中的文字,需要通过图像训练合适的OCR字符库,这时,我们需要利用到halcon上面的OCR助手。下面,我来教大家如何使用这个OCR助手,并且正确地训练出芯片上的字符。
第一步,我们需要打开OCR字符助手。


第二步,我们选择“加载一张实例图像”。

在这里,我们就把上面的图片加载进来。
第三步,我们选择“使用一个矩形框在图像中标记出需要识别文本地位置”。
因为我们这一幅图像上面芯片信息的倾斜角度几乎为0,所以我们选择第一个画倾斜角度为0的矩形框即可。

在这里,我们可以把合适的字符区域选取出来,防止不必要区域对我们训练OCR字符库造成干扰,让训练出来的效果更加精确。

第四步,我们需要在“分割”里面对一些参数进行适当的设置,具体的设置需要针对图像的情况而定。特别需要注意的是,由于本幅图像的背景相较于字符是非常暗的色调,我们就需要将“符号外观”中的“暗背景中亮文本”这个选项勾选出来,否则无论如何设置参数,OCR字符的识别都是无法达到理想状态的。

在这里,当我们按照图上面的参数数值进行设置的情况下,OCR字符的识别效果如下:

在这里,可以看到,除了第三行的横杠没有被识别出来之外,其余的字符已经被正确地识别。由于在芯片的信息中,我们无需理会横杠的意思,所以可以不做相应的处理。
第五步,我们选择“字体”,勾选“训练文件”。

然后,我们需要在“学习”的白色文本框内,逐一将图像上的字符进行手动训练,并将训练结果加入训练数据当中。

最后,我们需要按下“训练”中的“开始训练”按钮,并将训练出来的文件保存到适当的位置。

训练出来的文件如下:

第六步,我们选择“代码生成”中的“插入代码”,便可以将上面这一系列的操作化成我们需要用到的算法,供后续的图像处理使用。

插入的代码如下:
**以下这一段代码就是我们刚刚在“分割”里面的一些参数设置算法----------create_text_model_reader ('manual', [], TextModel)set_text_model_param (TextModel, 'polarity', 'light_on_dark')set_text_model_param (TextModel, 'char_width', 25)set_text_model_param (TextModel, 'char_height', 60)set_text_model_param (TextModel, 'stroke_width', 5)set_text_model_param (TextModel, 'return_punctuation', 'false')set_text_model_param (TextModel, 'return_separators', 'false')set_text_model_param (TextModel, 'fragment_size_min', 10)set_text_model_param (TextModel, 'eliminate_border_blobs', 'true')set_text_model_param (TextModel, 'base_line_tolerance', 0.8)set_text_model_param (TextModel, 'max_line_num', 2)----------**以下这段代码是将上面训练字符的过程以算法的形式呈现,并最终输出字符的准确区域和识别结果----------read_ocr_class_mlp ('Fonts.omc', OcrHandle) //读取训练出来的OCR字符库句柄read_image (Image, 'C:/Works/Chip_Information_Identification/Images/1/LM386N-1芯片.jpg')gen_rectangle1 (ROI_OCR_02_0, 16.8333, 56.1667, 143.833, 272.5) //在第二步里面选择的“使用一个矩形框在图像中标记出需要识别文本地位置”绘制的矩形框access_channel (Image, TmpObj_Mono, 1)reduce_domain (TmpObj_Mono, ROI_OCR_02_0, TmpObj_MonoReduced_OCR_02_0)hom_mat2d_identity (TmpCtrl_MatrixIdentity)get_domain (TmpObj_MonoReduced_OCR_02_0, TmpObj_Domain)get_system ('clip_region', TmpCtrl_ClipRegion)set_system ('clip_region', 'false')dilation_circle (TmpObj_Domain, TmpObj_DomainExpanded, 25) //将选定的矩形框以圆角矩形框的形状扩大25个像素affine_trans_region (TmpObj_DomainExpanded, TmpObj_DomainTransformedRaw, TmpCtrl_MatrixIdentity, 'true')smallest_rectangle1 (TmpObj_DomainTransformedRaw, TmpCtrl_Row1, TmpCtrl_Col1, TmpCtrl_Row2, TmpCtrl_Col2) //在TmpObj_DomainTransformedRaw区域内取最小的矩形hom_mat2d_translate (TmpCtrl_MatrixIdentity, -TmpCtrl_Row1, -TmpCtrl_Col1, TmpCtrl_MatrixTranslation)hom_mat2d_compose (TmpCtrl_MatrixTranslation, TmpCtrl_MatrixIdentity, TmpCtrl_MatrixComposite)affine_trans_region (TmpObj_Domain, TmpObj_DomainTransformed, TmpCtrl_MatrixComposite, 'true')affine_trans_image (TmpObj_MonoReduced_OCR_02_0, TmpObj_ImageTransformed, TmpCtrl_MatrixComposite, 'constant', 'true')dilation_circle (TmpObj_Domain, TmpObj_DomainExpanded, 25)expand_domain_gray (TmpObj_ImageTransformed, TmpObj_ImageTransformedExpanded, 25)reduce_domain (TmpObj_ImageTransformed, TmpObj_DomainTransformed, TmpObj_ImageTransformedReduced)crop_part (TmpObj_ImageTransformedReduced, TmpObj_MonoReduced_OCR_02_0, 0, 0, TmpCtrl_Col2-TmpCtrl_Col1+1, TmpCtrl_Row2-TmpCtrl_Row1+1)set_system ('clip_region', TmpCtrl_ClipRegion)find_text (TmpObj_MonoReduced_OCR_02_0, TextModel, TmpCtrl_ResultHandle_OCR_02_0)invert_image (TmpObj_MonoReduced_OCR_02_0, TmpObj_MonoInverted_OCR_02_0) //将TmpObj_MonoReduced_OCR_02_0区域反色get_text_object (Symbols_OCR_02_0, TmpCtrl_ResultHandle_OCR_02_0, 'all_lines') //提取出已识别字符的轮廓clear_text_result (TmpCtrl_ResultHandle_OCR_02_0) //将TmpCtrl_ResultHandle_OCR_02_0数组的内存释放----------dev_display (TmpObj_MonoInverted_OCR_02_0)dev_set_draw ('fill')dev_set_colored (3)dev_display (Symbols_OCR_02_0) //将字符轮廓以三种颜色间隔填充的方式显示do_ocr_multi_class_mlp (Symbols_OCR_02_0, TmpObj_MonoInverted_OCR_02_0, OcrHandle, SymbolNames_OCR_02_0, Confidences_OCR_02_0) //将字符的识别结果全部放入SymbolNames_OCR_02_0数组中clear_text_model (TextModel) //将TextModel模型的内存释放clear_ocr_class_mlp (OcrHandle) //将识别出来的OCR字符库句柄的内存释放
其实,只要我们拥有了能够识别图像字符的参数,它的识别过程是可以由我们自己编写的算法实现的。
decompose3 (Image, Image_R, Image_G, Image_B) //将RGB图片Image分离出只包含单一R、G、B这三种颜色的三幅图片,方便我们对单一的三原色图片进行处理gen_rectangle1 (Rectangle, 16.9774, 55.8333, 122.626, 242.5)reduce_domain (Image_R, Rectangle, ImageReduced)threshold (ImageReduced, Region, 0, 85) //将ImageReduced中阈值为0到85之间的区域选取出来fill_up (Region, RegionFillUp) //填充Region区域connection (RegionFillUp, ConnectedRegions) //将RegionFillUp里面的区域分离select_shape_std (ConnectedRegions, SelectedRegions, 'max_area', 70) //将ConnectedRegions里面面积最大的区域选取出来reduce_domain (ImageReduced, SelectedRegions, ImageReduced1)find_text (ImageReduced1, TextModel, TextResultID) //在ImageReduced1内查找TextModel模板invert_image (ImageReduced1, ImageInvert)get_text_object (Characters, TextResultID, 'all_lines')clear_text_result (TextResultID)dev_display (Image_R)dev_set_draw ('fill')dev_set_colored (3)dev_display (Characters)do_ocr_multi_class_mlp (Characters, ImageInvert, OcrHandle, Class, Confidences)clear_text_model (TextModel)clear_ocr_class_mlp (OcrHandle)1234567891011121314151617181912345678910111213141516171819
二、将单独的字符组合成正确的字符串
为了能够让识别出来的字符正确地结合成我们需要的字符串,我们需要进行区域填充和膨胀,让代表一个字符串的字符区域能够融合在一起,再在各个区域中读取字符以及其个数,把相应个数的字符提取出来组合再放进数组里。
**将同一个字符串的字符区域膨胀,设置字符宽度并依次选取字符串区域----------union1 (Characters, RegionUnion) //将Characters里面的区域集合成一个区域closing_rectangle1 (RegionUnion, RegionClosing, 25, 10) //将RegionUnion区域按照长度25,宽度10的矩形膨胀connection (RegionClosing, ConnectedRegions3)count_obj (ConnectedRegions3, Number1) //计算ConnectedRegions3内区域的个数sort_region (ConnectedRegions3, SortedRegions1, 'first_point', 'true', 'row') //将ConnectedRegions3内的区域按照列的形式排序,并以相应的数字命名character_width1 := 21 //第一种字符宽度character_width2 := 15 //第二种字符宽度for i := 1 to Number1 by 1 read_image (Image, images + 'LM386N-1芯片.jpg') select_obj (SortedRegions1, ObjectSelected1, i) //按顺序选取SortedRegions1内的区域 reduce_domain (Image, ObjectSelected1, ImageReduced7)----------**计算出字符串区域内字符的个数---------- threshold (ImageReduced7, Region1, 85, 255) connection (Region1, ConnectedRegions1) select_shape (ConnectedRegions1, SelectedRegions1, 'area', 'and', 0, 150) difference (Region1, SelectedRegions1, RegionDifference) read_image (Image, images + 'LM386N-1芯片.jpg') dev_display (RegionDifference) //去除杂项后的区域 area_center (RegionDifference, Area, Row1, Column1) character_center_x[i-1] := Column1 character_center_y[i-1] := Row1 smallest_rectangle1 (RegionDifference, Row11, Column11, Row2, Column2) if(i < Number1) character_number[i-1] := (Column2 - Column11) / character_width1 //计算每个字符串里面包含的字符数 elseif(i = Number1) character_number[i-1] := (Column2 - Column11) / character_width2 endifendfor----------**把相应数目的字符提取出来组成正确的字符串----------tuple_round (character_number, character_number_Round) //把character_number数组内的字符都化成整形read_image (Image, images + 'LM386N-1芯片.jpg')for a := 0 to 4 by 1 New_Class[a] := Class[a+2]endforfor b := 5 to 6 by 1 New_Class[b] := Class[b-5]endforfor c := 7 to 11 by 1 New_Class[c] := Class[c]endfor----------
三、在窗口显示整理出来的字符串
for j := 0 to |character_number_Round| - 1 by 1 tuple_first_n (New_Class, character_number_Round[j] - 1, Selected) tuple_sum (Selected, character_string) windows_data[j] := character_string disp_message (WindowHandle, character_string, 'image', character_center_y[j] - 25, character_center_x[j] + 20, 'black', 'true') for k := 0 to character_number_Round[j] - 1 by 1 tuple_remove (New_Class, 0, New_Class) endforendfor123456789123456789
字符串的显示效果如下:
