关于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)

二、将单独的字符组合成正确的字符串
为了能够让识别出来的字符正确地结合成我们需要的字符串,我们需要进行区域填充和膨胀,让代表一个字符串的字符区域能够融合在一起,再在各个区域中读取字符以及其个数,把相应个数的字符提取出来组合再放进数组里。

**将同一个字符串的字符区域膨胀,设置字符宽度并依次选取字符串区域
----------
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
    endif
endfor
----------
**把相应数目的字符提取出来组成正确的字符串
----------
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]
endfor
for b := 5 to 6 by 1
    New_Class[b] := Class[b-5]
endfor
for 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)
    endfor
endfor

字符串的显示效果如下:

这里写图片描述

  • 14
    点赞
  • 120
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值