[Halcon&定位] 二维仿射变换原理与算子解析

简介: [Halcon&定位] 二维仿射变换原理与算子解析

一. 仿射变换原理

二维仿射变换,顾名思义就是在二维平面内,将对象进行平移、旋转、缩放等变换的行为(还有其他的变换,这里仅论述这最常见的三种)。

进行仿射变换,首先我们待仿射变换的对象位置坐标、角度,然后找到目标对象的位置坐标、角度,通过计算两个参数的差值,就可以求出模板对象A和目标对象B之间的的仿射变换矩阵(二者的位置、角度等关系)。


二. 仿射变换的第一种方式

1、仿射变换的大致流程:

① 通过hom_mat2d_identity初始化一个空的仿射变换矩阵(即[1.0, 0.0, 0.0, 0.0, 1.0, 0.0]);

② 在初始化空的仿射矩阵中增加模板和目标之间的平移、旋转和缩放关系,用到的算子包括hom_mat2d_translate(平移)hom_mat2d_rotate(旋转)hom_mat2d_scale(缩放)等生成仿射变换矩阵(这几个算子可以叠加或者重复使用)

③ 得到模板和目标的仿射变换矩阵之后,可以对图像、区域或XLD执行仿射变换,用到的算子包括affine_trans_image(仿射图像)affine_trans_region(仿射区域)affine_trans_contour_xld(仿射轮廓)

实际应用中,我们求仿射矩阵的目的一般是在匹配时,找到目标对象的模板轮廓并显示到图像上,便于观察确认匹配的准确度。


2、仿射变换用到的核心代码:

函数1hom_mat2d_identity( : : HomMat2D)

功能:初始化一个空的仿射变换矩阵

参数

HomMat2D(in):输入一个空的仿射变换矩阵


函数2hom_mat2d_translate( : : HomMat2D, Tx, Ty : HomMat2DTranslate)

功能:把模板和目标的平移关系添加到防射变换矩阵

参数

HomMat2D(in):空的仿射变换矩阵

Tx(in)Row方向的平移量

Ty(in)Column方向的平移量

HomMat2DTranslate(out):输出平移变换矩阵


函数3hom_mat2d_rotate( : : HomMat2D, Phi, Px, Py: HomMat2DRotate)

功能:把模板和目标的角度关系添加到仿射变换矩阵

参数

HomMat2D(in):上面的平移仿射变换矩阵

Phi(in):旋转角度(逆时针旋转(Phi>0),顺时针旋转(Phi<0),单位弧度)

Px(in):变换的固定点行坐标(Row值)。固定点是指以该点为支撑进行仿射变换 (这里是指围绕这点进行旋转)

Py(in):变换的固定点列坐标(Col值)

HomMat2DRotate(out):输出具有平移+旋转变换关系的二维矩阵

hom_mat2d_rotate里面Phi,Px, Py的取值需要注意一下,比如,需要对下图中的的黑色矩形框进行仿射变换校正,经图像处理得到矩形框的角度是-89°,可以对图像旋转Phi = -1°(顺时针转)或Phi = 359°(逆时针旋转359°),Px = Width / 2Row值,Width 代表图像宽),Py = Height / 2Col值,Height 代表图像高)


函数4hom_mat2d_scale( : : HomMat2D, Sx, Sy, Px, Py : HomMat2DScale)

功能:把模板和目标的缩放关系添加到仿射变换矩阵

参数

HomMat2D(in):上面的平移+旋转仿射变换矩阵

Sx(in)Row方向的缩放系数(放大/缩小倍数)

Sy(in)Col方向的缩放系数

Px(in):缩放中心的Row值(基点)

Py(in): 缩放中心的Col

HomMat2DScale(out):输出具有平移+旋转+缩放变换关系的二维矩阵


函数5affine_trans_contour_xld( Contours : ContoursAffinTrans : HomMat2D : )

功能:对XLD轮廓进行二维仿射变换 (支持缩放,旋转,平移,斜切)

参数

Contours(in)XLD轮廓A

ContoursAffinTrans(out):对XLD轮廓A仿射变换得到的XLD轮廓B

HomMat2D(in): 仿射变换矩阵


函数6affine_trans_image( Image : ImageAffinTrans : HomMat2D, Interpolation, AdaptImageSize : )

功能:对图像进行二维仿射变换 (支持缩放、旋转、平移)

参数

Image(in):图像A

ImageAffinTrans(out):对图像A进行仿射变换得到图像B

HomMat2D(in):仿射变换矩阵

Interpolation(in): 插值算法(nearest_neighborbilinear,constantweighted)

AdaptImageSize(in):结果图像尺寸是否自适应。默认值:false


函数7affine_trans_region( Region : RegionAffineTrans : HomMat2D, Interpolate : )

功能:对区域进行二维仿射变换 (支持缩放、旋转、平移)

参数

Region(in):输入区域A

RegionAffineTrans(out):仿射变换得到的区域B

HomMat2D(in):仿射变换矩阵

Interpolate(in): 插值算法(constantnearest_neighbor)默认值:nearest_neighbor


3、仿射变换实战解析(模板匹配):

*创建模板
read_image (Image, 'D:/Data/3.jpg')
gen_rectangle1 (ModelRegion, 534.692, 581.663, 618.315, 621.485)
reduce_domain (Image, ModelRegion, TemplateImage)
create_shape_model (TemplateImage, 6, rad(0), rad(360), rad(0.2684), ['none','no_pregeneration'], 'use_polarity', [24,36,5], 4, ModelID)
area_center (ModelRegion, ModelRegionArea, AlignmentRow, AlignmentCol)
*显示模板轮廓
get_shape_model_contours (ModelContours, ModelID, 1)
* Matching 01: Get the reference position
area_center (ModelRegion, ModelRegionArea, RefRow, RefColumn)
vector_angle_to_rigid (0, 0, 0, RefRow, RefColumn, 0, HomMat2D)
affine_trans_contour_xld (ModelContours, TransContours, HomMat2D)
*开始读图匹配
TestImages := ['C:/Users/Administrator/Desktop/3.9/11111111.1.jpg']
for T := 0 to 0 by 1
    read_image (Image, TestImages[T])
    find_shape_model (Image, ModelID, rad(0), rad(360), 0.9, 0, 0.5, ['least_squares','max_deformation 6'], [6,1], 1, Row, Column, Angle, Score)
    dev_display (Image)
    for I := 0 to |Score| - 1 by 1
        hom_mat2d_identity (HomMat2D)
        hom_mat2d_rotate (HomMat2D, Angle[I], 0, 0, HomMat2D)
        hom_mat2d_translate (HomMat2D, Row[I], Column[I], HomMat2D)
        affine_trans_contour_xld (ModelContours, TransContours, HomMat2D)
        dev_set_color ('green')
        dev_display (TransContours)
        stop ()
    endfor
endfor
stop ()
clear_shape_model (ModelID)


代码解析:

创建模板:

这里要注意的是,创建模板之后模板的位置变为(0,0),模板的当前角度也默认为,在图像的左上角位置。

显示模板轮廓:

这里在获取模板轮廓自身的仿射矩阵中:vector_angle_to_rigid (0, 0, 0, RefRow, RefColumn, 0, HomMat2D)参数是(0,0,0)的原因是因为在创建模板之后会自动将模板的位置和当前角度都为0,即模板是在窗口的左上角的,我们需要做的是将左上角的初始模板(0,0,0)仿射到图像中的模板位置,并显示出来。

读图、匹配模板,对模板轮廓进行仿射变换:

hom_mat2d_identity创建一个初始化矩阵

②利用hom_mat2d_rotate,找到两者角度的差值。注意是以hom_mat2d_rotate的第3、4参数为基准坐标点进行旋转,这里是先旋转在平移,所以是先以模板中心坐标(0,0)为基准进行旋转,旋转了Angle[I] - 0度,在平移。如果是先平移在旋转,则要以目标位置的中心坐标为基准进行旋转,这个要注意。

③利用hom_mat2d_translate算子输入目标和模板的坐标差值,Row[I] - 0Column[I] - 0,生成平移矩阵 HomMat2D

上面三步的目的就为了要这个旋转平移矩阵HomMat2D

④使用affine_trans_contour_xld就可以对模板轮廓A进行仿射变换,仿射到新图像的模板位置处。


三. 仿射变换的第二种方式

有时候,并不需要创建初始化矩阵也可以执行仿射变换,例如我们在上面实例中显示模板轮廓用到的仿射变换vector_angle_to_rigid算子就是如此,该算子的作用是生成一个平移、旋转仿射变换矩阵。

1、核心算子

函数affine_trans_region( : : Row1, Column1, Angle1, Row2, Column2, Angle2 : HomMat2D)

功能:根据点和角度计算刚性仿射变换矩阵,支持旋转和平移,相当于将hom_mat2d_translatehom_mat2d_rotate算子功能进行了合并

参数

Row1(in):原始点行坐标

Column1(in):原始点列坐标

Angle1(in):原始点角度

Row2(in):目标点行坐标

Column2(in):目标点列坐标

Angle2(in):目标点角度

HomMat2D(out):输出仿射变换矩阵

该算子意思是:先将图像旋转,旋转角度为(Angle2 - Angle1) (逆时针为正),旋转中心坐标是(Row1, Column1)。再将原图的点(Row1, Column1)一一对应移到点 (Row2, Column2)上,移动的row和column方向的位移分别是( Row2 - Row1)、( Column2 - Column1),该算子方便就方便在不用考虑旋转中心了,直接将前后的坐标和角度输入即可

vector_angle_to_rigid最常用到的场合一般是模板匹配之类的算法场合,通常用在find_shape_model等算子后面。


2、仿射变换实战解析(模板匹配):对图像、region和XLD进行仿射变换

read_image (Image, 'D:/Data/1.jpg')
gen_rectangle1 (ModelRegion, 566.247, 490.534, 594.44, 535.676)
area_center (ModelRegion, Area, Row, Column)
reduce_domain (Image, ModelRegion, TemplateImage)
create_ncc_model (TemplateImage, 'auto', rad(0), rad(20), 'auto', 'use_polarity', ModelId)
find_ncc_model (Image, ModelId, rad(0), rad(20), 0.8, 5, 0.5, 'true', 0, MatchingRow, MatchingCol, MatchingAngle, MatchingScore)
for MatchingObjIdx := 0 to |MatchingScore| - 1 by 1
    gen_cross_contour_xld (TransContours, MatchingRow, MatchingCol, 20, MatchingAngle)
    dev_display (TransContours)
endfor
for MatchingObjIdx := 0 to |MatchingScore| - 1 by 1
vector_angle_to_rigid (Row, Column, 0, MatchingRow[MatchingObjIdx], MatchingCol[MatchingObjIdx], MatchingAngle[MatchingObjIdx], HomMat2D)
affine_trans_region (ModelRegion, RegionAffineTrans, HomMat2D, 'nearest_neighbor')
 *显示模式为“边界”,否则会显示整个实心矩形区域
 dev_set_draw ('margin')
 dev_display (RegionAffineTrans)
endfor
clear_ncc_model (ModelId)

效果和上面一样,都是通过引脚模板,找到芯片的所有引脚,就不放图了。

注:

  1. 上面的例子roi区域是不带方向的,在灰度值匹配中,如果创建的是带方向的roi区域,create_ncc_model创建模板后,不管之前的roi区域是多少角度的,create_ncc_model函数内部都将角度默认为0°的,所以在后面的仿射变换是vector_angle_to_rigid第三个参数应该为,从到匹配对象的角度。
  2. 如果矩形框角度与找到的对象角度不匹配,需要修改create_ncc_model (Operator)的第3、4参数,即搜索的角度范围,一般直接设置0 — 360°就可以了。
  3. vector_angle_to_rigid(Operator)中,什么时候第一、二参数为0
    一般我们在get_shape_model_contours获取模板轮廓时,halcon会默认将轮廓放置在窗口左上角,即中心坐标为(0,0)。这时我们仿射该模板轮廓进行显示的时候就需要将第一、二参数输出为0
HHomMat2D HomMat2d;
HomMat2d.VectorAngleToRigid(0, 0, 0, row[0].D(), col[0].D(), rotate[0].D());
HXLDCont ho_ModelContour = m_model.GetShapeModelContours(1);
_resRgn = HomMat2d.AffineTransContourXld(ho_ModelContour);

戳戳小手帮忙点个免费的赞和关注吧,嘿嘿。
目录
相关文章
|
5天前
|
Java
并发编程之线程池的底层原理的详细解析
并发编程之线程池的底层原理的详细解析
15 0
|
29天前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
66 1
|
2天前
|
安全 索引
【集合】03 Linkedlist原理深入解析
【集合】03 Linkedlist原理深入解析
6 0
|
2天前
|
Java Spring 容器
SpringBoot自动装配原理之@Import注解解析
SpringBoot自动装配原理之@Import注解解析
|
4天前
|
缓存 JavaScript 前端开发
|
5天前
|
SQL 分布式计算 资源调度
一文解析 ODPS SQL 任务优化方法原理
本文重点尝试从ODPS SQL的逻辑执行计划和Logview中的执行计划出发,分析日常数据研发过程中各种优化方法背后的原理,覆盖了部分调优方法的分析,从知道怎么优化,到为什么这样优化,以及还能怎样优化。
|
5天前
|
JSON Java Maven
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
11 0
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
|
5天前
|
前端开发 JavaScript 编译器
深入解析JavaScript中的异步编程:Promises与async/await的使用与原理
【4月更文挑战第22天】本文深入解析JavaScript异步编程,重点讨论Promises和async/await。Promises用于管理异步操作,有pending、fulfilled和rejected三种状态。通过.then()和.catch()处理结果,但可能导致回调地狱。async/await是ES2017的语法糖,使异步编程更直观,类似同步代码,通过事件循环和微任务队列实现。两者各有优势,适用于不同场景,能有效提升代码可读性和维护性。
|
16天前
|
机器学习/深度学习 分布式计算 BI
Flink实时流处理框架原理与应用:面试经验与必备知识点解析
【4月更文挑战第9天】本文详尽探讨了Flink实时流处理框架的原理,包括运行时架构、数据流模型、状态管理和容错机制、资源调度与优化以及与外部系统的集成。此外,还介绍了Flink在实时数据管道、分析、数仓与BI、机器学习等领域的应用实践。同时,文章提供了面试经验与常见问题解析,如Flink与其他系统的对比、实际项目挑战及解决方案,并展望了Flink的未来发展趋势。附带Java DataStream API代码样例,为学习和面试准备提供了实用素材。
39 0
|
1月前
|
存储 并行计算 算法
C++动态规划的全面解析:从原理到实践
C++动态规划的全面解析:从原理到实践
95 0

推荐镜像

更多