背景
在食品,药品及日用化学品等领域,有很大一部分产品采用瓶装容器来盛放产品。企业通常使用喷码机将产品的批号、生产日期、保质期等喷印在瓶底部位。喷码机受自身性能、机械振动等因素的影响,可能会出现多种缺陷,如字符的缺印、漏印、错印等,以上的质量问题会对企业的品牌形象及信誉产生影响。
传统的喷码字符检测采用人工全检,人工检测的工作效率低、工作强度大且容易因人眼疲劳等因素产生人为误差出现漏检、误检的情况。因此人工检测的方式已经不适应当下制造业自动化、信息化的发展趋势,基于机器视觉的字符识别算法则可以解决人工检测效率低,成本高和误差大的缺点,具有广泛的市场需求和较高的研究价值。
要求
针对瓶装产品设计基于机器视觉技术的瓶底字符识别算法,瓶底字符识别的难点在于瓶底的旋转姿态不定,致使识别的准确率难以保证,因此在字符识别之前必须对瓶底字符进行姿态矫正,使字符水平排列。
- 收集瓶体喷码字符数据(拍摄罐装饮料、调料等图像),类似下图中
样本,角度不定,多行,每行含有英文字符、数字和特殊符号(:等)。
- 设计算法,包括:图像预处理模块,字符定位模块,字符分割模块和字符识别模块。图像预处理模块用于对读取的图像进行便于操作的预先处理;字符定位模块用于将字符区域与背景区分开;字符分割模块用于将提取出的字符区域内的字符单独分割并排序;字符识别模块用于识别分割出的字符并显示。
- 设计针对瓶底图像字符分类器的训练程序,用于训练专属的分类器,进一步提高瓶底字符识别算法的准确率。
原理
Halcon已广泛应用于光学字符识别(OCR),利用Halcon中自带的工业字符识别模型可以实现多种字体的文本识别。罐装瓶底喷码字符多使用点式打印机,除使用自带的字符模型外可以根据样本进行训练,以此来提高识别准确率。
使用Halcon进行字符识别时,首先要获取水平排列的字符,分割出单个字符区域,然后再读取OCR分类器实现字符分类。
针对倾斜的文本,可以先进行仿射变换使其水平排列,不用考虑文本是否倒置。识别完成后对结果进行校验,如果识别结果符合逻辑,认为结果正确,否则认为文本倒置,调整后再进行识别,最后输出识别结果。
在实验时,待识别的图像应保证目标区域居中,即罐底应位于图片中央。图片大小一致,具有相同的长宽尺寸。在有条件的情况下,可以使用专业的检测平台获取罐底图像,拍摄时光照均匀且无明显阴影与遮盖,保证图片质量。
图片要求
- 目标居中,罐底圆形位于图片中央;
- 图片大小一致,长宽尺寸相同(正方形);
- 多角度可随意旋转(对字符而言);
- 拍摄时光照均匀无明显阴影与遮盖。
主要步骤
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. 识别结果校验
* 识别正确:显示识别结果。
* 识别错误:重新旋转图像并进行字符分割与识别;
显示识别结果。
过程步骤
- 设置圆形ROI,裁剪原图片:
生成圆形区域:gen_circle
缩小图像的域:reduce_domain - 图像处理:
增强图像对比度: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 - 字符分割:
阈值分割:threshold
使用矩形结构元素进行膨胀:dilation_rectangle1
连接区域:connection
区域选择:select_shape
拟合成矩形:shape_trans
区域排序:sort_region
统计区域个数:count_obj - 字符识别:
读取OCR分类器:read_ocr_class_mlp
选择识别的字符区域:select_obj
在灰度图中扣出字符区域图像:reduce_domain
使用OCR分类器进行字符识别:do_ocr_multi_class_mlp - 识别结果校验:
识别正确:显示识别结果。
识别错误:重新旋转图像并进行字符分割与识别;
显示识别结果。
运行结果
1、 输入图像文本水平排列时的样本图像与识别结果:
2、 输入图像文本倾斜排列时的样本图像与识别结果:
3、 裁剪ROI区域后图像:
4、 仿射变换后得到的字符区域:
5、 分割字符区域:
6、 字符识别:
思考分析
- 采用先识别再对结果进行校验的方法消耗太多资源,尤其是在工业中流水线识别时会浪费大量时间,一般工控机运算能力有限,实际应用时效果不佳。针对这个问题,可以先进行第一个字符的识别,随后立即进行校验,可以有效减少无效步骤。
- 除了识别后进行校验的方法,还可以根据字符排列的特点,如空格的空间位置,文本的排列特点等方式进行水平仿射变换,省去校验过程。
- 如果待识别图像文本中含有不变字符,可以使用模板匹配的方法,通过不变字符创建模板,寻找字符区域进行文字识别。
- 自己训练OCR文件可以显著提高识别准确率。
- 识别时最重要的是字符区域的确定,要找到包含字符的最小的矩形框,才能最好的与训练样本保持一致,识别准确率提高。
程序源码
* 瓶底字符识别
*
*设置系统参数
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 ()
原创文章,作者:kirin,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/270892.html