称为基于边缘方向梯度的匹配,是一种最常用也是最前沿的模板匹配算法
以物体边缘的梯度相关性作为匹配标准
提取ROI中的边缘特征,结合灰度信息创建模板,并根据模板的大小和清晰度的要求生成多层级的图像金字塔模型
接着在图像金字塔层中自上而下逐层搜索模板图像,直到搜索到最底层或得到确定的匹配结果为止
该方法使用边缘特征定位物体,对于很多干扰因素不敏感,如光照和图像的灰度变化,甚至可以支持局部边缘缺失、杂乱场景、噪声、失焦和轻微形变的模型
更进一步说,它甚至可以支持多个模板同步进行搜索
但是它不适用于旋转和缩放比较大的情况
/*
1.创建形状模型:create_shape_model()
2.寻找形状模型:find_shpae_model()
3.释放形状模型:clear_shape_model()
*/
标准形状:draw_rectangle1/2、draw_circle、draw_ellipse、draw_line
任意形状:draw_region、draw_polygon
生成标准ROI:gen_rectangle1/2、gen_circle、gen_ellipse、gen_region_line
通过XLD创建AOI:gen_region_contour_xld、gen_region_polygon_xld
利用area_center()找到这个ROI区域的中心
通过reduce_domain()从图像中获取这个ROI区域
修正函数:erosion(减小ROI)、dilation(扩大ROI)、shape_trans(形状转换)、boundary(像素级边界)、move_region(移动区域到新位置)
组合:intersection(交集)、difference(差集)、union2(两个区域的并集)
create_shape_model(Template , // 模板图像
NumLevels, // 金字塔层数
AngleStart, // 起始角度
AngleExtent, // 角度范围
AngleStep, // 角度步长
Optimization, // 设置模板优化和模板创建方法
Metric, // 匹配方法设置
Contrast, // 模板中前景与背景的对比度
MinContrast, // 被查找图片的最小对比度
ModelID) // 模板ID
// 可缩放比例
create_scaled_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, ScaleMin, ScaleMax, ScaleStep, Optimization, Metric, Contrast, MinContrast : ModelID)
create_scaled_shape_model (ImageReduced, 5, rad(-45), rad(90), 0, 0.8, 1.0, 0, ['none','no_pregeneration'], 'ignore_global_polarity', 40, 10, ModelID)
通过determine_shape_model_params算子得到金字塔层数,再通过inspect_shape_model算子测试对比度的数值是否合理
创建好模板以后,需要监视模板,用inspect_shape_model算子来完成,用来检测参数的适用性与找到合适的参数
该算子执行后将会把预设参数的金字塔分级图像显示出来,可以根据需要判断参数选取的是否合理
inspect_shape_model(Image : // 输入参数,输入图像
ModelImages, // 输出参数,输出图像基于金字塔的影像
ModelRegions : // 输出参数,输出模型区域
NumLevels, // 输入参数,使用的金字塔层数。默认4,范围1~10
Contrast : ) // 输入参数,设置对比度。默认30,参考10,20,30,40,60,80,100,120,140,160
(1)NumLevels
最开始是第一层,逐层+1
金字塔越小,细节信息越多,定位的更准确,但消耗的时间也更多;金字塔越大,找到匹配使用的时间就越小
另外必须保证最高层的图像具有足够的信息(至少四个点)。如果金字塔过大,模板不容易识别出来,这是需要将find_shape_model函数中MinScore和Greediness参数设置的低一些(注意这里的解决办法!!!)
如果最高层金字塔的消息太少,算法内部会自动减少金字塔层数
如果最底层金字塔的信息太少,函数就会报错
如果设为auto,算法会自动计算金字塔的层数,我们可以通过get_shape_model_params函数查看金字塔的层数
// 根据创建的模型ID来查看形状模型的参数
get_shape_model_params( : : ModelID : NumLevels, AngleStart, AngleExtent, AngleStep, ScaleMin, ScaleMax, ScaleStep, Metric, MinContrast)
// ScaleMin, ScaleMax, ScaleStep是模型的最小比例、最大比例、缩放步长
(2)Contrast
对比度是用来测量目标与背景之间和目标不同部分之间局部的灰度值差异
1个元素时:128,对比度,直接提取边缘
2个元素时:[100, 128],表示使用滞后阈值的算法来进行分割提取边缘
3个元素时:[100, 128, 10],前两个参数同2,最后一个参数表示所提取边缘的最小长度为10
对比度阈值可以使用determine_shape_model_params函数自动确定,也可以在调用create_shape_model之前使用inspect_shape_mode函数检查效果
determine_shape_model_params(Template, // 模板
‘auto’, // 金字塔层数
0, // 起始角度
rad(360), // 角度范围
0.9, // 缩小范围
1.1, // 放大范围
‘auto’, // 减少像素的方法
‘use_polarity’, // 极性
‘auto’, // 对比度
‘auto’, // 最小对比度
'all', // 需要自动确定的参数
ParameterName, // Name of values
ParameterValue) // Values
(3)AngleStart、AngleExtent、AngleStep
AngleStep的选择是基于目标的大小的,如果模板图像太小就不能产生许多不同离散角度的图像,因此对于较小的模板图像AngleStep应该设置的比较大
如果AngleExtent不是AngleStep的整数倍, 将会相应的修改AngleStep
AngleStep
选择标准:模板越大,角度步长越小;模板越小,角度步长越大
速度和内存:步长越小,占用内存越多,定位速度越慢
如果没有特殊要求,可选"auto"让系统做最佳选择,会基于模板的大小自动定义一个合适的角度步长
(4)Optimization
设置模板优化和模板创建方法
一些模板包含了太多像素点,这导致模板过大、增加执行时间、增加内存需求
参数Optimization是用来减少这些点,相同条件下,运行时间依次减少
none,不减少像素
point_reduction_low,大约一半点
point_reduction_medium,大约1/3
point_reduction_high,大约1/4
对于特别大的模板图像,将参数Optimization设置为不同于’none’的其他数值是非常有用的;对于比较小的模型,减少模型点数并不能提高搜索速度
如果模型点数变少了,必须在find_shape_model函数中将参数Greediness设为一个比较小的值, 比如:0.7、0.8
如果Optimization设置为’auto’, create_shape_model自动确定模型的点数
除了减少像素,该参数也可以控制模板的创建方式,来选择内存优先还是速度优先
第二个值可选下面两个
'pregeneration',模板预先创建,牺牲内存来换取查找速度
'no_pregeneration',在查找时才创建必须数据,占用内存少
默认的是系统中的设置
set_system('pregenerate_shape_models','true'/'false')
如果没有设置,默认为
set_system('pregenerate_shape_models','false')
(5)Metric
在图像中匹配模板的条件
use_polarity:图像中的目标和模型具有一样的对比度(前景亮,背景暗,那么仅仅那些比背景亮的目标可以找到)
ignore_global_polarity:在两者对比度完全相反时也能找到目标(如果目标是比背景暗的也能将目标找到)
ignore_local_polarity :即使局部对比度改变也能找到模型(当目标包含一部分中等灰度,并且其中部分比较亮部分比较暗时,这种模式是非常有用的)
由于这种模式下find_shape_model函数的运行时间显著增加,最好的方法是使用create_shape_model创建几个反映目标可能的对比度变化的模型,同时使用find_shape_models去匹配他们
(6)MinContrast
将模板从图像噪声中分离出来,如果灰度值的波动范围是10,则MinContrast = 10
模板图像边缘不一定都是有益的,噪声、纹理会造成有害边缘,有害边缘会导致定位不准或找错、错误的分值、稍微增大查找时间
参数MinContrast是在查找模板的时候,来减少“有害”边缘的
该值可通过estimate_noise函数、inspect_shape_model函数、助手判断得到
(7)注意事项:通过Dxf(格式交换文件)文件创建模板
通过像素轮廓可以直接创建模板
create_scaled_shape_model_xld
create_aniso_shape_model_xld
get_shape_model_contours(ModelContours, // 输出形状模型的轮廓表示
ModelID, // 模型句柄
Level) // 金字塔层数
在图像中找出最佳匹配的模板,返回一个模板实例的长、宽、旋转角度
find_shape_model(Image, // 搜索图像
ModelID, // 模板句柄
AngleStart, // 搜索时的起始角度
AngleExtent, // 搜索时的角度范围,必须与创建模板时的有交集
MinScore, // 最小匹配值,输出的匹配的得分Score大于该值
NumMatches, // 定义要输出的匹配的最大个数
MaxOverlap, // 当找到的目标存在重叠时,且重叠大于该值时选择一个好的输出
SubPixel, // 计算精度的设置,五种模式,多选2,3
NumLevels, // 搜索时金字塔的层数
Greediness, // 贪婪度,搜索启发式,一般都设为0.9,越高速度快,容易出现找不到的情况
Row, Column, Angle, Score) // 输出匹配位置的行和列坐标、角度、得分(模板在搜索图像中可见比例的近似测量,如果模板的一半被遮挡,该值就不能超过0.5)
参数影响到匹配的速度与精度
(1)MinScore
模板匹配时至少有个什么样的质量系数才算是在图像中找到模板
MinScore设置的越大,越相似,搜索的就越快
如果模板在图像中没有被遮挡,MinScore可以设置为0.8这么高甚至0.9
(2)NumMatches
在图像上找到模板的最大的个数
如果匹配时的质量系数大于MinScore的目标个数多于NumMatches,仅仅返回质量系数最好的NumMatches个目标位置。如果找的匹配目标不足NumMatches,那么就只返回找到的这几个
参数MinScore优于NumMatche
(3)Maximum Overlap
参数MaxOverlap是0到1之间的,定义了找到的两个目标区域最多重叠的系数,以便于把他们作为两个不同的目标区域分别返回
如果找到的两个目标区域彼此重叠并且大于MaxOverlap,仅仅返回效果最好的一个
重叠的计算方法是基于找到的目标区域的任意方向的最小外接矩形(看smallest_rectangle2)。如果MaxOverlap=0, 找到的目标区域不能存在重叠,如果MaxOverlap=1,所有找到的目标区域都要返回
(4)SubPixel
确定找到的目标是否使用亚像素精度提取,一般设置为interpolation
精度控制模型
none:不使用亚像素,最大误差为半个像素
interpolation:位置和角度都是亚像素精度的。在这种模式下模型的位置是在质量系数函数中插入的,这种模式几乎不花费计算时间,并且能达到足够高的精度
least_squares、least_squares_high、least_squares_very_high:最小二乘法亚像素精度
不同模式对运行时间的影响:前两者时间相同,最小二乘法时间比较长
该参数可影响以下结果:Position、Angle、Scaling
(5)NumLevels
如果NumLevels=0,使用创建模板时金字塔的层数
NumLevels还可以包含第二个参数,这个参数定义了找到匹配模板的最低金字塔层数
如NumLevels=[4,2]表示匹配在第四层金字塔开始,在第二层金字塔找到匹配(最低的设为1)
可以使用这种方法降低匹配的运行时间,但是这种模式下位置精度是比正常模式下低的,所谓正常模式是在金字塔最底层匹配
因此如果需要较高的精度,应该设置SubPixel至少为’least_squares’。如果金字塔最底层设置的过大,可能不会达到期望的精度,或者找到一个不正确的匹配区域。这是因为在较高层的金字塔上模板是不够具体的,不足以找到可靠的模板最佳匹配。在这种情况下最低金字塔层数应设为最小值
(6)Greediness
该参数是用来做定位加速的,很大程度上影响着搜索速度
若为0,则为启发式搜索;若为1,则为不安全搜索
值越小,速度越慢;值越高,找丢目标的可能越大
建议取值:0.7~0.9
(1)vector_angle_to_rigid()
从一个点和角度计算一个刚体仿射变换
(2)affine_trans_contour_xld()
for i:=0 to |Score|-1 by 1
// 得到对应匹配目标的旋转矩阵
vector_angle_to_rigid (0, 0, 0, Row[i], Column[i], Angle[i], HomMat2DRotate)
// 在旋转矩阵的基础上添加缩放量,生成新的矩阵
hom_mat2d_scale (HomMat2DRotate, Scale[i], Scale[i], Row[i],Column[i], HomMat2DScale)
// 矩阵变换(xld基础上)
affine_trans_contour_xld (ModelContours, ContoursAffineTrans, HomMat2DScale)
// xld转换成region
gen_region_contour_xld (ContoursAffineTrans, Region, 'filled')
// 对区域,生成最小外接矩形
smallest_rectangle1 (Region, Row1, Column1, Row2, Column2)
// 使用绿色矩形框,框选匹配结果
dev_set_color ('green')
disp_rectangle1 (WindowHandle, Row1[0], Column1[0], Row2[0], Column2[0])
// 使用红色勾画匹配结果轮廓
dev_set_color ('red')
dev_display (ContoursAffineTrans)
// 显示各匹配结果提示语
disp_message (WindowHandle, '第'+(i+1)+'个', 'window', Row1[0]-30, (Column1[0]+Column2[0])/2-10, 'green', 'false')
endfor
只要匹配成功,就尽可能的增加参数MinScore的数值
增加Greediness的值直到匹配失败,同时在需要时减小MinScore的值
在创建图像时,增加金字塔层数
限定允许的旋转范围与大小范围,在调用find_shape_model()时调整相应的参数
尽量限定搜索ROI区域的值
(1)网格线
// 关闭程序计数器,变量更新,图像窗口更新
dev_update_off ()
dev_close_window ()
// 读取模版图像
read_image (Image, 'wafer/wafer_mirror_dies_01')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
// 定义输出区域,轮廓的线宽
dev_set_line_width (3)
dev_display (Image)
// 这个过程会在屏幕右下角显示“Click 'Run' to continue”。
disp_continue_message (WindowHandle, 'black', 'true')
stop()
// 创建剪切矩形ROI作为模板图像
gen_rectangle1 (Rectangle, 362, 212, 414, 262)
reduce_domain (Image, Rectangle, ImageReduced)
// 根据金字塔数和对比度获取输入图像的金字塔图像、金字塔区域
inspect_shape_model (ImageReduced, ModelImages, ModelRegions, 4, 30)
// 显示金字塔各层级的图像,以检查层数的合理性
dev_display(ModelRegions)
area_center(ModelRegions, AreaModelRegions, RowModelRegions, ColumnModelRegions)
count_obj(ModelRegions, Number)
// 确定金字塔的层级
for i := 1 to Number by 1
if(AreaModelRegions[i-1]>=10)
NumLevels := i
endif
endfor
// 创建形状模版
create_shape_model (ImageReduced, NumLevels, rad(0), rad(1), 'auto', 'auto', 'use_polarity', 'auto', 'auto', ModelID)
// 获得模型轮廓,中心点在原点位置
get_shape_model_contours (ModelContours, ModelID, 1)
// 开始在搜索图像中搜索模版
for Index := 1 to 4 by 1
read_image (Image, 'wafer/wafer_mirror_dies_' + Index$'02')
// 计算当前过去的时间,单位是秒
count_seconds (S1)
// 使用匹配算子进行形状模板匹配
find_shape_model (Image, ModelID, rad(0), rad(1), 0.5, 0, 0.0, 'least_squares', 2, 0.5, Row, Column, Angle, Score)
// 计算当前过去的时间,单位是秒
count_seconds (S2)
Runtime := (S2 - S1) * 1000
// 生成十字对象
gen_cross_contour_xld (Cross, Row, Column, 6, rad(45))
// 显示匹配结果,将匹配得到的实例以形状轮廓的形式绘制出来
dev_display_shape_matching_results (ModelID, 'lime green', Row, Column, Angle, 1, 1, 0)
// 设置输出对象的颜色
dev_set_color ('orange')
// 显示图像
dev_display (Image)
// 显示十字
dev_display (Cross)
stop ()
endfor
get_system ('border_shape_models', model)
// 匹配结束,释放模板资源
clear_shape_model (ModelID)
边界处理
(2)环保标志
dev_update_off ()
dev_close_window ()
// 定位模板
// 读取图像
read_image (Image, 'E:/Halcon/算法/11模板匹配/基于形状的模板匹配/一个环保标志.png')
// 获取图像的宽高
get_image_size (Image, Width, Height)
// 以合适的尺寸打开图像
dev_open_window_fit_size (0, 0, Width, Height, -1, -1, WindowHandle)
//显示图像、字体、填充方式、颜色、字宽
dev_display (Image)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_color ('red')
dev_set_line_width (3)
// 定义数组
Message := '这个实例演示如何创建一个模板'
Message[1] := '形状匹配模板建立与保存'
Message[2] := '模板匹配的使用'
// 显示数组话语
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
// 继续提示语显示
disp_continue_message (WindowHandle, 'black', 'true')
// 执行断点处
stop()
// 预处理获得优质的模板图像
threshold (Image, Regions, 0, 122)
dev_set_colored(12)
connection (Regions, ConnectedRegions)
fill_up (ConnectedRegions, RegionFillUp)
select_shape (RegionFillUp, SelectedRegions, 'area', 'and', 14845, 57911.9)
dilation_circle (SelectedRegions, RegionDilation, 3.5)
reduce_domain (Image, RegionDilation, ImageReduced)
// 生成模板
determine_shape_model_params(ImageReduced, 'auto', -0.39, 0.79, 0.9, 1.1, 'auto', 'use_polarity', 'auto', 'auto', 'all', ParameterName, ParameterValue)
// 监视模板
inspect_shape_model (ImageReduced, ModelImages, ModelRegions, 5, 40)
// 创建形状模板
// 使用用图像创建带有缩放的匹配模板
create_scaled_shape_model (ImageReduced, 5, rad(-45), rad(90), 0, 0.8, 1.0, 0, ['none','no_pregeneration'], 'ignore_global_polarity', 40, 10, ModelID)
// 保存模板
write_shape_model (ModelID, 'E:/Halcon/算法/11模板匹配/基于形状的模板匹配/shapemodel_huanbao.shm')
// 清除模板
clear_shape_model (ModelID)
// 模板匹配
// 获取检测目标图像
read_image (Image1, 'E:/Halcon/算法/11模板匹配/基于形状的模板匹配/三个环保标志.png')
// 提示语定义与显示
Message := '形状匹配步骤开始'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
// 读取形状模板
read_shape_model ('E:/Halcon/算法/11模板匹配/基于形状的模板匹配/shapemodel_huanbao.shm', ModelID1)
// 模板匹配,后面的几个参数是匹配图像的位置状态等参数
find_scaled_shape_model (Image1, ModelID1, rad(-45), rad(90), 0.8, 1.0, 0.5, 0, 0.5, 'least_squares', 5, 0.8, Row, Column, Angle, Scale, Score)
// 返回一个轮廓模型的轮廓表示
get_shape_model_contours (ModelContours, ModelID1, 1)
dev_display (Image1)
// 循环
for i:=0 to |Score|-1 by 1
// 得到对应匹配目标的旋转矩阵
vector_angle_to_rigid (0, 0, 0, Row[i], Column[i], Angle[i], HomMat2DRotate)
// 在旋转矩阵的基础上添加缩放量,生成新的矩阵
hom_mat2d_scale (HomMat2DRotate, Scale[i], Scale[i], Row[i],Column[i], HomMat2DScale)
// 矩阵变换(xld基础上)
affine_trans_contour_xld (ModelContours, ContoursAffineTrans, HomMat2DScale)
// xld转换成region
gen_region_contour_xld (ContoursAffineTrans, Region, 'filled')
// 对区域,生成最小外接矩形
smallest_rectangle1 (Region, Row1, Column1, Row2, Column2)
// 使用绿色矩形框,框选匹配结果
dev_set_color ('green')
disp_rectangle1 (WindowHandle, Row1[0], Column1[0], Row2[0], Column2[0])
// 使用红色勾画匹配结果轮廓
dev_set_color ('red')
dev_display (ContoursAffineTrans)
// 显示各匹配结果提示语
disp_message (WindowHandle, '第'+(i+1)+'个', 'window', Row1[0]-30, (Column1[0]+Column2[0])/2-10, 'green', 'false')
endfor
// 提示语定义与显示
Message := '形状匹配结果如下:'
disp_message (WindowHandle, Message, 'window', 12, 12, 'green', 'false')
// 将窗口内容写入图像对象
dump_window_image (Image2, WindowHandle)
write_image (Image2, 'png', 0, 'E:/Halcon/算法/11模板匹配/基于形状的模板匹配/环保标志结果.bmp.png')
(3)晨光
dev_update_off()
dev_close_window()
// 读取图像
read_image(Image, 'E:/Halcon/算法/11模板匹配/基于形状的模板匹配/晨光模板图像.jpg')
get_image_size(Image, Width, Height)
rgb1_to_gray(Image, GrayImage)
dev_open_window_fit_image(GrayImage, 0, 0, -1, -1, WindowHandle)
dev_display(GrayImage)
// 预处理
binary_threshold(GrayImage, Region, 'max_separability', 'dark', UsedThreshold)
connection(Region, ConnectedRegions)
fill_up(ConnectedRegions, RegionFillUp)
select_shape(RegionFillUp, SelectedRegions, 'area', 'and', 22500, 23000)
dilation_circle(SelectedRegions, RegionDilation, 3.5)
reduce_domain(GrayImage, RegionDilation, ImageReduced)
// 获取金字塔层数,图像监视
determine_shape_model_params(ImageReduced, 'auto', -0.39, 0.79, 0.9, 1.1, 'auto', 'use_polarity', 'auto', 'auto', 'all', ParameterName, ParameterValue)
inspect_shape_model(ImageReduced, ModelImages, ModelRegions, 5, 20)
dev_set_draw ('margin')
dev_set_line_width(3)
// 创建模板
create_shape_model(ImageReduced, 'auto', rad(0), rad(1), 'auto', 'auto', 'use_polarity', 20, 3, ModelID)
write_shape_model(ModelID, 'E:/Halcon/算法/11模板匹配/基于形状的模板匹配/shapemodel_chenguang.shm')
clear_shape_model(ModelID)
// 在目标图像中寻找模板图像
read_image(ImageTest, 'E:/Halcon/算法/11模板匹配/基于形状的模板匹配/晨光测试图像.jpg')
message:= '查找模板'
disp_message(WindowHandle, message, 'window', 16, 16, 'black', 'true')
read_shape_model('E:/Halcon/算法/11模板匹配/基于形状的模板匹配/shapemodel_chenguang.shm',ModelID1)
find_shape_model(ImageTest, ModelID1, rad(0), rad(1), 0.5, 0, 0, 'least_squares', 5, 0.8, Row, Column, Angle, Score)
get_shape_model_contours(ModelContours, ModelID1, 1)
dev_display(ImageTest)
// 显示匹配结果,将匹配得到的实例以形状轮廓的形式绘制出来
dev_display_shape_matching_results(ModelID1, 'red', Row, Column, Angle, 1, 1, 0)
// 匹配结束,释放模板资源
clear_shape_model (ModelID1)