一、介绍
投影变换也叫透射变换、投影映射。透射变换是将图像投影到一个新的视平面,是一种二维坐标到三维坐标的变换。
透射变换是仿射变换的延续,也可以说仿射变换是透射变换的一种特殊形式。其特殊性在于变换后图像的形状仍然维持原状。投影变换包括的情况很多,有可能变换前后图像的形状发生了很大的改变,如对边不再平行,或者发生了透视畸变,这时可以使用投影变换使其恢复原状。其步骤与仿射变换类似,首先计算投影变换矩阵,然后计算投影变换参数,最后将投影变换矩阵映射到对象上。
透射变换是三维空间上的变换,因此,对于二维图像,最后一个原坐标z恒为1,变换矩阵的最后一个参数也恒为1。
要计算投影变换矩阵,应找出投影区域的特征点的位置及其投影后的位置,通过hom_vector_to_proj_hom_mat2d算子进线换算,就可以根据已知的投影对应的点的值计算投影变换矩阵,然后使用projective_trans_image对图形进线投射变换,就能得到投影后的图像了。
所以,透射变换的矩阵有8个未知数,要求解就需要找到4组映射点,四个点就刚好确定了一个三维空间。图像经过透视变换后通常不是平行四边形。与仿射变换类似,在经过变换之后,图像的灰度值也要经过图像插值计算,得到变换后的图像。

二、Halcon中相关算子
Transformations / 2D Transformations 根据给定点的投影计算一个同质变换矩阵 hom_vector_to_proj_hom_mat2d( : : Px, Py, Pw, Qx, Qy, Qw, Method : HomMat2D) Px:输入参数,图像变换前图像的顶点x坐标。 Py:输入参数,图像变换前图像的顶点y坐标。 Pw:输入参数,图像变换前图像的顶点w坐标。 Qx:输入参数,图像变换后图像的顶点x坐标。 Qy:输入参数,图像变换后图像的顶点y坐标。 Qw:输入参数,图像变换后图像的顶点w坐标。 Method:输入参数,变换方式选择。默认'normalized_dlt', 列表【 'dlt'算法最快速简单,但是有相对的不准确的误差 'normalized_dlt'速度与精度较好 】。 HomMat2D:输出参数,输出齐次投影变换矩阵。 |
Transformations / 2D Transformations 根据给定点的投影计算一个投影变换矩阵 vector_to_proj_hom_mat2d( : : Px, Py, Qx, Qy, Method, CovXX1, CovYY1, CovXY1, CovXX2, CovYY2, CovXY2 : HomMat2D, Covariance) Px:输入参数,图像变换前图像的顶点x坐标。 Py:输入参数,图像变换前图像的顶点y坐标。 Qx:输入参数,图像变换后图像的顶点x坐标。 Qy:输入参数,图像变换后图像的顶点y坐标。 Method:输入参数,变换方式选择。默认 'normalized_dlt', 列表【 'dlt'算法最快速简单,但是有相对的不准确的误差 'gold_standard'优化较好但速度较慢 'normalized_dlt'速度与精度较好 】 CovXX1:输入参数,图像变换前图像对应x值坐标的row方向的变动。默认[]。 CovYY1:输入参数,图像变换前图像对应y值坐标的col方向的变动。默认[]。 CovXY1:输入参数,图像变换前图像对应点的协方差。默认[]。 CovXX2:输入参数,图像变换后图像对应x值坐标的row方向的变动。默认[]。 CovYY2:输入参数,图像变换后图像对应y值坐标的col方向的变动。默认[]。 CovXY2:输入参数,图像变换后图像对应点的协方差。默认[]。 HomMat2D:输出参数,输出映射变换矩阵。 Covariance:输出参数,输出9×9协方差矩阵的投影变换矩阵。 |
Filters / Geometric Transformations 对图像应用投影变换 projective_trans_image(Image : TransImage : HomMat2D, Interpolation, AdaptImageSize, TransformDomain : ) Image:输入参数,输入需要变换的多通道图像。 TransImage:输出参数,输出变换后的图像。 HomMat2D:输入参数,输入变换矩阵。 Interpolation:输入参数,插值的方式。默认 'bilinear',列表【 'bilinear', 'nearest_neighbor'】。 AdaptImageSize:输入参数,是否自动调整输出图像的大小。默认'false',列表【'false', 'true'】。 TransformDomain:输入参数,输入图像的域也应该进行变换吗?。默认'false',列表【'false', 'true'】。 |
Regions / Geometric Transformations 对区域应用投影变换 projective_trans_region(Regions : TransRegions : HomMat2D, Interpolation : ) Regions:输入参数,输入区域。 TransRegions:输出参数,输出变换后的区域。 HomMat2D:输入参数,输入映射变换矩阵。 Interpolation:输入参数,插值的方式。默认 'bilinear',列表【 'bilinear', 'nearest_neighbor'】。 |
三、投影变换的案例
1、vector_to_proj_hom_mat2d案例
dev_set_draw('margin')
read_image(Image,'ecc200_to_preprocess_001.png')
*灰度阈值分割出区域
threshold(Image, Region, 0, 90)
*改变区域的形状为凸性
shape_trans(Region, RegionTrans, 'convex')
*生成XLD亚像素级轮廓,'border'边框像素的外边框作为轮廓点
gen_contour_region_xld(RegionTrans, Contours, 'border')
*将XLD轮廓分割成线段。
segment_contours_xld(Contours, ContoursSplit, 'lines', 5, 10, 1)
*保存四边形的顶点X坐标
X:=[]
*保存四边形的顶点y坐标
Y:=[]
*根据轮廓的相对位置排序
sort_contours_xld(ContoursSplit, SortedRegions, 'lower_left', 'true', 'row')
*计算元组中的数量
count_obj(SortedRegions, Number)
for Index:=1 to Number by 1
*按顺序选择数据
select_obj(SortedRegions, ObjectSelected, Index)
*拟合直线
fit_line_contour_xld(ObjectSelected, 'tukey', -1, 0, 5, 2, RowBegin, ColBegin, RowEnd, ColEnd, Nr, Nc, Dist)
*统一整合元组
tuple_concat(X,RowBegin,X)
tuple_concat(Y,ColBegin,Y)
endfor
*为每个输入点生成一个十字形状的XLD轮廓线
gen_cross_contour_xld(Cross,X,Y,10, 0.785398)
*根据给的变换前和变换后的数据计算一个投影矩阵
*[0,400,400,0],[0,0,400,400]这里的顺序一定要注意!!!,必须按照上面X和Y元组中的变换前的点的顺序
*且每个元组内是4这,因为要和上面变换前的坐标数量对应
vector_to_proj_hom_mat2d(X,Y,[0,400,400,0],[0,0,400,400],'normalized_dlt', [], [], [], [], [], [], HomMat2D, Covariance)
*对图像应用投影变换
projective_trans_image(Image,TransImage1, HomMat2D, 'bilinear', 'false', 'false')

2、hom_vector_to_proj_hom_mat2d 案例
read_image(Image,'ecc200_to_preprocess_001.png')
X:=[130,225,290,63]
Y:=[101,96,289,269]
hom_vector_to_proj_hom_mat2d(X,Y,[1,1,1,1],[0,400,400,0], [0,0,400,400],[1,1,1,1],'normalized_dlt', HomMat2D)
projective_trans_image(Image, TransImage, HomMat2D, 'bilinear', 'false', 'false')
3、案例3
*关闭当前显示窗口,清空屏幕
*dev_close_window ()
*读取测试图像
read_image (Image_display, 'display.jpg')
*将图像转化为灰度图像
rgb1_to_gray (Image_display, GrayImage)
*获取图像的尺寸
get_image_size(Image_display,imageWidth, imageHeight)
*新建显示窗口,适应图像尺寸
dev_open_window (0, 0, imageWidth, imageHeight, 'black', WindowHandle1)
dev_display (GrayImage)
*初始化角点坐标
XCoordCorners := []
YCoordCorners := []
*阈值处理,提取较暗的区域
threshold(GrayImage,DarkRegion,0, 80)
*分离不相连的区域
connection (DarkRegion, ConnectedRegions)
*选择面积最大的暗色区域,即屏幕区域
select_shape_std (ConnectedRegions, displayRegion, 'max_area', 70)
*裁剪屏幕区域
reduce_domain (GrayImage, displayRegion, displayImage)
*创建边缘轮廓
gen_contour_region_xld (displayRegion, Contours, 'border')
*将轮廓分割为边
segment_contours_xld (Contours, ContoursSplit, 'lines', 5, 4, 2)
*获取边的数量
count_obj (ContoursSplit, Number)
*存储每条边的起点位置
for index:=1 to Number by 1
select_obj(ContoursSplit, ObjectCurrent, index)
*拟合每条边
fit_line_contour_xld (ObjectCurrent, 'tukey', -1, 0, 5, 2, RowBegin, ColBegin, RowEnd, ColEnd, Nr, Nc, Dist)
*存储每条边的顶点x坐标
tuple_concat (XCoordCorners, RowBegin, XCoordCorners)
*存储每条边的顶点y坐标
tuple_concat (YCoordCorners, ColBegin, YCoordCorners)
endfor
* 投影变换给四个特征点与校正后的坐标建立关联
XOff:= 100
YOff:= 100*imageHeight/imageWidth
hom_vector_to_proj_hom_mat2d (XCoordCorners, YCoordCorners, [1,1,1,1], [YOff,YOff,imageHeight-YOff,imageHeight-YOff], [XOff,imageWidth-XOff,imageWidth-XOff,XOff], [1,1,1,1], 'normalized_dlt', HomMat2D)
*投影变换
projective_trans_image (Image_display, Image_rectified, HomMat2D, 'bilinear', 'false', 'false')
* 显示校正结果
dev_display (Image_rectified)
