一、实例 透视形变图像校正
透视形变图形校正步骤如下
1.读取图像,并对图像进行简单的处理,分割出目标形变区域
2.获取形变区域的轮廓,并计算出顶点坐标信息
3.利用上一步得出的坐标信息,计算投影变换矩阵
4.进行投影变换
二、实现代码
1.将图像转化为灰度图像
rgb1_to_gray (Image_display, GrayImage)
rgb1_to_gray将RGB图像转换为灰度图像
RGB图像的三个通道作为输入图像的前三个通道传递
根据以下公式对图像进行变换:
灰色= 0.299 *红色+ 0.587 *绿色+ 0.114 *蓝色
2.获取图像尺寸
get_image_size(Image_display,imageWidth, imageHeight)
算子get_image_size返回输入图像的大小(宽度和高度)
3.阈值处理,提取较暗的区域DarkRegion
threshold(GrayImage,DarkRegion,0, 80)
阈值选择输入图像中灰度值g满足以下条件的像素:MinGray≤g≤MaxGray
4.分离不相连的区域
connection (DarkRegion, ConnectedRegions)
5.选择面积最大的暗色区域
select_shape_std (ConnectedRegions, displayRegion, 'max_area', 70)
max_area:选择面积最大的区域
6.裁剪屏幕区域
reduce_domain (GrayImage, displayRegion, displayImage)
算子reduce_domain将给定图像的定义域缩小到指定的区域。新定义域计算为旧定义域与区域的交点。因此,新的定义域可以是区域的子集。矩阵的大小没有改变。
指定图像:GrayImage 指定区域:displayRegion 输出图像:displayImage
7.创建边缘轮廓
gen_contour_region_xld (displayRegion, Contours, 'border')
gen_contour_region_xld生成XLD轮廓。如果区域是通过分割操作获得的,则该操作符很有用,但更高层次的操作符,如多边形近似和平行提取,将在边界上执行。对于输入区域的每个连接分量,生成边界的闭合轮廓。
'center':边界像素的中心被用作轮廓点。
'border':边界像素的外部边界被用作轮廓点。
8.将轮廓分割为边
segment_contours_xld (Contours, ContoursSplit, 'lines', 5, 4, 2)
SmoothCont :用于平滑轮廓的点数,取值范围:0、3、5(default)、7、9
MaxLineDist1:轮廓线和近似线之间的最大距离,默认值:4.0
MaxLineDist2:等高线与近似线之间的最大距离,默认值:2.0
9.获取边的数量
count_obj (ContoursSplit, Number)
算子count_obj为对象参数Objects确定它包含的对象数量。在这个连接中,应该注意对象与连接组件是不同的(参见连接)。例如,一个区域由三个未连通的部分组成,其对象数为1。
10.
*存储每条边的起点位置
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
select_obj将带有Index(从1开始)给出的索引的图标对象从图标输入对象元组objects复制到输出对象ObjectSelected。没有为区域和映像分配新的存储空间。相反,将创建包含对现有对象引用的新对象。对象元组中的对象个数可以通过操作符count_obj查询。
fit_line_contour_xld通过线段逼近XLD轮廓。它不执行输入轮廓的分割。因此,必须确保每个轮廓对应一个且仅对应一个线段。算子返回每个轮廓线的起点(RowBegin, ColBegin),终点(RowEnd, ColEnd),以及由直线的法向量(Nr, Nc)及其距原点的距离Dist给出的轮廓线的回归线,即直线方程由r·Nr+c·Nc-Dist=0。
MaxNumPoints用于计算的轮廓点的最大数量(所有点为-1)
ClippingEndPoints拟合时在轮廓的开始和结束处要忽略的点的数量
Iterations迭代最大迭代次数
ClippingFactor剔除异常值的裁剪因子(典型值:“huber”和“drop”为1.0,“tukey”为2.0)
RowBegin线段起始点的行坐标。
ColBegin线段起始点的列坐标。
RowEnd线段端点的行坐标。
ColEnd线段端点的列坐标。
Nr线参数:法向量的行坐标
Nc线参数:法向量的列坐标
Dist 直线参数:直线到原点的距离
tuple_concat将输入元组T1和T2连接到一个新的元组Concat。Concat的第一个元素符合T1的元素,Concat的其余元素符合T2的元素
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)
hom_vector_to_proj_hom_mat2d确定齐次射影变换矩阵HomMat2D,它最优地满足由至少4个点.如果给出的点对(Px,Py,Pw), (Qx,Qy,Qw)少于4对,则不存在唯一解;如果给出的点对恰好是4对,则矩阵HomMat2D完全按照所需的方式对它们进行变换;如果给出的点对多于4对,则hom_vector_to_projec_hom_mat2d寻求将变换误差最小化。为了实现这样的最小化,有两种不同的算法可用。使用的算法可以通过参数Method来选择。对于传统的几何问题,Method='normalized_dlt'通常会得到更好的结果。但是,如果坐标Qw或Pw中的一个等于0,则必须选择Method='dlt'。
与vector_to_proj_hom_mat2d相反,hom_vector_to_proj_hom_mat2d对点使用齐次坐标,因此可以使用无穷远处的点(Pw = 0或Qw = 0)来确定转换。如果使用有限点,通常将Pw和Qw设为1。在这种情况下,也可以使用vector_to_proj_hom_mat2d。Vector_to_proj_hom_mat2d的优点是可以使用一个额外的优化方法,并且可以考虑到点的协方差。如果还没有确定点之间的对应关系,那么应该使用proj_match_points_ransac来确定对应关系以及转换。
如果要转换的点是在标准图像坐标中指定的,那么它们的行坐标必须传递为Px,列坐标传递为Py。这对于获取图像的右手坐标系是必要的。特别是,这保证了旋转是在正确的方向上进行的。注意,矩阵的(x,y)顺序很自然地对应于图像中坐标的通常顺序(行,列)。
11.投影变换
projective_trans_image (Image_display, Image_rectified, HomMat2D, 'bilinear', 'false', 'false')
projecve_trans_image将齐次变换矩阵HomMat2D确定的射影变换(homography)应用到输入图像image上,并将结果存储到输出图像TransImage中。
完整实现代码
*关闭当前显示窗口,清空屏幕
dev_close_window ()
*读取测试图像
read_image (Image_display, 'C:/Users/Desktop/code/data/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)
三、显示结果