在食品,药品及日用化学品等领域,有很大一部分产品采用瓶装容器来盛放产品。企业通常使用喷码机将产品的批号、生产日期、保质期等喷印在瓶底部位。喷码机受自身性能、机械振动等因素的影响,可能会出现多种缺陷,如字符的缺印、漏印、错印等,以上的质量问题会对企业的品牌形象及信誉产生影响。
传统的喷码字符检测采用人工全检,人工检测的工作效率低、工作强度大且容易因人眼疲劳等因素产生人为误差出现漏检、误检的情况。因此人工检测的方式已经不适应当下制造业自动化、信息化的发展趋势,基于机器视觉的字符识别算法则可以解决人工检测效率低,成本高和误差大的缺点,具有广泛的市场需求和较高的研究价值。
针对瓶装产品设计基于机器视觉技术的瓶底字符识别算法,瓶底字符识别的难点在于瓶底的旋转姿态不定,致使识别的准确率难以保证,因此在字符识别之前必须对瓶底字符进行姿态矫正,使字符水平排列。
Halcon已广泛应用于光学字符识别(OCR),利用Halcon中自带的工业字符识别模型可以实现多种字体的文本识别。罐装瓶底喷码字符多使用点式打印机,除使用自带的字符模型外可以根据样本进行训练,以此来提高识别准确率。
使用Halcon进行字符识别时,首先要获取水平排列的字符,分割出单个字符区域,然后再读取OCR分类器实现字符分类。
针对倾斜的文本,可以先进行仿射变换使其水平排列,不用考虑文本是否倒置。识别完成后对结果进行校验,如果识别结果符合逻辑,认为结果正确,否则认为文本倒置,调整后再进行识别,最后输出识别结果。
在实验时,待识别的图像应保证目标区域居中,即罐底应位于图片中央。图片大小一致,具有相同的长宽尺寸。在有条件的情况下,可以使用专业的检测平台获取罐底图像,拍摄时光照均匀且无明显阴影与遮盖,保证图片质量。
* 生成圆形区域: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、 字符识别:
* 瓶底字符识别 * *设置系统参数 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 ()