一. 仿射变换原理
二维仿射变换,顾名思义就是在二维平面内,将对象进行平移、旋转、缩放等变换的行为(还有其他的变换,这里仅论述这最常见的三种)。
进行仿射变换,首先我们待仿射变换的对象位置坐标、角度,然后找到目标对象的位置坐标、角度,通过计算两个参数的差值,就可以求出模板对象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、仿射变换用到的核心代码:
函数1:hom_mat2d_identity( : : HomMat2D)
功能:初始化一个空的仿射变换矩阵
参数:
HomMat2D(in):输入一个空的仿射变换矩阵
函数2:hom_mat2d_translate( : : HomMat2D, Tx, Ty : HomMat2DTranslate)
功能:把模板和目标的平移关系添加到防射变换矩阵
参数:
HomMat2D(in):空的仿射变换矩阵
Tx(in):Row
方向的平移量
Ty(in):Column
方向的平移量
HomMat2DTranslate(out):输出平移变换矩阵
函数3:hom_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°
(顺时针转1°
)或Phi = 359°
(逆时针旋转359°
),Px = Width / 2
(Row
值,Width
代表图像宽),Py = Height / 2
(Col
值,Height
代表图像高)
函数4:hom_mat2d_scale( : : HomMat2D, Sx, Sy, Px, Py : HomMat2DScale)
功能:把模板和目标的缩放关系添加到仿射变换矩阵
参数:
HomMat2D(in):上面的平移+旋转仿射变换矩阵
Sx(in):Row
方向的缩放系数(放大/缩小倍数)
Sy(in):Col
方向的缩放系数
Px(in):缩放中心的Row
值(基点)
Py(in): 缩放中心的Col
值
HomMat2DScale(out):输出具有平移+旋转+缩放变换关系的二维矩阵
函数5:affine_trans_contour_xld( Contours : ContoursAffinTrans : HomMat2D : )
功能:对XLD
轮廓进行二维仿射变换 (支持缩放,旋转,平移,斜切)
参数:
Contours(in):XLD
轮廓A
ContoursAffinTrans(out):对XLD
轮廓A
仿射变换得到的XLD
轮廓B
HomMat2D(in): 仿射变换矩阵
函数6:affine_trans_image( Image : ImageAffinTrans : HomMat2D, Interpolation, AdaptImageSize : )
功能:对图像进行二维仿射变换 (支持缩放、旋转、平移)
参数:
Image(in):图像A
ImageAffinTrans(out):对图像A
进行仿射变换得到图像B
HomMat2D(in):仿射变换矩阵
Interpolation(in): 插值算法(nearest_neighbor
,bilinear,constant
,weighted
)
AdaptImageSize(in):结果图像尺寸是否自适应。默认值:false
函数7:affine_trans_region( Region : RegionAffineTrans : HomMat2D, Interpolate : )
功能:对区域进行二维仿射变换 (支持缩放、旋转、平移)
参数:
Region(in):输入区域A
RegionAffineTrans(out):仿射变换得到的区域B
HomMat2D(in):仿射变换矩阵
Interpolate(in): 插值算法(constant
,nearest_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)
,模板的当前角度也默认为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] - 0
,Column[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_translate
和hom_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)
效果和上面一样,都是通过引脚模板,找到芯片的所有引脚,就不放图了。
注:
- 上面的例子
roi
区域是不带方向的,在灰度值匹配中,如果创建的是带方向的roi
区域,create_ncc_model
创建模板后,不管之前的roi
区域是多少角度的,create_ncc_model
函数内部都将角度默认为0°的,所以在后面的仿射变换是vector_angle_to_rigid
第三个参数应该为0°
,从0°
到匹配对象的角度。 - 如果矩形框角度与找到的对象角度不匹配,需要修改
create_ncc_model (Operator)
的第3、4参数,即搜索的角度范围,一般直接设置0 — 360°
就可以了。 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);
戳戳小手帮忙点个免费的赞和关注吧,嘿嘿。 |