《HALCON机器视觉与算法原理编程实践》第11章 模板匹配

文章目录

  • 11.1 模板匹配的种类
    • 11.1.1 基于灰度值的模板匹配
    • 11.1.2 基于相关性的模板匹配
    • 11.1.3 基于形状的模板匹配
    • 11.1.4 基于组件的模板识别
    • 11.1.5 基于形变的模板匹配
    • 11.1.6 基于描述符的模板匹配
    • 11.1.7 基于点的模板匹配
    • 11.1.8 模板匹配方法总结
  • 11.2 图像金字塔
  • 11.3 模板图像
    • 11.3.1 从参考图像的特定区域中创建模板
    • 11.3.2 使用XLD轮廓创建模板
  • 11.4 模板匹配的步骤
    • 11.4.1 基于灰度值的模板匹配
    • 11.4.2 基于相关性的模板匹配
    • 11.4.3 基于形状的模板匹配
    • 11.4.4 基于组件的模板匹配
    • 11.4.5 基于局部形变的模板匹配
    • 11.4.6 基于透视形变的模板匹配
    • 11.4.7 基于描述符的模板匹配
    • 11.4.8 优化匹配速度
    • 11.4.9 使用Halcon匹配助手进行匹配
  • 11.5 指定区域的形状匹配

模板匹配是一种最原始、最基本的模式识别方法,研究某一特定对象物的图案位于图像的什么地方,进而识别对象物,这就是一个匹配问题。它是图像处理中最基本、最常用的匹配方法。

11.1 模板匹配的种类

针对不同的图像特征和检测环境,有多种模板匹配算法。如何选择合适的模板匹配算法,取决于具体的图像数据和匹配任务。

11.1.1 基于灰度值的模板匹配

这种算法的根本思想是,计算模板图像与检测图像之间的像素灰度差值的绝对值综总和(SAD方法)或者平方差总和(SSD方法)。

其原理是:首先选择一块ROI(感兴趣区域)作为模板图像,生成基于灰度值的模板;然后
将检测图像与模板图像进行粗匹配,在检测图像与模板图像中任选一点,采取隔点搜索的方式计算二者灰度的相似性,这样粗匹配一遍得到粗相关点;接下来进行精匹配,将得到的粗相关点作为中心点,用最小二乘法寻找二者之间的最优匹配点。

注意:只有针对极少数的简单图像,才会考虑基于灰度值的匹配

1.创建模板:create_template()2.寻找模板:best_match()3.释放模板:clear_template()

11.1.2 基于相关性的模板匹配

NCC是一种基于统计学计算两组样本数据相关性的算法,其取值范围为[-1, 1]之间,而对图像来说,每个像素点都可以看出是RGB数值,这样整幅图像就可以看成是一个样本数据的集合,如果它有一个子集与另外一个样本数据相互匹配则它的ncc值为1,表示相关性很高,如果是-1则表示完全不相关,基于这个原理,实现图像基于模板匹配识别算法,其中第一步就是要归一化数据,数学公式如下:

该方法不但能适应光照变化,对小范围的遮挡和缺失也同样适用,同时还适用于聚焦不清的图像和形状变形,因此在实际工程中应用比较广泛。但是,该方法也有其局限性,如果与参考图像相比,检测图像的位移、旋转或者缩放比较大,可能会导致匹配失败。

注意:一般应在检测图像中指定匹配区域,然后再该区域中进行搜索

1.创建模板:create_ncc_model()2.寻找模板:find_ncc_model()3.释放模板:clear_ncc_model()

11.1.3 基于形状的模板匹配

该方法使用边缘特征定位物体,对于很多干扰因素不敏感,如光照和图像的灰度变化,甚至可以支持局部边缘缺失、杂乱场景、噪声、失焦和轻微形变的模型。更进一步说,它甚至可以支持多个模板同步进行搜索。但是,在搜索过程中,如果目标图像发生大的旋转或缩放,则会影响搜索的结果,因此不适用于旋转和缩放比较大的情况。

1.创建形状模型:create_shape_model()2.寻找形状模型:find_shpae_model()3.释放形状模型:clear_shape_model()

11.1.4 基于组件的模板识别

基于组件的模板匹配可以说是基于形状的模板匹配的加强版,加强的地方在于,这种方法允许模板中包含多个目标,并且允许目标之间存在相对运动(位移和旋转)。这决定了这种方式不适用于尺寸缩放的情况。由于有多个ROI,且需要检测多个ROI之间的相对运动关系,因此这种方法与基于形状的模板匹配相比要稍微复杂一点,且不适用于失焦图像和轻微形变的目标。图114是个基于组件的模板匹配的例子。

11.1.5 基于形变的模板匹配

形变分为两种,一种是基于目标局部的形变,另一种是由于透视关系而产生的形变。基于形变的模板匹配也是一种基于形状的匹配方法,但不同的是,其返回结果中不仅包括轻微形变的形状、形变的位置和参数,还有描述形变的参数,如旋转角度、缩放倍数等。

基于形变的模板匹配对于很多干扰因素不敏感,如光照变化、混乱无序、缩放变化等。其适用于多通道图像,对于纹理复杂的图像匹配则不太适用。

1.创建模板:create_local_deformable_model()2.寻找模板:find_local_deformable_model()3.释放模板:clear_deformable_model()

11.1.6 基于描述符的模板匹配

注意:基于描述符的模板匹配只能用于有纹理的图像

1.创建模板:create_calib_descriptor_model()2.寻找模板:find_calib_descriptor_model()3.释放模板:clear_descriptor_model()

11.1.7 基于点的模板匹配

主要用在三维匹配中

11.1.8 模板匹配方法总结

在二维匹配中,最常用的还是基于形状的匹配和基于相关性的匹配。

11.2 图像金字塔

以多个分辨率来表示图像的一种有效且概念简单的结构是图像金字塔。图像金字塔最初用于机器视觉和图像压缩,一个图像金字塔是一系列以金字塔形状排列的,分辨率逐步降低的图像集合。金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

11.3 模板图像

可以从参考图像特定区域创建模板,也可以使用XLD轮廓创建合适的模板。

11.3.1 从参考图像的特定区域中创建模板

模板匹配的第一步,是准备好合适的模板。

注意:如果想得到质量比较好的模板,ROI中应尽可能少的包含噪声和杂乱场景

11.3.2 使用XLD轮廓创建模板

11.4 模板匹配的步骤

不同的模板匹配方法,其操作步骤也不一样。

11.4.1 基于灰度值的模板匹配

dev_close_window ()dev_open_window (0, 0, 599, 464, 'black', WindowID)*读取了一幅彩色图像read_image (Imagecolor, 'data/holesBoard')*将其转化为灰度图像rgb1_to_gray (Imagecolor, Image)dev_set_draw ('margin')dev_set_line_width(3)Row1 :=700Column1 := 950Row2 := 906Column2 := 1155*选择了一块矩形的ROI区域gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)dev_display (Rectangle)*将ROI区域进行裁剪,变成模板图像reduce_domain (Image, Rectangle, ImageReduced)*创建模板,因为光照比较稳定,GrayValues选择‘original’create_template (ImageReduced, 5, 4, 'sort', 'original', TemplateID)*读取测试图像read_image (ImageNoise, 'data/holesBoardNoise')*应用灰度模板并进行匹配adapt_template (ImageNoise, TemplateID)best_match_mg (ImageNoise, TemplateID, 35, 'false', 4, 'all', Row_, Column_, Error_)dev_clear_window ()dev_display (ImageNoise)*根据匹配返回的坐标中心,绘制矩形标识框,将匹配到的目标框选出来disp_rectangle2 (WindowID, Row_, Column_, 0, 95, 95)*匹配结束,释放模板资源clear_template (TemplateID)

11.4.2 基于相关性的模板匹配

*读取参考的原始图像。如果是彩色的,需要先转化为单通道灰度图像read_image (Image, 'data/carmex-0')get_image_size (Image, Width, Height)dev_close_window ()dev_open_window (0, 0, Width, Height, 'black', WindowHandle)*设置窗口绘制参数,线宽设为3dev_set_line_width(3)dev_set_draw ('margin')*创建圆形,因为目标区域是圆形,因为用圆形将ROI区域选择出来gen_circle (Circle, 161, 208, 80)*获取圆形的中心点,为匹配后的可视化显示结果做准备area_center (Circle, Area, RowRef, ColumnRef)*裁剪ROI区域,得到模板图像reduce_domain (Image, Circle, ImageReduced)*创建基于相关性的匹配模型,输入模板图像和模型参数create_ncc_model (ImageReduced, 'auto', 0, 0, 'auto', 'use_polarity', ModelID)*显示原始图像和圆形框dev_display (Image)dev_display (Circle)stop ()*读取测试图像。该测试图像和参考图像比起来有轻微的位移,旋转,缩放,以及失焦read_image (Image2, 'data/carmex-1')*进行行基于相关性的模板匹配find_ncc_model (Image2, ModelID, 0, 0, 0.5, 1, 0.5, 'true', 0, Row, Column, Angle, Score)vector_angle_to_rigid (RowRef, ColumnRef, 0, Row, Column, 0, HomMat2D)*对圆形进行仿射变换,使其将匹配的结果目标标识出来affine_trans_region (Circle, RegionAffineTrans, HomMat2D, 'nearest_neighbor')*显示测试画面和圆形标记圈dev_display (Image2)dev_display (RegionAffineTrans)*匹配结束,释放模板资源clear_ncc_model (ModelID)

11.4.3 基于形状的模板匹配

*读取参考图像read_image(Image, 'data/labelShape-0')*根据要匹配的目标,围绕目标创建一个矩形,获取ROI区域gen_rectangle1 (Rectangle, 34, 290, 268, 460)*对ROI区域进行裁剪,得到模板图像reduce_domain (Image, Rectangle, ImageReduced)*测试金字塔的层级参数inspect_shape_model (ImageReduced, ModelImages, ModelRegions, 4, 30)*设置显示图像、绘制线条的线宽等窗口参数dev_set_draw ('margin')dev_set_line_width(3)dev_display(Image)dev_display(Rectangle)*根据剪裁的模板图像创建基于形状的模板,返回模板句柄ShapeModelIDcreate_shape_model (ImageReduced, 5, rad(-10), rad(20), 'auto', 'none', 'use_polarity', 20, 10, ShapeModelID)stop()*读取用于测试的图像read_image(SearchImage, 'data/labelShape-1')*使用匹配算子进行形状模板匹配find_shape_model (SearchImage, ShapeModelID, 0, rad(360), 0.5, 3, 0, 'least_squares', 0, 0.5, RowCheck, ColumnCheck, AngleCheck, Score)*显示匹配结果,将匹配得到的实例以形状轮廓的形式绘制出来dev_display_shape_matching_results (ShapeModelID, 'red', RowCheck, ColumnCheck, AngleCheck, 1, 1, 0)*匹配结束,释放模板资源clear_shape_model (ShapeModelID)

11.4.4 基于组件的模板匹配

dev_close_window ()*读取参考图像,这里读取的是单通道灰度图像read_image (ModelImage, 'data/bolts-0') *设置显示图像、绘制线条等窗口参数dev_open_window_fit_image (ModelImage, 0, 0, -1, -1, WindowHandle)dev_display (ModelImage)dev_set_draw ('margin')dev_set_line_width(3)stop ()*定义各个组件, 选取各个组件的ROI区域gen_rectangle1 (Rectangle1, 140, 71, 279, 168)gen_rectangle1 (Rectangle2, 181, 281,285, 430)gen_circle (Circle, 106, 256, 60)*将所有组件放进一个名为ComponentRegions的Tuple中concat_obj (Rectangle1, Rectangle2, ComponentRegions)concat_obj (ComponentRegions, Circle, ComponentRegions)*显示参考图像,以及选择的各个组件区域。核对区域选择是否理想dev_display (ModelImage)dev_display (ComponentRegions)stop ()*创建基于组件的模板,返回模板句柄ComponentModelIDcreate_component_model (ModelImage, ComponentRegions, 20, 20, rad(25), 0, rad(360), 15, 40, 15, 10, 0.8, 3, 0, 'none', 'use_polarity', 'true', ComponentModelID, RootRanking)*读取测试图像,该测试图像相对于参考图像有一定的位移和旋转。read_image (SearchImage, 'data/bolts-1')*在参考图像模板的基础上,进行基于基于组件的匹配find_component_model (SearchImage, ComponentModelID, RootRanking, 0, rad(360), 0.5, 0, 0.5, 'stop_search', 'search_from_best', 'none', 0.8, 'interpolation', 0, 0.8, ModelStart, ModelEnd, Score, RowComp, ColumnComp, AngleComp, ScoreComp, ModelComp)*显示测试图像dev_display (SearchImage)*对每一个检测到的组件实例进行可视化的显示for Match := 0 to |ModelStart| - 1 by 1dev_set_line_width (4)*获得每个组件的实例和位移旋转等参数get_found_component_model (FoundComponents, ComponentModelID, ModelStart, ModelEnd, RowComp, ColumnComp, AngleComp, ScoreComp, ModelComp, Match, 'false', RowCompInst, ColumnCompInst, AngleCompInst, ScoreCompInst)dev_display (FoundComponents)endforstop ()*匹配结束,释放模板资源clear_component_model (ComponentModelID)

11.4.5 基于局部形变的模板匹配

dev_close_window ()*读取参考图像,这里读取的是单通道灰度图像*这里的参考图像是已经剪裁好的感兴趣区域图像,可以直接作为模板图像read_image (ModelImage, 'data/creamlabel')*设置显示窗口参数dev_open_window_fit_image (ModelImage, 0, 0, -1, -1, WindowHandle)*创建局部形变模板,返回局部形变模板句柄ModelIDcreate_local_deformable_model (ModelImage, 'auto', rad(-15), rad(30), 'auto', 1, 1, 'auto', 1, 1, 'auto', 'none', 'use_polarity', [40,60], 'auto', [], [], ModelID)*获取局部形变模板的轮廓get_deformable_model_contours (ModelContours, ModelID, 1)*为了将模板轮廓可视化显示,需要将轮廓与图像实物对应起来*因此出于可视化显示的目的,先获取模板图像的几何中心area_center (ModelImage, Area, Row, Column)*进行仿射变换hom_mat2d_identity (HomMat2DIdentity)hom_mat2d_translate (HomMat2DIdentity, Row, Column, HomMat2DTranslate)affine_trans_contour_xld (ModelContours, ContoursAffinTrans, HomMat2DTranslate)*设置轮廓显示的线条参数,显示模板图像与轮廓dev_set_line_width (2)dev_display (ModelImage)dev_display (ContoursAffinTrans)stop ()*读取测试图像,这里的图像中更包含模板图像,并且有一定的形变read_image (DeformedImage, 'data/cream')*显示用于测试的局部形变图像dev_resize_window_fit_image (DeformedImage, 0, 0, -1, -1)dev_display (DeformedImage)*进行局部形变模板匹配find_local_deformable_model (DeformedImage, ImageRectified, VectorField, DeformedContours, ModelID, rad(-14), rad(28), 0.9, 1, 0.9, 1, 0.78, 0, 0, 0, 0.7, ['image_rectified','vector_field','deformed_contours'], ['deformation_smoothness','expand_border','subpixel'], [18,0,0], Score, Row, Column)*显示形变轮廓dev_display (DeformedImage)dev_set_line_width (2)dev_set_color ('red')dev_display (DeformedContours)stop()*匹配结束,释放模板资源clear_deformable_model (ModelID)

11.4.6 基于透视形变的模板匹配

(1)选择ROI
(2)创建基于透视形变的匹配模型
(3)搜索目标
(4)清除模型

11.4.7 基于描述符的模板匹配

dev_close_window ()*读取参考图像,这里的参考图像应只包含识别的关键区域,用于创建模板read_image (ImageLabel, 'data/labelShape-0')*设置窗口参数用于显示图像get_image_size (ImageLabel, Width, Height)dev_open_window (0, 0, Width, Height, 'black', WindowHandle1)dev_set_draw ('margin')dev_display (ImageLabel)*设置用于存储特征点和感兴趣区域的变量NumPoints := []RowRoi := [10,10,Height - 10,Height - 10]ColRoi := [10,Width - 10,Width - 10,10]*将参考图像中的除边缘外的区域都设为感兴趣区域。因为参考图像已经近似于匹配的纹理样本gen_rectangle1 (Rectangle, 10, 10, Height - 10, Width - 10)*显示参考图像上选择的ROI区域dev_set_line_width (4)dev_display (Rectangle)stop ()*将感兴趣区域剪裁为模板图像reduce_domain (ImageLabel, Rectangle, ImageReduced)dev_clear_window ()dev_display (ImageLabel)*创建基于描述符的模板create_uncalib_descriptor_model (ImageReduced, 'harris_binomial', [], [], ['min_rot','max_rot','min_scale','max_scale'], [-90,90,0.2,1.1], 42, ModelID)*设置模型的原点,为了后面获取坐标作参照set_descriptor_model_origin (ModelID, -Height / 2, -Width / 2)*获取模型中特征点的位置get_descriptor_model_points (ModelID, 'model', 'all', Row_D, Col_D)*将模型中计算出的特征点存入NumPoints变量中NumPoints := [NumPoints,|Row_D|]*读取测试图像,这里读取的是单通道灰度图像,因此省略了通道转化的步骤read_image (ImageGray, 'data/labelShape-1')dev_resize_window_fit_image (ImageGray, 0, 0, -1, -1)dev_display (ImageGray)*对描述符特征点进行匹配find_uncalib_descriptor_model (ImageGray, ModelID, 'threshold', 800, ['min_score_descr','guided_matching'], [0.003,'on'], 0.25, 1, 'num_points', HomMat2D, Score)*显示匹配结果,将特征点用不同的颜色绘制出来if ((|HomMat2D| > 0) and (Score > NumPoints[0] / 4))    get_descriptor_model_points (ModelID, 'search', 0, Row, Col)*创建十字标识符    gen_cross_contour_xld (Cross, Row, Col, 6, 0.785398)    projective_trans_region (Rectangle, TransRegion, HomMat2D, 'bilinear')    projective_trans_pixel (HomMat2D, RowRoi, ColRoi, RowTrans, ColTrans)    angle_ll (RowTrans[2], ColTrans[2], RowTrans[1], ColTrans[1], RowTrans[1], ColTrans[1], RowTrans[0], ColTrans[0], Angle)    Angle := deg(Angle)    if (Angle > 70 and Angle < 110)        area_center (TransRegion, Area, Row, Column)        dev_set_color ('green')        dev_set_line_width (4)        dev_display (TransRegion)        dev_set_colored (6)        dev_display (Cross)                   endifendifstop ()*匹配结束,释放模板资源clear_descriptor_model (ModelID)

11.4.8 优化匹配速度

可从两个方面下手:缩小搜索空间和使用图像不采样。

11.4.9 使用Halcon匹配助手进行匹配

(1)选择匹配方法
(2)创建模板
(3)检测模板
(4)优化匹配速度

11.5 指定区域的形状匹配

* 这个例子用来介绍 HALCON中的形状模板匹配dev_close_window()*读取图像并获取其宽高read_image(ModelImage, 'data/arrow1')median_image (ModelImage, ImageMedian, 'circle', 6, 'mirrored')get_image_size(ModelImage, Width,Height)dev_open_window (0, 0, Width/2, Height/2, 'white', WindowHandle)*显示模板图像dev_display (ModelImage)* 设置画笔颜色和线条dev_set_color ('yellow')dev_set_line_width (3)* -------------------  形状模板匹配程序  ----------------*第1步:选择模板中的目标Row1 := 281Column1 := 160Row2 := 440Column2 := 312*用矩形框选定一个目标区域gen_rectangle1 (ROI, Row1, Column1, Row2, Column2)*显示ROI区域dev_display (ROI) *剪裁出这个区域reduce_domain (ModelImage, ROI, ImageROI)*第2步,创建模板 *检查模板参数inspect_shape_model (ImageROI, ShapeModelImages, ShapeModelRegions, 4, 50) *显示金字塔各层级的图像,以检查层数的合理性dev_display (ShapeModelRegions)area_center (ShapeModelRegions, AreaModelRegions, RowModelRegions,ColumnModelRegions)count_obj (ShapeModelRegions, HeightPyramid) *确定金字塔的层级for i := 1 to HeightPyramid by 1if (AreaModelRegions[i - 1] >= 15)        NumLevels := i    endifendfor *使用ROI图像创建模板create_shape_model (ImageROI, NumLevels, 0, rad(360), 'auto', 'none', 'ignore_global_polarity', 50, 10, ModelID)*获取轮廓信息,用于结果显示get_shape_model_contours (ShapeModel, ModelID, 1)* step 3: 在检测图像中搜索模板*读取检测图像read_image(SearchImage, 'data/arrow2')*寻找最佳模板匹配find_shape_model (SearchImage, ModelID, 0, rad(360), 0.3, 1, 0.5, 'least_squares', 0, 0.7,RowCheck, ColumnCheck, AngleCheck, Score)*如果找到了目标,则将它标示出来if (|Score| > 0.9)*计算刚性变换矩阵vector_angle_to_rigid (0, 0, 0, RowCheck, ColumnCheck, AngleCheck,MovementOfObject)*应用二维仿射变换XLD轮廓,以便在图像中显示检测到的轮廓affine_trans_contour_xld (ShapeModel, ModelAtNewPosition, MovementOfObject)*显示检测图像     gen_rectangle2 (recResult, RowCheck, ColumnCheck, AngleCheck, 80, 80)     dev_set_draw ('margin')dev_display (SearchImage)     *标示出检测到的模板dev_display (ModelAtNewPosition)dev_set_color ('blue')dev_display (recResult)endif* -------------------  程序结束  -----------------* 清除模板clear_shape_model (ModelID)
(0)

相关推荐