当前帖子实现洗发水瓶上标签位置的检测。
首先在参考图片上创建瓶子和标签的形状模型,然后在随后的图片上查找 模型。
如果找到的两模型相对位置(中心X,Y,角度)与参考图片上计算的数值对比,
在要求范围内就表示合格。
实例中使用了形状模板匹配方法来定位瓶子与标签。
模板匹配定位方法其速度 相对blob分析会低些,但是在对比 度较好的环境 下匹配精度 比较高。
工业 视觉中采用形状类型的模板 匹配居多。
其具体实现过程 是 先建立 一个形状模板,在图片上搜索这个模板,
找到模板后就确定 的目标区域的坐标位置及区域,
然后在这个区域 内进行下一步的检测 识别等操作。
下面是实现实现的代码和注释:
上位机实现洗发水瓶标签偏移检测
- dev_update_off ()
- dev_set_draw ('margin')
- dev_set_line_width (2)
- * 加载一幅参考图像,用于创建模型
- set_system ('clip_region', 'false')
- read_image (Image, 'packaging/shampoo_01')
- dev_close_window ()
- dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
- set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
- dev_display (Image)
- *
- * 准备形状匹配模型,生成第一个模型区域和搜索ROI
- BottleModelRow := 131
- BottleModelColumn := 370
- BottleModelLength1 := 350
- BottleModelLength2 := 35
- BottleModelPhi := -0.1093
- gen_rectangle2 (Rectangle1, BottleModelRow, BottleModelColumn, BottleModelPhi, BottleModelLength1, BottleModelLength2)
- gen_rectangle2 (Rectangle2, BottleModelRow + 220, BottleModelColumn, -BottleModelPhi, BottleModelLength1, BottleModelLength2)
- union2 (Rectangle1, Rectangle2, TemplateBottleRegion)
- *获取图片的区域,在halcon中区域不等于图像,区域要在图像中用reduce_domain等算子截取对应图像后才有数据。
- get_domain (Image, Domain)
- *获取TemplateBottleRegion, Domain的交集区域,保存到TemplateBottleRegion
- intersection (TemplateBottleRegion, Domain, TemplateBottleRegion)
- area_center (TemplateBottleRegion, Area, RowBottleRef, ColumnBottleRef)
- gen_circle (SearchROIBottle, RowBottleRef, ColumnBottleRef, 40)
- reduce_domain (Image, TemplateBottleRegion, ImageReduced)
- *
- *创建形状模型,ImageReduced为要创建的模板函数, 5为金字塔层数, -rad(3)为模板 起始 角度 ,
- *rad(6)为模板角度范围, 0为旋转角度 步长, 'auto'为优化选项,表示 是否减少模板的像素点数,
- *这里表示自动,'use_polarity'匹配度量极性选择方式,就是匹配标准,这里使用了极性,
- *25为对应阈值, 3最小对比度, ModelIDBottle为输出 的模板句柄,后续用于模板查找。
- create_shape_model (ImageReduced, 5, -rad(3), rad(6), 0, 'auto', 'use_polarity', 25, 3, ModelIDBottle)
- *
- dev_display (Image)
- dev_set_color ('forest green')
- dev_display (TemplateBottleRegion)
- dev_set_color ('slate blue')
- disp_message (WindowHandle, 'bottle shape model', 'window', 12, 12, 'black', 'true')
- disp_continue_message (WindowHandle, 'black', 'true')
- stop ()
- * 生成第二模板区域及搜索ROI
- * generate second model region and search ROI
- LabelRow1 := 180
- LabelRow2 := 310
- LabelColumn1 := 50
- LabelColumn2 := 470
- gen_rectangle1 (TemplateLabelRegion, LabelRow1, LabelColumn1, LabelRow2, LabelColumn2)
- area_center (TemplateLabelRegion, Area1, RowLabelRef, ColumnLabelRef)
- gen_circle (SearchROILabel, RowLabelRef, ColumnLabelRef, 60)
- reduce_domain (Image, TemplateLabelRegion, ImageReduced)
- *根据金字塔层数1, 和对比度25检查要生成的模板。所谓的金字塔层数就是对图像的二次抽样,
- *如等比例抽样,把图像的像素个数每次抽取 一半,也就是每次的高宽各减一半,这样图像 层数越高,
- *抽样的像素点越少。ImageReduced为输入图像,ModelImages为ImageReduced对应输出的图像,
- *ModelRegions为输出的模板金字塔区域
- inspect_shape_model (ImageReduced, ModelImages, ModelRegions, 1, 25)
- *
- create_shape_model (ImageReduced, 5, rad(-3), rad(6), 0, 'auto', 'use_polarity', 25, 5, ModelIDLabel1)
- create_shape_model (ImageReduced, 5, rad(180 - 3), rad(6), 0, 'auto', 'use_polarity', 25, 5, ModelIDLabel2)
- ModelIDsLabel := [ModelIDLabel1,ModelIDLabel2]
- *
- dev_display (Image)
- dev_set_color ('forest green')
- dev_display (TemplateLabelRegion)
- dev_set_color ('slate blue')
- dev_display (ModelRegions)
- disp_message (WindowHandle, 'create label shape model', 'window', 12, 12, 'black', 'true')
- disp_continue_message (WindowHandle, 'black', 'true')
- stop ()
- *
- * 循环读取图片,在图片上查找标签的瓶子相对位置
- for Index := 1 to 13 by 1
- read_image (Image, 'packaging/shampoo_' + Index
- .2')
- dev_display (Image)
- disp_message (WindowHandle, 'check label position', 'window', 12, 12, 'black', 'true')
- count_seconds (s1)
- reduce_domain (Image, SearchROIBottle, ImageReduced)
- *在图像ImageReduced上查找模板ModelIDBottle,-rad(3), rad(6)分别为模板搜索的起始角度和角度范围
- *, 0.7为被找到模板实例 的最小分数也就是模板 有多少部分的像素 被找到,为百分比形式。
- *1表示要找几个实例,这里只找一个模板就好, 0.5表示被找到实例 的最大重叠 度,最多 重叠 遮挡 多大比例还表示找到,
- *least_squares'表示是否采用亚像素查找,这里采用least_squares,none为不采用,
- *0, 0.9分别表示金字塔层数和贪婪度,贪婪值越大,搜索速度越快,精度越低。
- * RowBottle, ColumnBottle, AngleBottle, ScoreBottle分别为找到模板实例的中心坐标,角度及匹配分数值。
- find_shape_model (ImageReduced, ModelIDBottle, -rad(3), rad(6), 0.7, 1, 0.5, 'least_squares', 0, 0.9, RowBottle, ColumnBottle, AngleBottle, ScoreBottle)
- * 在图像 中准备搜索ROI
- *将两个图形对象合并到第三个参数中,这里将SearchROILabel放入SearchROIs。
- concat_obj (SearchROILabel, SearchROILabel, SearchROIs)
- *对要搜索的区域添加灰度图像,也就是获取Image在区域SearchROIs的图像 数据,
- add_channels (SearchROIs, Image, GrayRegions)
- * 同时搜索多个模板实例,GrayRegions, ModelIDsLabel为要搜索的图像及模板句柄 。
- *[rad(-3),rad(180 - 3)]为模板开始的搜索角度,这里表示从两个起始角度开始搜索,
- *[rad(6),rad(6)]为模板搜索的角度范围,对应前面的起始角度。
- *0.6被查找模板的最小分数值, 1查找一个模板实例, 1被找模板实例的最大重叠 度。
- *'interpolation'采用interpolation方式查找板式, 0表示金字塔层数,
- *0.9贪婪度, Row, Column, Angle, Score, FoundModel为找到模板实例的中心点,角度,分值和找到模板实例的索引
- find_shape_models (GrayRegions, ModelIDsLabel, [rad(-3),rad(180 - 3)], [rad(6),rad(6)], 0.6, 1, 1, 'interpolation', 0, 0.9, Row, Column, Angle, Score, FoundModel)
- count_seconds (s2)
- *如果瓶子模板或标签模板没有找到,信息提示。
- if (|Score| != 1 or |ScoreBottle| != 1)
- disp_message (WindowHandle, 'Model not found', 'window', 40, 12, 'red', 'true')
- else
- if (ModelIDsLabel[FoundModel] == ModelIDLabel2)
- disp_message (WindowHandle, 'Label rotated by 180°', 'window', 40, 12, 'red', 'true')
- else
- * 计算列坐标偏差。这里是用找到的瓶子中心Y坐标减去找到的标签中心Y坐标,
- *等到的差减去在参考图片计算所得的差(RowBottleRef - RowLabelRef),最终得Y偏差。
- Diffy := (RowBottle - Row) - (RowBottleRef - RowLabelRef)
- *同样计算X偏差
- Diffx := (ColumnBottle - Column) - (ColumnBottleRef - ColumnLabelRef)
- *瓶子角度减去标签角度,得到两者角度偏差。
- Diffa := deg(AngleBottle - Angle)
- Time := s2 - s1
- * 根据X,Y,角度偏差,显示结果
- Color := 'black'
- ModelColor := 'forest green'
- if (abs(Diffx) > 3)
- Color := [Color,'red']
- ModelColor := 'red'
- else
- Color := [Color,'forest green']
- endif
- if (abs(Diffy) > 1)
- Color := [Color,'red']
- ModelColor := 'red'
- else
- Color := [Color,'forest green']
- endif
- if (abs(Diffa) > 1)
- Color := [Color,'red']
- ModelColor := 'red'
- else
- Color := [Color,'forest green']
- endif
- dev_display_shape_matching_results (ModelIDsLabel, ['slate blue',ModelColor], Row, Column, Angle, 1, 1, FoundModel)
- disp_message (WindowHandle, ['Time = ' + (Time * 1000)
- .2' + ' ms','Diff x = ' + Diffx
- .2','Diff y = ' + Diffy
- .2','Diff angle = ' + Diffa
- .2'], 'window', 35, 12, Color, 'true')
- endif
- *
- endif
- if (Index < 13)
- disp_continue_message (WindowHandle, 'black', 'true')
- stop ()
- else
- disp_message (WindowHandle, 'Program finished', 'window', 450, 430, Color, 'true')
- endif
- endfor
- stop ()
- clear_shape_model (ModelIDLabel1)
- clear_shape_model (ModelIDLabel2)
- clear_shape_model (ModelIDBottle)
- set_system ('clip_region', 'true')
复制代码
|