图像到图像的映射
一、实验目的
1、学习了解本篇博客中 H_from_points(fp,tp)和affine_from_points函数;
2、根据匹配点,通过最小二乘法分别求解单应性变换矩阵和仿射变换矩阵;
3、【图像变换】根据仿射或单应性变换实现图像的扭曲、映射、融合。
二、单应性变换
【原理及数据】
单应性变换也称为“透视变换”
- 是将一个平面内的点映射到另一个平面内的二维投影变换。(平面是指图像或者三维中的平面表示)。
- 具有很强的实用性,比如图像配准,图像纠正和纹理扭曲,以及创建全景图像。
- 本质上,单应性变换H,按照下面的方程映射二维中的点(齐次坐标意义下):
- 点的齐次坐标是依赖于其尺度定义的,所以,x=[x,y,w]=[ax,ay,aw]=[x/w,y/w,1]都表示同一个二维点。因此,单应性矩阵H也仅依赖尺度定义,所以,单应性矩阵具有8个独立的自由度。我们通常使用w=1来归一化点,这样,点具有唯一的图像坐标x和y。这个额外的坐标是的我们可以简单地使用一个矩阵来表示变换。
【代码】
创建homography.py文件,使用下边的函数实现对点进行归一化和转换齐次坐标的功能:
def normallize(points):
"""在齐次坐标意义下,对点集进行归一化,是最后一行为1"""
for row in points:
row /= points[-1]
return points
def make_homog(points):
"""将点集(dim×n的数组)转换为齐次坐标表示"""
return vstack((points,ones((1, points.shape[1]))))
【分析】
行点和变换处理时,我们会按照列优先的原则存储这些点。因此,n个二维点集将会存储为齐次坐标意义下的一个3 *n数组。这种格式使得矩阵乘法和点的变换操作更加容易。
1、直接线性变换
【原理及数据】
单应性矩阵可以由两幅图像中对应点对计算出来。一个完全射影变换具有8个自由度,根据对应点约束,每个对应点对可以写出两个方程,分别对应于x和y坐标:
因此,计算单应性矩阵H需要4个对应点对。
DLT(Direct Linear Transformation,直接线性变换)是给定4个点或者更多对应点对矩阵,来计算单应性矩阵H的算法。将单应性矩阵H作用在对应点上,重新写出该方程,我们可以得到下面的方程:
又因为上式即:
所以Ah=0,其中A是一个具有对应点对二倍数量行数的矩阵。将这些对应点对方程的系数堆叠到一个矩阵红,我们可以使用SVD算法找到H的最小二乘解。
【代码】
- 下面是算法代码:(将其添加至homography.py文件中)
def H_from_points(fp, tp):
"""使用线性DLT方法,计算单应性矩阵H,使fp映射到tp。点自动进行归一化"""
if fp.shape != tp.shape:
raise RuntimeError('number of points do not match')
# 对点进行归一化(对数值计算很重要)
# --- 映射起始点 ---
m = mean(fp[:2], axis=1)
maxstd = max(std(fp[:2], axis=1)) + 1e-9
C1 = diag([1/maxstd, 1/maxstd, 1])
C1[0][2] = -m[0]/maxstd
C1[1][2] = -m[1]/maxstd
fp = dot(C1,fp)
# --- 映射对应点 ---
m = mean(tp[:2], axis=1)
maxstd = max(std(tp[:2], axis=1)) + 1e-9
C2 = diag([1 / maxstd, 1 / maxstd, 1])
C2[0][2] = -m[0] / maxstd
C2[1][2] = -m[1] / maxstd
tp = dot(C2, tp)
# 创建用于线性方法的矩阵,对于每个对应对,在矩阵中会出现两行数值
nbr_correspondences = fp.shape[1]
A = zeros((2 * nbr_correspondences, 9))
for i in range(nbr_correspondences):
A[2*i] = [-fp[0][i], -fp[1][i],-1,0,0,0,
tp[0][i]*fp[0][i],tp[0]