图像处理(8) 模板匹配_模板匹配的图像模板,算法太TM重要了

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新大数据全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注大数据)
img

正文

基于相关性的模板匹配其实是另一种基于灰度值的匹配,不过它的特点是使用一种归一化的互相关匹配(Normalized Cross Correlation,NCC)来衡量模板图像和检测图像之间的关系,因此,在光照方面受的影响比较小。与经典的基于灰度值的匹配算法不同的是,它的速度要快很多。与基于形状模板的匹配算法相比,它的优势是对一些形状有细微变化的、纹理复杂的或者是聚焦模糊的检测图像都能检索得到。

其原理是:把模板图像中的所有像素按列顺序组成一个行向量a,即模板的特征向量,然后在检测图像上寻找与模板最匹配的区域b,通过计算两个向量的夹角,来衡量匹配的概率,如下面所示:

以下是一个实例:

read_image (Image, 'cap_exposure/cap_exposure_03')
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_update_off ()
gen_circle (Circle, 246, 336, 150)
area_center (Circle, Area, RowRef, ColumnRef)
reduce_domain (Image, Circle, ImageReduced)
create_ncc_model (ImageReduced, 'auto', 0, 0, 'auto', 'use_polarity', ModelID)
dev_set_draw ('margin')
dev_display (Image)
dev_set_color ('yellow')
dev_display (Circle)
disp_message (WindowHandle, 'Trained NCC model', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
Rows := []
Cols := []
for J := 1 to 10 by 1
    read_image (Image, 'cap_exposure/cap_exposure_' + J$'02')
    find_ncc_model (Image, ModelID, 0, 0, 0.5, 1, 0.5, 'true', 0, Row, Column, Angle, Score)
    Rows := [Rows,Row]
    Cols := [Cols,Column]
    dev_display (Image)
    dev_display_ncc_matching_results (ModelID, 'green', Row, Column, Angle, 0)
    disp_message (WindowHandle, 'Found NCC model', 'window', 12, 12, 'black', 'true')
    if (J < 10)
        disp_continue_message (WindowHandle, 'black', 'true')
    endif
    stop ()
endfor

选取一块圆形区域作为模板图像,并根据其灰度值创建模板。当检测图像亮度和形状变化很大还是能够匹配得到。

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

三、基于形状的模板匹配

基于形状的模板匹配,也称为基于边缘方向梯度的匹配,是一种最常用也最前沿的模板匹配算法。该算法以物体边缘的梯度相关性作为匹配标准,原理是提取ROI中的边缘特征,结合灰度信息创建模板,并根据模板的大小和清晰度的要求生成多层级的图像金字塔模型。接着在图像金字塔层中自上而下逐层搜索模板图像,直到搜索到最底层或得到确定的匹配结果为止。

以下是一个实例:

dev_update_pc ('off')
dev_update_window ('off')
dev_update_var ('off')
read_image (Image, 'green-dot')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_set_color ('red')
dev_display (Image)
threshold (Image, Region, 0, 128)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 10000, 20000)
fill_up (SelectedRegions, RegionFillUp)
dilation_circle (RegionFillUp, RegionDilation, 5.5)
reduce_domain (Image, RegionDilation, ImageReduced)
create_scaled_shape_model (ImageReduced, 5, rad(-45), rad(90), 'auto', 0.8, 1.0, 'auto', 'none', 'ignore_global_polarity', 40, 10, ModelID)
get_shape_model_contours (Model, ModelID, 1)
area_center (RegionFillUp, Area, RowRef, ColumnRef)
vector_angle_to_rigid (0, 0, 0, RowRef, ColumnRef, 0, HomMat2D)
affine_trans_contour_xld (Model, ModelTrans, HomMat2D)
dev_display (Image)
dev_display (ModelTrans)
read_image (ImageSearch, 'green-dots')
dev_display (ImageSearch)
dev_set_line_width (3)
find_scaled_shape_model (ImageSearch, ModelID, rad(-45), rad(90), 0.8, 1.0, 0.5, 0, 0.5, 'least_squares', 5, 0.8, Row, Column, Angle, Scale, Score)
for I := 0 to |Score| - 1 by 1
    hom_mat2d_identity (HomMat2DIdentity)
    hom_mat2d_translate (HomMat2DIdentity, Row[I], Column[I], HomMat2DTranslate)
    hom_mat2d_rotate (HomMat2DTranslate, Angle[I], Row[I], Column[I], HomMat2DRotate)
    hom_mat2d_scale (HomMat2DRotate, Scale[I], Scale[I], Row[I], Column[I], HomMat2DScale)
    affine_trans_contour_xld (Model, ModelTrans, HomMat2DScale)
    dev_display (ModelTrans)
endfor

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

四、基于组件的模板匹配

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

以下是一个实例:

dev_update_off ()
dev_close_window ()
read_image (ModelImage, 'modules/modules_model')
dev_open_window_fit_image (ModelImage, 0, 0, -1, -1, WindowHandle)
dev_display (ModelImage)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
Message := 'This program shows how to use the'
Message[1] := 'component-based matching'
Message[2] := 'to locate a compound object'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 
* Define the regions for the components
gen_rectangle2 (ComponentRegions, 318, 109, -1.62, 34, 19)
gen_rectangle2 (Rectangle2, 342, 238, -1.63, 32, 17)
gen_rectangle2 (Rectangle3, 355, 505, 1.41, 25, 17)
gen_rectangle2 (Rectangle4, 247, 448, 0, 14, 8)
gen_rectangle2 (Rectangle5, 237, 537, -1.57, 13, 10)
concat_obj (ComponentRegions, Rectangle2, ComponentRegions)
concat_obj (ComponentRegions, Rectangle3, ComponentRegions)
concat_obj (ComponentRegions, Rectangle4, ComponentRegions)
concat_obj (ComponentRegions, Rectangle5, ComponentRegions)
dev_set_colored (12)
dev_set_draw ('margin')
dev_set_line_width (2)
dev_display (ModelImage)
dev_display (ComponentRegions)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
disp_message (WindowHandle, 'Regions of the components', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 
* Create the component model by explicitly specifying the relations
create_component_model (ModelImage, ComponentRegions, 20, 20, rad(25), 0, rad(360), 15, 40, 15, 10, 0.8, [4,3,3,3,3], 0, 'none', 'use_polarity', 'true', ComponentModelID, RootRanking)
* 
* Find the component model in a run-time image
ImageName := 'modules/modules_'
for I := 1 to 12 by 1
    read_image (SearchImage, ImageName + I$'.2d')
    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)
    * Display the found component models
    for Match := 0 to |ModelStart| - 1 by 1
        dev_set_line_width (1)
        get_found_component_model (FoundComponents, ComponentModelID, ModelStart, ModelEnd, RowComp, ColumnComp, AngleComp, ScoreComp, ModelComp, Match, 'false', RowCompInst, ColumnCompInst, AngleCompInst, ScoreCompInst)
        dev_display (FoundComponents)
    endfor
    disp_message (WindowHandle, 'Found component models', 'window', 12, 12, 'black', 'true')
    * If the program shall stop after every image, the following lines
    * must be activated
    if (I < 12)
        disp_continue_message (WindowHandle, 'black', 'true')
    endif
    stop ()
endfor

本例在图中选取了几个元器组件作为模板图像,并根据其形状和相对关系创建了模板,图像在旋转的情况下仍得到了理想的匹配结果。

基于组件的模板匹配适用于组成部件之间有相对运动的物体,使用边缘特征定位物体,对于很多干扰因素不敏感,如光照变化、混乱无序等。其适用于多通道图像,不适用于纹理图像、聚焦不清的图像和形状变形的图像。

五、基于形变的模板匹配

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

基于透视的形变可以返回一个二维投影变换矩阵。如果是在相机标定的情况下,通过相机参数,还可以计算出目标的三维位姿。

以下是一个实例:

dev_update_off ()
dev_close_window ()
read_image (ModelImage, 'food/peanut_chocolate_candies_model')
dev_open_window_fit_image (ModelImage, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
* 
* 创建一个模板
create_local_deformable_model (ModelImage, 'auto', [], [], 'auto', 1, [], 'auto', 1, [], 'auto', 'none', 'use_polarity', 65, 25, [], [], 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, ContoursAffineTrans, HomMat2DTranslate)
dev_set_line_width (2)
dev_set_color ('yellow')
dev_display (ModelImage)
dev_display (ContoursAffineTrans)
disp_message (WindowHandle, 'Model image and contours', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
​
Smoothness := 19
NumImages := 12
for Index := 1 to NumImages by 1
    read_image (Image, 'food/peanut_chocolate_candies_' + Index$'02')
    dev_resize_window_fit_image (Image, 0, 0, -1, -1)
    dev_display (Image)
    disp_message (WindowHandle, 'Search ...', 'window', 12, 12, 'black', 'true')
    count_seconds (S1)
​
    * 查找
    find_local_deformable_model (Image, ImageRectified, VectorField, DeformedContours, ModelID, rad(-120), rad(60), 1, 1, 1, 1, 0.3, 0, 0.7, 0, 0.1, ['vector_field','deformed_contours'], ['deformation_smoothness','expand_border','subpixel'], [Smoothness,0,0], Score, Row, Column)
    count_seconds (S2)
    Time := S2 - S1
  
    * 显示结果
    gen_warped_mesh (VectorField, WarpedMesh, Smoothness)
    dev_set_line_width (1)
    dev_set_color ('yellow')
    dev_display (WarpedMesh)
    Found[Index] := |Score|
    dev_set_line_width (2)
    dev_set_color ('green')
    dev_display (DeformedContours)
    disp_message (WindowHandle, |Score| + ' matches found in ' + Time$'1.2f' + ' s', 'window', 12, 12, 'black', 'true')
    disp_message (WindowHandle, 'Score: ' + Score$'.2f', 'image', 350, Column - 80, 'black', 'true')
    if (Index < NumImages)
        disp_continue_message (WindowHandle, 'black', 'true')
        stop ()
    endif
endfor

六、基于描述符的模板匹配

与基于透视形变的模板匹配类似,基于描述符的模板匹配能够在物体处于透视形变的状态下进行匹配,并且已标定和未标定的相机图像都适用。与透视形变不同的是,它的模板不是根据边缘轮廓创建的,而是根据特征点创建的。

点的位置或相邻像素的灰度信息等都可以作为描述符。有纹理的平面图形非常适用于这种方法,尤其是对于旋转倾斜等场景中的匹配可以得到非常理想的结果。

以下是一个实例:

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]


**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)**
![img](https://img-blog.csdnimg.cn/img_convert/e9343eb759eb2ecde88c25dd3aab805d.png)

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

储特征点和感兴趣区域的变量
NumPoints := []
RowRoi := [10,10,Height - 10,Height - 10]


**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)**
[外链图片转存中...(img-0n3Ph7d1-1713384973014)]

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

#模板匹配 import cv2 as cv import numpy as np def template_demo(): dog = cv.imread("E:/opencv/picture/dog.jpg") dog_nose = cv.imread("E:/opencv/picture/nose.jpg") cv.imshow("dog",dog) result = cv.matchTemplate(dog,dog_nose,cv.TM_CCORR_NORMED) h,w =dog_nose.shape[:2] min_val,max_val,min_loc,max_loc=cv.minMaxLoc(result) pt1 = max_loc pt2 = (pt1[0]+w,pt1[1]+h) cv.rectangle(dog,pt1,pt2,(0,255,0),2) cv.imshow("match",dog) print(result) #src = cv.imread("E:/opencv/picture/dog.jpg") #cv.imshow("inital_window",src) template_demo() cv.waitKey(0) cv.destroyAllWindows() 分析: 模板匹配通常用于目标检测。本文我们检测狗图片的鼻子。 • 我们需要两个主要组件: 1. 源图像(I):我们期望找到与模板图像匹配的图像 2. 模板图像(T):将与模板图像进行比较的补丁图像 1. result = cv.matchTemplate(dog,dog_nose,cv.TM_CCORR_NORMED) void cv::matchTemplate( cv::InputArray image, // 待匹配图像W*H cv::InputArray templ, // 模板图像,和image类型相同, 大小 w*h cv::OutputArray result, // 匹配结果图像, 类型 32F, 大小 (W-w+1)*(H-h+1) int method // 用于比较的方法 ); 其中method有: TM_SQDIFF_NORMED匹配数值越低表示匹配效果越好 TM_CCORR_NORMED,TM_CCOEFF_NORMED匹配数值越大表示匹配效果越好 result参数:(保存各个点匹配结果的参数) 模板匹配函数cvMatchTemplate依次计算模板与待测图片的重叠区域的相似度,并将结果存入映射图像result当中,也就是说result图像中的每一个点的值代表了一次相似度比较结果 模板在待测图像上每次在横向或是纵向上移动一个像素,并作一次比较计算 我们可以通过cv.minMaxLoc函数来确定结果矩阵的最大值和最小值的位置。 2. cv.minMaxLoc(result) 返回result数值中最小值以及最小值所在的位置和最大值以及最大值所在的位置。 3. 当知道哪个点匹配度最高时这个时候我们需要用矩阵把模板给标出来 C++: void rectangle(Mat& img, Point pt1,Point pt2,const Scalar& color, int thickness=1, int lineType=8, int shift=0) 第一个参数:要在哪个图像上画? 第二个参数:矩阵的左上角点坐标 第三个参数:矩阵的右下角点坐标 第四个参数:颜色
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值