Fork me on GitHub

至简

Be simple

为了寻找你,我把自己搬进鸟的眼睛,经常盯着路过的风。


工业视觉项目之一:2D图像模板匹配


写在前面

这个系列我会把做的视觉项目的检测点梳理出来,但出于种种原因,项目工程代码无法开源,我尽量贴出一些Halcon代码,并且把运行时所需要的样例图片附在文中以供下载,确保能运行复现,希望对初学者有所帮助,那么这个系列就从2D图像模板匹配开始。
Halcon的模板匹配有三类:1、基于灰度;2、基于形状;3、基于描述符
在我做的项目里面,模板匹配主要解决的是定位问题,并且是基于形状。比如下面一幅图,是锂电行业某公司产线上的焊后成像,在这里模板匹配主要解决的是极柱孔的定位(红色框中)。


模板生成

read_image (Image, './1215-B.jpg')

* 1.Build the ROI from basic regions
gen_circle (ModelRegion, 418.721, 452.892, 114.265)

* 2.Reduce the model template
reduce_domain (Image, ModelRegion, TemplateImage)

* 3.Create the shape model
create_aniso_shape_model (TemplateImage, 5, rad(0), rad(360), rad(1.0527), 0.95, 1.1, 0.0092, 0.95, 1.1, 0.0092, ['none','no_pregeneration'], 'use_polarity', [29,50,25], 5, ModelID)

* 4.Save the shape model
write_shape_model (ModelID,'./InnerCircle2D.shm')

原图请点击:1215-B.jpg

在上面代码中,create_aniso_shape_model这个算子主要应用于模板在行列方向有不同形变的场合,比如上面的0.951.1即分别表示行列方向上允许的形变范围。
第二个参数如果过大,则模板不容易识别出来,这时需要将find_shape_model函数中MinScoreGreediness参数设置的低一些。如果该值过小则找到模板的时间会增加。可以先使用inspect_shape_model函数的输出结果来选择一个合适的值。如果实在不清楚如何设置,就选择默认值'auto'
第三、四、五个参数分别表示模板可能的旋转范围下限、上限和角度范围搜索步长。
第六、七、八个参数分别表示行方向形变下限、上限和形变范围搜索步长。
第九、十、十一个参数分别表示列方向形变下限、上限和形变范围搜索步长。
第十二个参数['none','no_pregeneration']'none'表示保存全部模型点,no_pregeneration表示模型不完全预先生成,模型的完全预生成通常导致运行时间稍微降低,因为模型不需要在运行时转换。然而,在这种情况下,创建模型所需的内存要求和时间要高得多。如果模型不是完全预先生成的,那么find_aniso_shape_model通常会返回稍低的分数,这可能需要为MinScore设置一个稍低于完全预生成模型的值。
第十三个参数'use_polarity'表示测试图像和模型中的对象必须具有相同的对比度。例如,如果模型是黑色背景上的明亮对象,那么在测试图像中寻找时,则只有当对象比背景更亮时才会找到该对象。
第十四个参数表示模型点应具有的对比度。对比度是对象和背景之间以及对象的不同部分之间的局部灰度值差异的度量。该参数可以是一个包含三个值的元组,元组的第一个元素决定了较低的阈值,而第二个元素确定了上限阈值,元组的最后一个元素表示找到的小于该点数的组件将被抑制。
第十五个参数表示模型应该具有的最小的对比度。
有关更多参数内容请参考Halcon官网的这里

模板使用

read_shape_model ('./InnerCircle2D.shm', ModelID)

* 1. Get the model contour for transforming it later into the image
get_shape_model_contours (ModelContours, ModelID, 1)

read_image (Image, './test2dModel.jpg')

* 2. Find the model
find_aniso_shape_model (Image, ModelID, rad(0), rad(360), 0.95, 1.1, 0.95, 1.1, 0.5, 1, 0.5, 'least_squares', [5,1], 0.75, Row, Column, Angle, ScaleRow, ScaleColumn, Score)

* 3. Transform the model contours into the detected positions
if (|Score|>0)
	hom_mat2d_identity (HomMat2D)
	hom_mat2d_scale (HomMat2D, ScaleRow, ScaleColumn, 0, 0, HomMat2D)
	hom_mat2d_rotate (HomMat2D, Angle, 0, 0, HomMat2D)
	hom_mat2d_translate (HomMat2D, Row, Column, HomMat2D)
	affine_trans_contour_xld (ModelContours, TransContours, HomMat2D)
		
	gen_region_contour_xld (TransContours, Region2, 'filled')
	union1 (Region2, RegionUnion)
	shape_trans (RegionUnion, RegionTrans2, 'convex')
	gen_contour_region_xld (RegionTrans2, Contours, 'border')
	fit_circle_contour_xld (Contours, 'algebraic', -1, 0, 0, 3, 2, RowPole, ColumnPole, RadiusPole, StartPhi, EndPhi, PointOrder)
	gen_circle (BlackPoleRegion, RowPole, ColumnPole, RadiusPole)
else
	* do sth.
endif

测试图片请点击:test2dModel.jpg

在上面代码中,find_aniso_shape_model算子的大部分参数已经描述,有关更多参数内容请参考Halcon官网的这里
如果根据模板能定位到,那么BlackPoleRegion就是要定位的极柱孔内圆区域,其实在实际工业场景中,为了保证算法的稳定性,通常要加很多规则,体现在上面代码的话就是else内的处理方法,在此不一一赘述。