基于Halcon的瓶底字符识别


背景

在食品,药品及日用化学品等领域,有很大一部分产品采用瓶装容器来盛放产品。企业通常使用喷码机将产品的批号、生产日期、保质期等喷印在瓶底部位。喷码机受自身性能、机械振动等因素的影响,可能会出现多种缺陷,如字符的缺印、漏印、错印等,以上的质量问题会对企业的品牌形象及信誉产生影响。
传统的喷码字符检测采用人工全检,人工检测的工作效率低、工作强度大且容易因人眼疲劳等因素产生人为误差出现漏检、误检的情况。因此人工检测的方式已经不适应当下制造业自动化、信息化的发展趋势,基于机器视觉的字符识别算法则可以解决人工检测效率低,成本高和误差大的缺点,具有广泛的市场需求和较高的研究价值。

要求

针对瓶装产品设计基于机器视觉技术的瓶底字符识别算法,瓶底字符识别的难点在于瓶底的旋转姿态不定,致使识别的准确率难以保证,因此在字符识别之前必须对瓶底字符进行姿态矫正,使字符水平排列。

  1. 收集瓶体喷码字符数据(拍摄罐装饮料、调料等图像),类似下图中
    样本,角度不定,多行,每行含有英文字符、数字和特殊符号(:等)。
    imageimage
  2. 设计算法,包括:图像预处理模块,字符定位模块,字符分割模块和字符识别模块。图像预处理模块用于对读取的图像进行便于操作的预先处理;字符定位模块用于将字符区域与背景区分开;字符分割模块用于将提取出的字符区域内的字符单独分割并排序;字符识别模块用于识别分割出的字符并显示。
  3. 设计针对瓶底图像字符分类器的训练程序,用于训练专属的分类器,进一步提高瓶底字符识别算法的准确率。

原理

Halcon已广泛应用于光学字符识别(OCR),利用Halcon中自带的工业字符识别模型可以实现多种字体的文本识别。罐装瓶底喷码字符多使用点式打印机,除使用自带的字符模型外可以根据样本进行训练,以此来提高识别准确率。
使用Halcon进行字符识别时,首先要获取水平排列的字符,分割出单个字符区域,然后再读取OCR分类器实现字符分类。
针对倾斜的文本,可以先进行仿射变换使其水平排列,不用考虑文本是否倒置。识别完成后对结果进行校验,如果识别结果符合逻辑,认为结果正确,否则认为文本倒置,调整后再进行识别,最后输出识别结果。
在实验时,待识别的图像应保证目标区域居中,即罐底应位于图片中央。图片大小一致,具有相同的长宽尺寸。在有条件的情况下,可以使用专业的检测平台获取罐底图像,拍摄时光照均匀且无明显阴影与遮盖,保证图片质量。

图片要求

  1. 目标居中,罐底圆形位于图片中央;
  2. 图片大小一致,长宽尺寸相同(正方形);
  3. 多角度可随意旋转(对字符而言);
  4. 拍摄时光照均匀无明显阴影与遮盖。

主要步骤

1. 设置圆形ROI,裁剪原图片

* 生成圆形区域:gen_circle
* 缩小图像的域:reduce_domain

这一步的目的是去掉原图像的背景,以免干扰识别结果,处理后的图像保留全部的字符区域和小部分的背景。

2. 图像处理

* 增强图像对比度:emphasize
* 转化为灰度图像:rgb1_to_gray
* 使用矩形结构元素进行膨胀:dilation_rectangle1
* 连接区域:connection
* 区域选择:select_shape
* 合并为一个区域:union1
* 拟合成矩形:shape_trans
* 得到矩形区域的偏转角度:orientation_region
* 计算矩形区域面积和中心点坐标:area_center
* 旋转图片至水平并得到仿射矩阵:vector_angle_to_rigid
* 仿射矩阵应用于图片:affine_trans_image
* 仿射矩阵应用于矩形区域:affine_trans_region
* 在原图中扣出字符区域图像:reduce_domain
* 选择第一个通道:access_channel

3. 字符分割

* 阈值分割:threshold
* 使用矩形结构元素进行膨胀:dilation_rectangle1
* 连接区域:connection
* 区域选择:select_shape
* 拟合成矩形:shape_trans
* 区域排序:sort_region
* 统计区域个数:count_obj

4. 字符识别

* 读取OCR分类器:read_ocr_class_mlp
* 选择识别的字符区域:select_obj
* 在灰度图中扣出字符区域图像:reduce_domain
* 使用OCR分类器进行字符识别:do_ocr_multi_class_mlp

5. 识别结果校验

* 识别正确:显示识别结果。
* 识别错误:重新旋转图像并进行字符分割与识别;
           显示识别结果。

过程步骤

  1. 设置圆形ROI,裁剪原图片:
    生成圆形区域:gen_circle
    缩小图像的域:reduce_domain
  2. 图像处理:
    增强图像对比度:emphasize
    转化为灰度图像:rgb1_to_gray
    使用矩形结构元素进行膨胀:dilation_rectangle1
    连接区域:connection
    区域选择:select_shape
    合并为一个区域:union1
    拟合成矩形:shape_trans
    得到矩形区域的偏转角度:orientation_region
    计算矩形区域面积和中心点坐标:area_center
    旋转图片至水平并得到仿射矩阵:vector_angle_to_rigid
    仿射矩阵应用于图片:affine_trans_image
    仿射矩阵应用于矩形区域:affine_trans_region
    在原图中扣出字符区域图像:reduce_domain
    选择第一个通道:access_channel
  3. 字符分割:
    阈值分割:threshold
    使用矩形结构元素进行膨胀:dilation_rectangle1
    连接区域:connection
    区域选择:select_shape
    拟合成矩形:shape_trans
    区域排序:sort_region
    统计区域个数:count_obj
  4. 字符识别:
    读取OCR分类器:read_ocr_class_mlp
    选择识别的字符区域:select_obj
    在灰度图中扣出字符区域图像:reduce_domain
    使用OCR分类器进行字符识别:do_ocr_multi_class_mlp
  5. 识别结果校验:
    识别正确:显示识别结果。
    识别错误:重新旋转图像并进行字符分割与识别;
    显示识别结果。
    image

运行结果

1、 输入图像文本水平排列时的样本图像与识别结果:
imageimage
2、 输入图像文本倾斜排列时的样本图像与识别结果:
imageimage
3、 裁剪ROI区域后图像:
image
4、 仿射变换后得到的字符区域:
image
5、 分割字符区域:
image
6、 字符识别:
image

思考分析

  1. 采用先识别再对结果进行校验的方法消耗太多资源,尤其是在工业中流水线识别时会浪费大量时间,一般工控机运算能力有限,实际应用时效果不佳。针对这个问题,可以先进行第一个字符的识别,随后立即进行校验,可以有效减少无效步骤。
  2. 除了识别后进行校验的方法,还可以根据字符排列的特点,如空格的空间位置,文本的排列特点等方式进行水平仿射变换,省去校验过程。
  3. 如果待识别图像文本中含有不变字符,可以使用模板匹配的方法,通过不变字符创建模板,寻找字符区域进行文字识别。
  4. 自己训练OCR文件可以显著提高识别准确率。
  5. 识别时最重要的是字符区域的确定,要找到包含字符的最小的矩形框,才能最好的与训练样本保持一致,识别准确率提高。

程序源码

* 瓶底字符识别
*
*设置系统参数
dev_update_off ()
get_system ('clip_region', Information)
set_system ('clip_region', 'true')
*读取图片
read_image (Image, 'E:/学习/大三下/机器视觉专题实践/图像/样本/1')
*获取图片尺寸
get_image_size (Image, Width, Height)
*配置窗体
dev_close_window ()
dev_open_window (0, 0, Width/4, Height/4, 'black', WindowHandle)
dev_set_colored (12)
dev_display (Image)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*
*图像处理
*预处理,裁剪出字符区域
gen_circle (CircleROI, Width/2, Height/2, 745)
reduce_domain (Image, CircleROI, ImageReduced)
*增强对比度
emphasize (ImageReduced, ImageEmphasize, 3, 3, 1)
*转化为灰度图像
rgb1_to_gray (ImageEmphasize, GrayImage)
*阈值分割
threshold (GrayImage, Image_threshold, 0, 100)
*使用矩形结构元素进行膨胀
dilation_rectangle1 (Image_threshold, RegionDilation, 12, 24)
*连接区域
connection (RegionDilation, RegionConnection)
*区域选择
select_shape (RegionConnection, RegionSelect, 'area', 'and', 1000, 50000)
*合并为一个区域
union1 (RegionSelect, RegionUnion)
*拟合成矩形
shape_trans (RegionUnion, TransShape, 'rectangle2')
*得到矩形区域的偏转角度
orientation_region (TransShape, TransShapePhi)
*计算矩形区域面积和中心点坐标
area_center (TransShape, TransShapeArea, TransShapeRow, TransShapeColumn)
*旋转图片至水平并得到仿射矩阵
vector_angle_to_rigid (TransShapeRow, TransShapeColumn, TransShapePhi, TransShapeRow, TransShapeColumn, 3.141593, HomMat2D)
*仿射矩阵应用于图片
affine_trans_image (GrayImage, ImageAffineTrans, HomMat2D, 'constant', 'false')
*仿射矩阵应用于矩形区域
affine_trans_region (TransShape, RegionAffineTrans, HomMat2D, 'nearest_neighbor')
*在原图中扣出字符区域图像
reduce_domain (ImageAffineTrans, RegionAffineTrans, ImageOCR)
*选择第一个通道
access_channel (ImageOCR, ImageOCR, 1)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*
*分割字符并识别
*阈值分割
threshold (ImageOCR, ImageOCRThreshold, 0, 100)
*膨胀
dilation_rectangle1 (ImageOCRThreshold, ImageOCRDilation, 12, 25)
*连接区域
connection (ImageOCRDilation, ImageOCRConnection)
*区域选择
select_shape (ImageOCRConnection, ImageOCRSelect, 'area', 'and', 750, 10000)
*拟合成矩形
shape_trans (ImageOCRSelect, ImageOCRRectangle, 'rectangle1')
*区域排序
sort_region (ImageOCRRectangle, ImageOCRSorted, 'upper_left', 'true', 'column')
*统计区域个数
count_obj (ImageOCRSorted, Number)
*读取OCR分类器
read_ocr_class_mlp ('E:/学习/大三下/机器视觉专题实践/test.omc', OCRHandle)
*识别
for i := 1 to Number by 1
    *选择识别的字符区域
    select_obj (ImageOCRSorted, ObjectSelected, i)
    *在灰度图中扣出字符区域图像
    reduce_domain (ImageOCR, ObjectSelected, Character)
    *使用OCR分类器进行字符识别
    do_ocr_multi_class_mlp (Character, Character, OCRHandle, Class, Confidence)
    *存放识别结果
    char[i-1] := Class
    *返回字符中心坐标
    area_center (Character, Area, charcenterRow, charcenterColum)
    charRow[i-1] := charcenterRow 
    charColum[i-1] := charcenterColum
endfor
*识别结果校验
if (char[0] == '2')
    *结果正确
else
    *旋转图片至水平并得到仿射矩阵
    vector_angle_to_rigid (TransShapeRow, TransShapeColumn, TransShapePhi, TransShapeRow, TransShapeColumn, 0, HomMat2D)
    *仿射矩阵应用于图片
    affine_trans_image (GrayImage, ImageAffineTrans, HomMat2D, 'constant', 'false')
    *仿射矩阵应用于矩形区域
    affine_trans_region (TransShape, RegionAffineTrans, HomMat2D, 'nearest_neighbor')
    *在原图中扣出字符区域图像
    reduce_domain (ImageAffineTrans, RegionAffineTrans, ImageOCR)
    *选择第一个通道
    access_channel (ImageOCR, ImageOCR, 1)
    set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
    disp_continue_message (WindowHandle, 'black', 'true')
    stop ()
    *
    *分割字符并识别
    *阈值分割
    threshold (ImageOCR, ImageOCRThreshold, 0, 100)
    *膨胀
    dilation_rectangle1 (ImageOCRThreshold, ImageOCRDilation, 12, 25)
    *连接区域
    connection (ImageOCRDilation, ImageOCRConnection)
    *区域选择
    select_shape (ImageOCRConnection, ImageOCRSelect, 'area', 'and', 1000, 20000)
    *拟合成矩形
    shape_trans (ImageOCRSelect, ImageOCRRectangle, 'rectangle1')
    *区域排序
    sort_region (ImageOCRRectangle, ImageOCRSorted, 'upper_left', 'true', 'column')
    *统计区域个数
    count_obj (ImageOCRSorted, Number)
    *读取OCR分类器
    read_ocr_class_mlp ('E:/学习/大三下/机器视觉专题实践/test.omc', OCRHandle)
    *识别
    for i := 1 to Number by 1
        *选择区域
        select_obj (ImageOCRSorted, ObjectSelected, i)
        *在灰度图中扣出字符区域图像
        reduce_domain (ImageOCR, ObjectSelected, Character)
        *使用OCR分类器进行字符识别
        do_ocr_multi_class_mlp (Character, Character, OCRHandle, Class, Confidence)
        *存放识别结果
        char[i-1] := Class
        *返回字符中心坐标
        area_center (Character, Area, charcenterRow, charcenterColum)
        charRow[i-1] := charcenterRow 
        charColum[i-1] := charcenterColum
    endfor
endif
*清除句柄
clear_ocr_class_mlp (OCRHandle)
*显示识别结果
dev_display (Image)
for i := 1 to Number by 1
    disp_message (WindowHandle, char[i-1], 'Image', charRow[i-1] + 100, charColum[i-1], 'red', 'true')
endfor
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

原创文章,作者:bd101bd101,如若转载,请注明出处:https://blog.ytso.com/270872.html

(0)
上一篇 2022年7月1日
下一篇 2022年7月1日

相关推荐

发表回复

登录后才能评论