halcon 形状匹配

1、例子

  • 指定模板图像区域(也可以用draw_rectangle1画一个矩形)
Row1 := 188
Column1 := 182
Row2 := 298
Column2 := 412
gen_rectangle1 (ROI, Row1, Column1, Row2, Column2)
reduce_domain (ModelImage, ROI, ImageROI)
  •   创建模板

如果创建模板的时候不但含有方向,还含有角度的话:create_scaled_shape_model 或者 create_aniso_shape_model

*找到适合模型创建的参数(主要的参数就是金字塔层数,和最小的对比度),返回一个在与金字塔对应的模板点集
inspect_shape_model (ImageROI, ShapeModelImages, ShapeModelRegions, 8, 30)
*模板旋转的角度范围,以及每次旋转角度的步长,使用最优的参数可以有效减少模板点数。对于大型模板非常有效,也可已设置相应的角度旋转范围。返回一个modelID
create_shape_model (ImageROI, NumLevels, 0, rad(360), 'auto', 'none', \
'use_polarity', 30, 10, ModelID)
  • 寻找到匹配的图像
for i := 1 to 20 by 1
    grab_image (SearchImage, FGHandle)
    find_shape_model (SearchImage, ModelID, 0, rad(360), 0.7, 1, 0.5, \
    'least_squares', 0, 0.7, RowCheck, ColumnCheck, \
    AngleCheck, Score)
endfor

AngleStart, AngleExtent和NumLevels已经在创建模板的时候确定了。MinScore制定了必须被发现的匹配莫斑点个数,0.5意味着模板一半被找到了,

 

2、创建合适的模板

2.1、最小的包含感兴趣区域

首先是找到ROI区域

reduce_domain (ModelImage, ROI, ImageROI)
create_shape_model (ImageROI, 0, 0, rad(360), 0, 'none', 'use_polarity', 30, \
10, ModelID)

2.1.1 怎样创建一个区域

  • gen_rectangle2
  • gen_ellipse
  • gen_region_polygon_filled需要坐标等输入参数
    draw_rectangle1 (WindowHandle, ROIRow1, ROIColumn1, ROIRow2, ROIColumn2)
    gen_rectangle1 (ROI, ROIRow1, ROIColumn1, ROIRow2, ROIColumn2)

     

2.1.2 怎样合并和掩藏一个区域

union2和difference

draw_rectangle1 (WindowHandle, ROI1Row1, ROI1Column1, ROI1Row2, ROI1Column2)
gen_rectangle1 (ROI1, ROI1Row1, ROI1Column1, ROI1Row2, ROI1Column2)
draw_rectangle1 (WindowHandle, ROI2Row1, ROI2Column1, ROI2Row2, ROI2Column2)
gen_rectangle1 (ROI2, ROI2Row1, ROI2Column1, ROI2Row2, ROI2Column2)
union2 (ROI1, ROI2, ROI)
draw_circle (WindowHandle, ROI1Row, ROI1Column, ROI1Radius)
gen_circle (ROI1, ROI1Row, ROI1Column, ROI1Radius)
gen_circle (ROI2, ROI1Row, ROI1Column, ROI1Radius-8)
difference (ROI1, ROI2, ROI)

为了避免在金字塔中消失,因此ROI区域最小尺寸应该为2^{NumLevels-1}

2.1.3 使用图像处理技术创建和修改区域

实例1:使用blob分析创建ROI

a、提取亮度区域

*阈值分割
threshold (ModelImage, BrightRegions, 200, 255)
*区域拆分
connection (BrightRegions, ConnectedRegions)
*区域填充
fill_up (ConnectedRegions, FilledRegions)

b、选中区域

select_shape (FilledRegions, Card, 'area', 'and', 1800, 1900)

可以使用Visualization->Region Features选择合适的特征筛选方式

c、使用ROI区域

reduce_domain (ModelImage, Card, ImageCard)

只检测选择区域内的图像,减少不必要的干扰,简化操作流程

d、提取logo

threshold (ImageCard, DarkRegions, 0, 230)
connection (DarkRegions, ConnectedRegions)
select_shape (ConnectedRegions, Characters, 'area', 'and', 150, 450)
union1 (Characters, CharacterRegion)

与之前的定位区域提取是一样的,检测区域提取的后面使用union1来将检测区域合并到一起

e、使用形morphology态学方法,扩大检测区域

dilation_circle (CharacterRegion, ROI, 1.5)
reduce_domain (ModelImage, ROI, ImageROI)
create_shape_model (ImageROI, 3, 0, rad(360), 'auto', 'none', \
'use_polarity', 30, 10, ModelID)

最后创建形状模板shape model

示例2、 inspect_shape_model结果的进一步处理

创建一个第一的交互式模板区域,处理这个区域获取ROI

a、选择箭头

gen_rectangle1 (ROI, 361, 131, 406, 171)

人为的创建了ROI

b、创建第一模板区域

reduce_domain (ModelImage, ROI, ImageROI)
*金字塔层数,对比度
inspect_shape_model (ImageROI, ShapeModelImage, ShapeModelRegion, 1, 30)

通过改变不同的对比度获取较为完整的检测区域。

c、处理模板区域

*填充箭头内部
fill_up (ShapeModelRegion, FilledModelRegion)
*去掉小的区域
opening_circle (FilledModelRegion, ROI, 3.5)

d、创建最终的模板

reduce_domain (ModelImage, ROI, ImageROI)
create_shape_model (ImageROI, 3, 0, rad(360), 'auto', 'none', \
'use_polarity', 30, 15, ModelID)

创建出了形状模板。

2.1.4、RIO如何去做搜索

ROI的中心点会作为参考点,来评估位置、旋转、尺度。创建完模型之后可以使用get_shape_model_origin获取相关参数,使用set_shape_model设置相关形变参数。

2.2 模板信息存储在哪里

对比度超过设置的阈值的点轮廓被提取,,对比度的话可以包括一个阈值的范围hysteresis threshold,然后最小化轮廓尺寸。

2.2.1 模板部分的像素在哪里

对比度contrast(与邻居点灰度值的差异)大于阈值的就会在create_shape_model中创建为模板,为了获取合适的模板,应该将对比度设置为近似于关注对象的显著像素。模板不应该包含clutter(这些不属于对象的像素)。

在某些情况下对比度contrast也许在一个对比度阈值的情况下不太适用,比如将clutter踢出来,但是也将对象区域也剔除了一部分,为了解决这个问题,contrast提供了两个附加的方法:hysteresis thresholding 和以及选中轮廓点的尺寸。也就是追加一组参数来替代单一的参数。

Hysteresis thresholding(可以参考hysteresis_threshold)使用两个阈值,阈值下限和阈值上限。也就是如果对比度高于最高阈值的直接选中,如果小于最高阈值,但是大于最低阈值的,只要是邻近点有高于最大阈值的也选中。该方法允许对比度随像素变化而变化。

inspect_shape_model (ImageROI, ModelImages, ModelRegions, 1, [26,52])

其次是理由最小尺寸(像素个数),最小尺寸约束在三元组里面,如果不想用Hysteresis thresholding可以直接将最大最小的对比度contrast设置成一样

inspect_shape_model (ImageROI, ModelImages, ModelRegions, 1, [26,26,12])

determine_shape_model_params可以'auto'自动的寻找合适的对比度等参数。

2.2.2 怎样使用降采样来加速搜索。

为了加速搜索,一个被称之为图像金字塔被创建image pyramid,包括模板图像和寻找图像,图像金字塔包含原尺寸图像和一系列的降采样图像(尺寸长宽都缩小一半),尺寸最小的图像在金字塔的最高层,搜寻图像首先在最小的图像开始,该搜索的结果会影响下一步需要搜索的金字塔图像,依次用于下一层金字塔直到最底层。使用迭代的方法,该方法快速有效。

NumLevels表面金字塔层数,建议最高层的金字塔至少有10-15个像素,并且目标对象的形状依旧保存,然后可以使用inspect_shape_model进行检测,

***HDevelop program examples\solution_guide\shape_matching\first_example_shape_matching.dev
inspect_shape_model(ImageROI, ShapeModelImages, ShapeModelRegoins, 8, 30)
are_center( ShapeMdelRegions, AreaModelRegions, RowModelRegions, ColumnModelRegions)
count_obj(ShapeModelRegions, HeightPyramid)
for i := 1 to HeightPyramid by 1
    if(AreaModelRegions[i-1] >= 15)
        NumLevels := 1
    endif
endfor
create_shape_model( ImageROI, NumLevels, 0, rad(360), 'auto', 'none', 'use_polarity', 30, 10, ModelID);

通过计算regions的最小尺寸不少于15从而确定金字塔的层数。

如果要自动的选择合适的金字塔层数,使用get_shape_model_params来'auto' NumLevels。

inspect_shape_model通过图像元组的形式返回图像金字塔,单张金字塔图像的获取可通过select_obj获取,对象的索引下标从1开始,控制参数的下标是从0开始。

可以通过最优化Optimization的方式减少模板点数,这样可以有效的提速,特别是在较大的模板匹配算法中,推荐使用'auto'让halcon自动的选择合适的参数。所有满足对比度contrast的点都会显示出来,没办法判断他是不是匹配模板的一部分。

通过设置其他参数可以设定模板是否允许旋转或者放缩,一般情况模板不是事先生成的,'pregeneration'作为Optimization的第二个值,通过set_system设置给参数。如果要使用多线程,那么将其设置成预生成pregeneration是十分合适的。如果需要大量的旋转或者尺度变换,对内存的需求也要增大,耗时也将增大。

2.2.3 允许方向范围

如果在搜索图像中对象旋转是任意的,可以同过AngleExtent设置允许的范围,起始角度为AngleStart,单位是rad幅度。该旋转角度是针对模板图像而言的的,例如起始角度AngleStart是0,那么模板的角度和搜索图像中对象对应的角度一致。如果允许旋转的角度是+/-5°,那么开始角度应该是-rad(5),角度范围AngleExtent是rad(10)。

建议减少角度旋转范围,以提升检测速度,如果是预先定义的模板,那么能存的损耗也是增大的。在find_shape_model中会对其做进一步限制,如果是希望为不同的任务重用模板,那么就应该创建一个大范围的模板,然后在一个小范围里面搜索模板。

如果检测对象几乎是对称的,那么就应该限制角度范围,否则模板会在不同的角度上找到多个最匹配的模板,十字形状或者正方形形状必须将角度范围限定在90°,对于长方形,应该限制在180°,圆的话应该是0°。

在匹配处理期间AngleStep可以设置成'auto',让halcon自动的选择最优的步长尺度,\o _{opt}来获得最可能的最小旋转范围。如果物体中心移动了至少2个像素,那个该旋转角度就能够被识别。因此相关的角度计算为:

d^{2}=l^{2}+l^{2}-2 \cdot l \cdot cos\phi \Rightarrow \phi_{opt}=arccos(1-\frac{d^{2}}{2 \cdot l^{2} } ) = arccos(1-\frac{2}{l^{2}})

l是中心点与检测对象边界最大的距离,并且d=2个像素,对一些模板而言,角度步长尺寸的评估还是太大了,所以他会自动的除以2

自动的决定角度步长\o _{opt}是否合适,因此推荐用'auto',可以通过get_shape_model_params来查询具体的参数,通过选择最高的值,可以提高检测速度,代价就是降低了方向的精确度。对于太高的值,匹配可能失败啊。

AngleStep不应该离最优值太远,(\frac{1}{3} \phi _{opt}\leqslant \phi \leqslant 3 \phi_{opt}),应当注意,即便是引入很小的角度步长,也不会明显的改变角度的精确度。

2.2.4 允许的尺度范围

与方向范围类似,我们也可以设置尺度范围,通过两种方式改变尺度:

  • 在横向和纵向按照相同的比例放缩(各向同性isotropic放缩)
  • 在横向和纵向按照不同的比例放缩(各向异性anisotropic放缩)

对于各向同性isotropic放缩,我们在create_scaled_shape_model简单的设置ScaleMin,ScaleMax和ScaleStep就可以了,对于各向异性anisotropic放缩,可以使用create_aniso_shape_model代替,相同的会引入6个参数。

相同的,也是需要约束放缩范围以加快搜索速度,假定使用预设模型,大的尺度范围也会需要大量的内存。同样的也可以在find_scaled_shape_model或者find_aniso_shape_model中约束。

如果在大尺度范围内搜素对象,应该创建基于大尺度的模板,因为halcon不能猜测模板点,特别是当预计算的模型实例比原图更大的时候,换句话说NumLevels应该选则高层金字塔层足以包含最小尺度的足够多的模板点。

如果我们选择'auto'用于参数ScaleStep或者要求各向异性尺度,halcon自动选择合适的放缩尺寸步长,来获得高精确足够辨别图像的最小尺度,相同的每个角度步长,如果冥想的例原点(物体中心)比较远就可以清晰的辨别,至少是2个像素,\Delta s_{opt}:

\Delta s=\frac{d}{l}\Rightarrow\Delta s_{opt}=\frac{2}{l}

l是中心点与检测对象边界最大的距离,并且d=2个像素.对一些模板而言,角度步长尺寸的评估还是太大了,所以他会自动的除以2

自动的决定放缩步长是否合适,因此推荐用'auto',可以通过get_shape_model_params来查询具体的参数,通过选择最高的值,可以提高检测速度,代价就是降低了尺度评估的精确度。对于太高的值,匹配可能失败啊。

ScaleStep不应该离最优值太远,(\frac{1}{3} \Delta s _{opt}\leqslant \Delta s \leqslant 3 \Delta s_{opt}),应当注意,即便是引入很小的尺度步长,也不会明显的改变尺度的精确度。

2.2.5 哪些像素与模板相比较

为了提高效率,模板包含了许多影响搜索速度的信息,参数MinContrast可以指定搜索图像必须大于某个最小的对比度,才可以与模板进行比较。该参数主要是避免在匹配过程中的噪声(灰度范围的波动),可以通过HDevelop dialog ->Visualization->Pixel Info设置最小的对比度范围应当比噪声大,也可以用'auto'来自动的设定MinContrast

参数Metric可以指定极性polarity,例如对比度的比较方向,如果是'use_polarity'那么极性比较就存在,也就是匹配对象的对比度方向应该用与模板的对比度方向一致,例如模板对象是在暗背景中的亮对象,那么在检测图中的对象也应当是在暗背景下的亮对象。

如果极性设置为'ignore_global_polarity'忽略全局极性,那么即便是待检测物体与模板极性相反,也会被检测。也就是在亮背景下的暗对象也能够被检测,反之亦然。该方法较为灵活,损失的匹配时间也是很低。

如果选择的是'ignore_local_polarity',可以更好的在彩色图像上匹配(多通道图像),例如examples\hdevelop\Applications\FA\matching_multi_channel_yogurt.dev

在set_shape_model_metric里面你可以决定模板边缘的极性,在训练图像中,自动的设置匹配度量为'use_polarity'或者'ignore_global_polarity'。例子在examples\hdevelop\Matching\Shape-Based\
create_shape_model_xld.dev.

2.3合成图像模型

模板对象是很难创建,实例

examples\
solution_guide\shape_matching\synthetic_circle.dev;

a、创建XLD轮廓

RadiusCircle := 43
SizeSynthImage := 2*RadiusCircle + 10
gen_ellipse_contour_xld (Circle, SizeSynthImage / 2, SizeSynthImage / 2, 0, RadiusCircle, RadiusCircle, 0, 6.28318, 'positive', 1.5)

gen_ellipse_contour_xld生成圆形区域,可以设定合适的检测半径,合成图像应当大于区域,因为区域附近的像素会用来创建图像金字塔。

b、创建图像并且插入XLD轮廓

gen_image_const (EmptyImage, 'byte', SizeSynthImage, SizeSynthImage)
paint_xld (Circle, EmptyImage, SyntheticModelImage, 128)

使用gen_image_const来创建一副空的图像,XLD轮廓使用paint_xld绘制在里面

c、创建一个模板

create_scaled_shape_model (SyntheticModelImage, 'auto', 0, 0, 0.01, 0.8,1.2, 'auto', 'none', 'use_polarity', 30, 10, ModelID)

使用合成的图像来创建一个形状模板。

2.4、从XLD轮廓中创建模板,或者DXF文件

XLD轮廓可以直接作为模板使用,create_shape_model, create_scaled_shape_model,
or create_aniso_shape_model 被 create_shape_model_xld, create_scaled_shape_model_xld,或者 create_aniso_shape_model_xld操作替代。

另外你也可以创建DXF文件,首先从DXF文件中提取XLD轮廓read_contour_xld_dxf,可以按照例子examples\hdevelop\
Applications\FA\pm_multiple_dxf_models.dev来使用,也可以直接使用XLD轮廓。

3、优化搜索处理

find_shape_model, find_scaled_shape_model,
find_aniso_shape_model, find_shape_models, find_scaled_shape_models, or
find_aniso_shape_models

3.1 限制搜索空间

3.1.1 寻找感兴趣区域

find_shape_model来找到ROI区域

a、创建ROI

Row1 := 141
Column1 := 159
Row2 := 360
Column2 := 477
gen_rectangle1 (SearchROI, Row1, Column1, Row2, Column2)

b、约束感兴趣区域
 

for i := 1 to 20 by 1
    grab_image (SearchImage, FGHandle)
    reduce_domain (SearchImage, SearchROI, SearchImageROI)
    find_shape_model (SearchImageROI, ModelID, 0, rad(360), 0.7, 1, 0.5,'interpolation', 0, 0.7, RowCheck, ColumnCheck, AngleCheck, Score)
endfor

3.1.2、 约束方向和尺度范围

create_shape_model, create_scaled_shape_model,or create_aniso_shape_model创建模板,类似的find_shape_model,
find_scaled_shape_model, or find_aniso_shape_model去寻找模板,可以使用s AngleStart, AngleExtent, ScaleMin, and ScaleMax去进一步限定范围,有时候即便是稍微超出约束范围也是可以找到的。

3.1.3、 可见性

模板对象必须可见,MinScores表示有多少个模板点被匹配,

  • 如果检测对象被边界遮挡了,导致无法检测,可以通过设置set_system(’border_shape_models’,’true’).来改善,实例examples\hdevelop\Applications\FA\matching_image_border.dev,该方法情况下,搜索时间会增加。
  • 创建模板的时候,轮廓对比度低于参数最小对比度MinContrast。
  • 改变全局或者局部对比度的极性。
  • 如果物体发生性变,包括相机角度的变换,部分轮廓可见,但是出现错误位置,因此不再适合模型,如果增加的容忍模式被激活,可能会发现变形或散焦的对象。因此最低的金字塔登记必须在NumLevels的负极性,,返回仍然提供匹配的最低金字塔级别的匹配。
  • 如果由于角度步长过大,也可能导致得分较低。尺度步长也是一样的
  • 另外一个原因是金字塔的使用,当候选模型与模型进行匹配时,指定在每一层的最小得分必须被达到。然而不同层的得分也许是多变的,仅仅在对底层的得分返回在参数Score中,这样反而导致MinScore必须比Score低,
  • MinScore得分最高的,最快找到。

3.1.4 彻底匹配和快速匹配

参数Greediness会影响到算法的thoroughness和Speed,如果选择的值是0,且对象是存在的,那么他就会被发现,这样的情况导致即便不是模板对象也会被检测出来,影响检测速度。

“贪婪”搜索算法背后的主要思想是,当一个候选对象与模型的比较似乎不太可能达到最低分数时,它就会中断。换句话说,我们的目标不是把时间浪费在无望的候选人身上,然而,这种贪婪可能带来不受欢迎的后果在某些情况下,一个完全可见的物体是找不到的,因为这个比较一开始就走错了方向,因此被归类为没有希望的候选者,然后就中断了。

你可以调整搜索的贪婪程度Greediness。通过选择0(无中断:彻底但缓慢)和1(最早中断:快速但不安全)之间的值,判断比较何时中断。注意,参数贪婪Greediness和MinScore相互作用,即为了使用更贪婪的搜索,您可能必须指定一个更低的最小得分MinScore。通常情况下,你可以以很高的贪婪和足够低的最低分数达到更高的速度。

3.2 设置形状参数

大多数参数都是在形状模型的创建过程中设置的,set_shape_model_param.里面也可以设置两个参数,一个是min_contrast一个是timeout,min_contrast可以被改变,特别是针对一些搜索图像对比度很低的情况,“timeout”只能用set_shape_model_param来设置,但不能在模型创建期间设置。可以指定查找候选对象最大的时间期限,你可以创建中断,例子为examples\hdevelop\
Matching\Shape-based\extended_contrast.dev。

3.3 寻找对象的多个实例

NumMatches设置检测对象个数,find_shape_model (or find_scaled_shape_model or find_aniso_shape_model)返回一堆匹配后的参数结果Row, Column, Angle, Scale,Score,如果设置为0,所有的匹配对象都会被返回。搜索多个对象要比搜索一个对象慢一些。

MaxOverlap指定匹配对象可能重叠的程度,

3.4 同时搜索多个模板

如果在一幅图里面寻找多个匹配模板,需要多次调用find_shape_model (or find_scaled_shape_model or find_aniso_shape_model)。如果使用find_shape_models, find_scaled_shape_models,or find_aniso_shape_models会更快一些,大体上相似,但是略有差异。

  • ModelIDs模板IDs的元组来替代单一图像,作为寻找多个实例,这些匹配结果参数ROW等返回一个元组值。
  • 输出参数Model会展示所有能被发现的实例,参数没有返回model IDs本身,而是反回了ModelIDs元组索引
  • 查询结果是在单幅图像当中,也可以通过传递一个图像元组来限制搜索区域。
  • 可以为每一个模板指定一个元素AngleStart,也可以为每个模板指定不同的元素,存储在元组中。
  • 可以寻找多个模板的多个实例,指定NumMatches个数,0代表所有实例,例如[3,0]返回第一个模型的三个最匹配的实例和第二个模型所有实例.
  • 相似的,指定单一值用于MaxOverlap,将检查该实例是否有其他独立的实例所覆盖,通过指定值的元组,每个实例只针对相同类型的所有其他实例进行检查。

示例:examples\solution_guide\shape_matching\multiple_models.dev使用find_scaled_shape_models来同时寻找多个模型。

a、第一步创建多个模板

create_scaled_shape_model (ImageROIRing, 'auto', -rad(22.5), rad(45), 'auto', 0.8, 1.2, 'auto', 'none', 'use_polarity', 60, 10, ModelIDRing)
create_scaled_shape_model (ImageROINut, 'auto', -rad(30), rad(60), 'auto',0.6, 1.4, 'auto', 'none', 'use_polarity', 60, 10, ModelIDNut)
ModelIDs := [ModelIDRing, ModelIDNut]

b、指定单个搜索的ROI

gen_rectangle1 (SearchROIRing, 110, 10, 130, Width - 10)
gen_rectangle1 (SearchROINut, 315, 10, 335, Width - 10)
concat_obj (SearchROIRing, SearchROINut, SearchROIs)
add_channels (SearchROIs, SearchImage, SearchImageReduced)

因为实例没有重叠,因此可以单独的对每一个模板进行搜索,搜索的ROI有一定的移动范围,因此狭长的水平ROIs能够被使用。

concat_obj可以将两个region组成一个数组。

add_channels是将region数组追加搜索图像中,操作的结果是含有多张图的图像数组,都用同样的图像矩阵,第一个图像用于约束第一个ROI,第二个ROI用于约束第二个图像的ROI。

c、找到两个模板的所有实例。

find_scaled_shape_models (SearchImageReduced, ModelIDs, [-rad(22.5),-rad(30)], [rad(45), rad(60)], [0.8, 0.6], [1.2, 1.4], 0.7, 0, 0, least_squares', 0, 0.8, RowCheck, ColumnCheck, AngleCheck, ScaleCheck, Score, ModelIndex)

find_scaled_shape_models用于创建图像数组,因为两个模板允许用在不同的旋转和尺度范围。

3.5 更精确

匹配的时候会有一些旋转,位移,尺度方面的变换,每一个模型的匹配得分都会被计算,如果设置SubPixel设置为none,那个结果参数Row、Colum,Angle和Scale包含最佳匹配的多个值。在该情况下,位置的精确度是1个像素,而方向和尺度的精度为AngleStep和ScaleStep的精度,如果中心点和边界的距离为100个像素,那么方向的精度一般是\approx \frac{1}{10}°

因为插值是比较快的操作,因此SubPixel应当设置为'interpolation'。

当选中的值是'least_squares'、'least_squares_hight'或者'least_squares_very_high'最想二乘法就会用于现有的差值运算,计算精度较高,但是时间复杂度会增加。

使用set_shape_model_origin回到值位置精确度不会那么的准。参考原点不变只是移动参考点的方向,位置错误将会与多个因素相关,例如参考点的偏移和发现对象的方向,误差随着参考点与原点的距离线性增加。

非精确的评估尺度也是在参考位置引入的误差,也是修改点和原位置的线性距离增加而增加。

为了保证在参考点移动时的最大精度,应该使用最小二乘调整来确定位置。注意,修改参考点不会影响估计的方向和刻度的准确性。

3.6、寻找最有的匹配速度

如果内存足够的话,就事先生成多尺度多方向的模板。也就是一组代表性测试映像,例如他的位置、方向、遮挡、光照等。

3.6.1、 step 1:确保所有对象都被找到。

找到所有对象实例,如果默认值检测不到,则使用以下步骤进行排除:

a、 对象是否在边界处被裁减

set_system(’border_shape_models’,’true’)

b、搜索算法是否过于贪婪。

Greediness设置为0用于寻找。

c、对象是否被部分遮挡。

减少参数MinScore

d、在最高层的金字塔上面是否匹配失败。

如果在最高的金字塔上没有达到最小的分,就应该交替的将find_shape_model中的NumLevels和MinScore减小。

e、对象的对比度很低吗

改变creat_shape_model的参数MinContrast

f、对比度的极性是全局的还是局部的

设定的参数Metric合适的值创建模型,如果只是少部分的对象受到影响,应当修改MinScore

g、两个检测对象重叠了么

增加MaxOverlap

h、在同一个对象中发现多个匹配

如果对象是堆成的,那么就可以约束旋转范围,或者减少MaxOverlap。

3.6.2、 stpe2:调整与速度有关的参数。

  • MinScore尽可能的增加,只需要匹配成功就可以
  • 增加Greediness知道匹配失败,然后试着减小MinScore,如果失败的话恢复之前的值。
  • 尽可能的限制旋转和尺度变换,find_shape_model, find_scaled_shape_model, or find_aniso_shape_model
  • 约束感兴趣区域
  • 增加MinContrast,可能匹配失败
  • 如果搜索一个大的对象选择一个更高一点的点,减少Optimization参数
  • 增加angleStep尽可能的匹配成功

4、 使用匹配结果

find_shape_model,find_scaled_shape_model返回的结果

  • 通过Row和Column返回位置信息
  • 通过Angle返回方向信息
  • 通过Scale返回尺度信息
  • 通过Score返回匹配得分

匹配得分反映的是模板和匹配对象之间的相似度,可以通过仿射变换affine transformations来进行矫正或者ROIs的对齐。

4.1、 仿射变换

‘Affine transformation’:是数学中描述变换的术语。包含了translated(moved)、rotated和scaled。旋转和放缩需要一个特殊的点,fixed point或者point of reference。这些变换都是围绕这个点操作的,因为在旋转和尺度放缩的时候这个点基本上是不变的。

4.3、 创建和使用仿射变换

halcon中可以进行仿射变换的有regions、images和XLD轮廓,对应affine_trans_region, affine_trans_image,和affine_trans_contour_xld。

affine_trans_region (IC, TransformedIC, ScalingRotationTranslation, 'false')

ScalingRotationTranslation称之为齐次变换矩阵homogeneous transformation matrix,用于描述相应的变换。该矩阵的创建可以通过很少的步骤进行,

a、创建单位矩阵identity matrix

hom_mat2d_identity(EmptyTransformation)

b、围绕着中心点的放缩

hom_mat2d_scale(EmptyTransformation, 0.5, 0.5, RowCenterIC, ColumnCenterIC, Scaling)

c、同样的可以增加旋转和平移

hom_mat2d_rotate(Scaling, rad(90), RowCenterIC, ColumnCenterIC, ScalingRotation)
hom_mat2d_rotate(ScalingRotation, 100, 200, ScalingRotationTranslation)

要注意的是在这些操作中使用的是x,y而不是行列坐标。

Transformation matrices有时候可以通过逆向工程reverse engineering实现。也就是说,如果我们知道某些点的变换关系,我们就可已确定transformation matrix。例如中心点的位置和变换后的防线一直,我们就可以获得对应的矩阵通过vector_angle_to_rigid

vector_angle_to_rigid(RowCenterIC, ColumnCenterIC, 0, TransformedRowCenterIC, TransformedColumnCenterIC, rad(90), RotationTranslation)

相应的计算放射区域的方法

affine_trans_region(IC, TransformedIC, RotationTranslation, 'false')

4.3、使用估计的位置和方向

  • 在单个匹配中显示发现的实例
  • ROIs对齐用于其他检测任务
  • 将检测对象进行仿射变换,使其能与模板对齐
  • 机械手的引导

需要注意的是位置和方向包含在参数Row、Column和Angle,该点的估计位置并不是精确的参考点位置,因为不能直接使用,因此要对转换矩阵做优化以实现上述目的。

模板对象的旋转角度是0,即便是看起来是斜的。

4.3.1、显示匹配对象

在某些应用上模板会直接覆盖在匹配对象上面,可以简单的实现。

the HDevelop program examples\solution_guide\shape_matching\first_example_shape_matching.dev

a、接受包含XLD轮廓的模板

creat_shape_model(ImageROI, NumLevels, 0, rad(360), 'auto', 'none', 'use_polarity', 30, 10, ModelID)
get_shape_model_contours(ShapeModel, ModelID, 1)

接下来我们希望在提取的位置和方向上显示模板,相关的可以通过inspect_shape_model_contours,这是讲模板显示在模板图像上最有效的方法,更推荐使用XLD版本的模板,因为XLD轮廓可以被转换的更精确且快速。可以使用get_shape_model_contours在创建完模板之后,要注意的是XLD位于图像的原点(左上角),而不是模板图的模板位置。

b、确定仿射变换affine transformation

find_shape_model(SearchImage, ModelID, 0, rad(360), 0.7, 1, 0.5, 'least_squares', 0, 0.7, RowCheck, ColumnCheck, AngleCheck, Score)
if(|Score|=1)
    vector_angle_to_rigid(0, 0, 0, RowCheck, AngleCheck, MovementOfObject)

使用find_shape_model之后,返回的结果被检查一遍,如果匹配失败,Score里面就是空的。如果匹配成功的话,放射矩阵就可已通过position和orientation来创建vector_angle_to_rigid,前两个参数是参考点的相对位置,也就是到默认参考点的距离,默认的参考点是ROI的重心。默认的参考点位置是(0,0),

c、将XLD进行变换

affine_trans_contour_xld(ShapeModel, ModelAtNewPosition, MovementOfObject)

dev_display(ModelAtNewPosition)

使用affine_trans_contour_xld进行XLD的仿射变换,并且使用dev_dispaly显示出来。

4.3.2 处理多个匹配

如果对象的多个实例被检测出来,那么相关的参数Row,Column,Angle,和Score就是元组的形式。实例:The HDevelop program examples\solution_guide\shape_matching\multiple_objects.dev

a、确定反射变换矩阵affine transformation

find_shape_model(SearchImage, ModelID, 0, rad(360), 0.6, 0, 0.55, 'least_squares', 0, 0.8, RowCheck, ColumnCheck, AngleCheck, Score)
for j:= 0 to |Score| - 1 by 1
    vector_angle_to_rigid(0, 0, 0, RowCheck[j], ColumnCheck[j], AngleCheck[j], MovementOfObject)
    affine_trans_contour_xld(ShapeModel, ModelAtNewPosition, MovementOfObject)

变换都一样,只不过之前是用if判断Score,现在使用循环for去操作。

b、使用变换

affine_trans_pixel(MovementOfObject, -120, 0, RowArrowHead, ColumnArrowHead)
dis_arrow(WidowHandle, RowCheck[j], ColumnCheck[j], RowArrowHead, ColumnArrowHead, 2)

在该示例中,增加了一个显示方向的箭头,使用affine_trans_pixel显示箭头的位置,和XLD模板的变换矩阵是一样的。

必须注意的是,要使用affine_trans_pixel而不是affine_trans_point_2d,因为后者使用了不同的图像坐标系,(affine_trans_pixel,affine_trans_contour_xld,affine_trans_region和affine_trans_image)

4.3.3 处理多模板

当同时查找多个模板时,存储关于模板 的信息是有用的,多个XLD模板存储在tuples中,参考实例:HDevelop program examples\solution_guide\shape_matching\multiple_models.dev

a、输入多个XLD模板

creat_scaled_shape_model(ImageROIRing, 'auto', -rad(22.5), rad(45), 'auto', 0.8, 1.2, 'auto', 'none', 'use_polarity', 60, 10, ModelIDRing)
get_shape_model_contours(ShapeModelRing, ModelIDRing, 1)
creat_scaled_shape_model(ImageROINut, 'auto', -rad(30), rad(60), 'auto', 0.6, 1.4, 'auto', 'none', 'use_polarity', 60, 10, ModelIDNut)
inspect_shape_model(ImageROINut, PyramidImage, ModelRegionNut, 1, 30)

get_shape_model_countours用于获取轮廓

b、在tuples中保存多个模板信息

count_obj(ShapeModelRing, NumContoursRing)
get_shape_model_contours(ShapeModelRing, ModelIDRing, 1)
ModelIDs := [ModelIDRing, ModelIDNut]
concat_obj(ShapeModelRing, ShapeModelNut, ShapeModels)
StartContoursInTuple := [1, NumContoursRing+1]

为了方便后续去访问models,XLD轮廓也保存在tuples中,和模板ID是一样的,
使用concat_obj连接XLD的时候一定要注意,XLD已经是tuples了,因为他包含多个轮廓。为了使用属于指定模型的轮廓,需要模型的轮廓数和连接元组中的起始索引数,前者由count_obj生成,轮廓数的起始坐标是1,随后的轮廓索引是1+之前的轮廓数。

c、找到相应的实例

find_scaled_shape_models(SearchImageReduced, ModelIDs, [-rad(22.5), -rad(30)], [rad(45), rad(60)], [0.8, 0.6], [1.2, 1.4], 0.7, 0, 0,'least_squares', 0, 0.8, RowCheck, ColumnCheck, AngleCheck, ScaleCheck, Score, ModelIndex)
for i:= 0 to |Score| - 1 by 1
    Model := ModelIndex[i]
    vector_angle_to_rigid(0, 0, 0, RowCheck[i], ColumnCheck[i], AngleCheck[i], MovementOfObject)
    hom_mat2d_scale(MovementOfObject, ScaleCheck[i], ScaleCheck[i], RowCheck[i], ColumnCheck[i], MoveAndScalingOfObject)
    copy_obj(ShapeModels, ShapeModel, StartContoursInTuple[Model], NumContoursInTuple[Model])
    affine_trans_contour_xld(ShapeModel, ModelAtNewPosition, MoveAndScalingOfObject)
    dev_display (ModelAtNewPosition)
endfor

输出参数模型通过在参数ModelIDs中指定的ID元组中存储相应模型ID的索引来指示匹配属于哪个模型.

因为一个XLD可能包含多个轮廓,所以不能简单的使用select_obj,可以使用操作符copy_obj选择属于模型的轮廓,指定连接元组中的模型的起始索引和轮廓的数量作为参数。copy_obj不复制轮廓,只复制相应的HALCON对象,这些对象可以看作是对轮廓的引用。

4.3.4、 对齐其他的区域

示例:examples\solution_guide\shape_matching\align_measurements.dev
a、定位ROIs

Rect1Row := 244
Rect1Col := 73
DistColRect1Rect2 := 17
Rect2Row := Rect1Row
Rect2Col := Rect1Col + DistColRect1Rect2
RectPhi := rad(90)
RectLength1 := 122
RectLength2 := 2

常见两个测量矩阵ROIs,为了便于可以和XLD一起移动,我们将它移到XLD对应的位置上,参考点使图像的原点,

注意,在移动区域之前,剪切必须关闭。

area_center (ModelROI, Area, CenterROIRow, CenterROIColumn)
get_system ('clip_region', OriginalClipRegion)
set_system ('clip_region', 'false')
move_region (MeasureROI1, MeasureROI1Ref, - CenterROIRow, - CenterROIColumn)
move_region (MeasureROI2, MeasureROI2Ref, - CenterROIRow, - CenterROIColumn)
set_system ('clip_region', OriginalClipRegion)
DistRect1CenterRow := Rect1Row - CenterROIRow
DistRect1CenterCol := Rect1Col - CenterROIColumn
DistRect2CenterRow := Rect2Row - CenterROIRow
DistRect2CenterCol := Rect2Col - CenterROIColumn

b、找到所有的实例

find_shape_model (SearchImage, ModelID, 0, 0, 0.8, 0, 0.5, 'least_squares', 0, 0.7, RowCheck, ColumnCheck, AngleCheck, Score)

c、确定affine transformation矩阵

for i := 0 to |Score|-1 by 1
    vector_angle_to_rigid (0, 0, 0, RowCheck[i], ColumnCheck[i], AngleCheck[i], MovementOfObject)
    affine_trans_contour_xld (ShapeModel, ModelAtNewPosition, MovementOfObject)

计算每一个对象的位置和方向。

d、在相应的位置创建测量对象。

affine_trans_pixel (MovementOfObject, DistRect1CenterRow, DistRect1CenterCol, Rect1RowCheck, Rect1ColCheck)
affine_trans_pixel (MovementOfObject, DistRect2CenterRow, DistRect2CenterCol, Rect2RowCheck, Rect2ColCheck)

计算测量ROI仿射后的新位置,affine_trans_pixel,必须使用affine_trans_pixel而不能使用affine_trans_point_2d,新的测量对象被创建。

RectPhiCheck := RectPhi + AngleCheck[i]
gen_measure_rectangle2 (Rect1RowCheck, Rect1ColCheck, RectPhiCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle1)
gen_measure_rectangle2 (Rect2RowCheck, Rect2ColCheck, RectPhiCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle2)

这里只是用了简单的平移而没有使用旋转变换,可以使用transflate_measure去平移测量对象。

e、测量宽度

measure_pairs (SearchImage, MeasureHandle1, 2, 25, 'negative', 'all', RowEdge11, ColEdge11, Amp11, RowEdge21, ColEdge21, Amp21, Width1, Distance1)
measure_pairs (SearchImage, MeasureHandle2, 2, 25, 'negative', 'all',RowEdge12, ColEdge12, Amp12, RowEdge22, ColEdge22, Amp22, Width2, Distance2)

f、检测测量

NumberTeeth1 := |Width1|
if (NumberTeeth1 < 37)
    for j := 0 to NumberTeeth1 - 2 by 1
        if (Distance1[j] > 4.0)
            RowFault := round(0.5*(RowEdge11[j+1] + RowEdge21[j]))
            ColFault := round(0.5*(ColEdge11[j+1] + ColEdge21[j]))
            disp_rectangle2 (WindowHandle, RowFault, ColFault, 0, 4, 4)

如果测量对象太短或者根本没有的话,边缘不能有效的被提取,那么可以通过测量距离来判定。

4.3.5 对齐查找结果

forward transformation将检测对象通过仿射从模板图映射到查找图,通过transformation可以将modelimage在search image上放到正确位置。

inverse transformation就是讲search image 映射到search image。

值得注意的数,alignment图像只是rotate的和translated,如果要移除perspective或者lens distortions,必须要rectify the image。

示例:HDevelop program examples\solution_guide\shape_matching\rectify_results.dev
a、计算inverse transformation

vector_angle_to_rigid (CenterROIRow, CenterROIColumn, 0, RowCheck, ColumnCheck, AngleCheck, MovementOfObject)
hom_mat2d_invert (MovementOfObject, InverseMovementOfObject)

hom_mat2d_invert获得一些反转信息,注意的是与之前的处理过程不同,transformation是根据reference point的绝对坐标计算的,因为我们希望将图像变换到模板图中。

b、rectify the search image

affine_trans_image (SearchImage, RectifiedSearchImage, InverseMovementOfObject, 'constant', 'false')

对search image使用affine_trans_image,潜在的像素被标记成灰色。

c、提取数字

reduce_domain (RectifiedSearchImage, NumberROI, RectifiedNumberROIImage)
threshold (RectifiedNumberROIImage, Numbers, 0, 128)
connection (Numbers, IndividualNumbers)

一串数字被定为在原图当中,很容易被提取,不幸的是affine_trans_image转换即便是用reduce_domain也是。因为时间约束,需要在放射之前运用它。

a、裁剪search image

affine_trans_region (NumberROI, NumberROIAtNewPosition, MovementOfObject, 'false')
smallest_rectangle1 (NumberROIAtNewPosition, Row1, Column1, Row2, Column2)
crop_rectangle1 (SearchImage, CroppedNumberROIImage, Row1, Column1, Row2, Column2)

使用smallest_rectangle1获取最小的rectangle,search image是这个裁剪的部分。

b、创建affine transformation

hom_mat2d_translate (MovementOfObject, - Row1, - Column1, MoveAndCrop)
hom_mat2d_invert (MoveAndCrop, InverseMoveAndCrop)

裁剪可以作为附加的仿射变换:由裁剪矩形左上角的否定坐标进行的平移。hom_mat2d_translate追加平移操作,hom_mat2d_invert逆变换该操作。

c、平移裁剪图像

affine_trans_image (CroppedNumberROIImage, RectifiedROIImage,InverseMoveAndCrop, 'constant', 'true')
reduce_domain (RectifiedROIImage, NumberROI, RectifiedNumberROIImage)

affine_trans_image修正图像,然后reduced ROI。

4.4 使用估计放缩尺度

与旋转rotation类似,如果没有使用set_shape_model_origin,则尺度变化是在ROI的中心,评估尺度会返回Scale,能够用于相似的计算位置和方向,但是vector_angle_to_rigid不能很灵活的创建scale,示例:HDevelop program examples\solution_guide\shape_matching\multiple_scales.dev

examples\hdevelop\Matching\Shape-Based\find_aniso_shape_model.dev

a、指定点

RowUpperPoint := 284
ColUpperPoint := 278
RowLowerPoint := 362
ColLowerPoint := 278

grasping points直接在model image种植的,
为了将他们和XLD模型一起使用,因此他们都位于XLD模型中。

area_center (ModelROI, Area, CenterROIRow, CenterROIColumn)
RowUpperPointRef := RowUpperPoint - CenterROIRow
ColUpperPointRef := ColUpperPoint - CenterROIColumn
RowLowerPointRef := RowLowerPoint - CenterROIRow
ColLowerPointRef := ColLowerPoint - CenterROIColumn

b、计算仿射

find_scaled_shape_model (SearchImage, ModelID, -rad(30), rad(60), 0.6, 1.4, 0.65, 0, 0, 'least_squares', 0, 0.8, RowCheck,ColumnCheck, AngleCheck, ScaleCheck, Score)
for i := 0 to |Score| - 1 by 1
    vector_angle_to_rigid (0, 0, 0, RowCheck[i], ColumnCheck[i], AngleCheck[i], MovementOfObject)
    hom_mat2d_scale (MovementOfObject, ScaleCheck[i], ScaleCheck[i], RowCheck[i], ColumnCheck[i], MoveAndScalingOfObject)
    affine_trans_contour_xld (ShapeModel, ModelAtNewPosition, MoveAndScalingOfObject)

vector_angle_to_rigid可以确定translational和rotational。追加尺度变化hom_mat2d_scale。注意的地方是匹配配置要作为reference参考点,该操作需要放在translation和rotation之后。

c、计算grasping points

affine_trans_pixel (MoveAndScalingOfObject, RowUpperPointRef, ColUpperPointRef, RowUpperPointCheck, ColUpperPointCheck)
affine_trans_pixel (MoveAndScalingOfObject, RowLowerPointRef, ColLowerPointRef, RowLowerPointCheck, ColLowerPointCheck)

仿射变换也可以用affine_trans_pixel操作符应用于模型图像中的其他点,必须使用affine_trans_pixel and 而不是affine_trans_point_2d.

5、 其他Miscellaneous

5.1、 parallel programming并行运算

可以在多线程中运行,对于单个操作,会自动执行并行化,也就是说如果只是想利用并行化操作,不需要改变任何其他部分。但是,如果您想在不同的线程中应用复杂的代码部分,则不希望操作符的额外并行化,则可以关闭自动并细化开关,手动调整并行度。如果模型的预生成被关闭,实际的模型是在搜索过程中创建的,find_scaled_shape_model模型的生成导致了访问不同线程所需的同步工作导致的性能问题。需要避免两个问题:

  • 在创建初始模型时,可以通过将参数Optimization优化的第二个值设置为“pregeneration”来切换预生成,模型不是在搜索过程中创建的,而是在创建过程中创建的,因此在不同线程中搜索不需要同步。注意,对于这种方法,模型变得非常大,因此会消耗大量内存。
  • 或者你可以多次加载相同的非预生成模型,find_scaled_shape_model。

5.2、适应相机方向改变

如果在倾斜角度下拍摄,shaped-based matching就会失败,如果不是垂直于物体运动的平面,会引入相机的畸变,相应的位置和方向也会改变,应该在匹配之前先做图像校正,则需要经过三个处理过程:

a、calibrate the  camera。使用camera_calibration来确定position和orientation。

b、获得的矫正系数通过gen_image_to_word_plane_map创建映射函数

c、应用于map_image。

也可以不进行矫正,使用可行变的匹配替代给予形状的匹配,考虑perspective形变,将2D homography替代2D pose,

5.3、重用模型

示例:HDevelop program examples\solution_guide\shape_matching\reuse_model.dev

就是将模型保存到文件中

create_scaled_shape_model (ImageROI, 'auto', -rad(30), rad(60), 'auto', 0.6, 1.4, 'auto', 'none', 'use_polarity', 60, 10, ModelID)

存储模型

write_shape_model (ModelID, ModelFile)

读取模型

read_shape_model (ModelFile, ReusedModelID)
get_shape_model_contours (ReusedShapeModel, ReusedModelID, 1)
get_shape_model_origin (ReusedModelID, ReusedRefPointRow, ReusedRefPointCol)
get_shape_model_params (ReusedModelID, NumLevels, AngleStart, AngleExtent,AngleStep, ScaleMin, ScaleMax, ScaleStep, Metric, MinContrast)

read_shape_model读取模型

获取轮廓get_shape_model_contours

获取模板图get_shape_model_origin

获取创建模型的参数get_shape_model_params

find_scaled_shape_model (SearchImage, ReusedModelID, AngleStart, AngleExtent, ScaleMin, ScaleMax, 0.65, 0, 0, 'least_squares', 0, 0.8, RowCheck, ColumnCheck,AngleCheck, ScaleCheck, Score)
for i := 0 to |Score| - 1 by 1
    vector_angle_to_rigid (ReusedRefPointRow, ReusedRefPointCol, 0, RowCheck[i], ColumnCheck[i], AngleCheck[i],MovementOfObject)
    hom_mat2d_scale (MovementOfObject, ScaleCheck[i], ScaleCheck[i], RowCheck[i], ColumnCheck[i], MoveAndScalingOfObject)
    affine_trans_contour_xld (ReusedShapeModel, ModelAtNewPosition, MoveAndScalingOfObject)
    dev_display (ModelAtNewPosition)
endfor

 

  • 17
    点赞
  • 134
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值