cs231A Homework-2:ps-code2-part-2
2 图片校正 之 单应性匹配
2.1 求解过程
校正两个图片不需要就知道相机的内参K和外参矩阵R,T,只需要通过基础矩阵计算极线;
然后计算所以极线的交点—极点;由于噪点的干扰,不可能交于一点,因此计算极点,利用最小二乘方法求得极线拟合一点;
并且在极线上的每一点:
如果定义极线集合:
可以得到:
因此整个步骤为:
- 通过归一化8点算法获取基本矩阵
- 极线交于极点: 通过最小二乘误差拟合
- svd计算 极点
在求得极点e,e’后,如果极点在水平方向上不是无限的,说明图片没有平行,如果点是无限的,说明图片平行了;
因此,我们的目的:
- 寻找一对单应性矩阵H1,H2,使得极点无穷,即两张图片平行;
(1). 寻找H2:令e’在水平方向上无限,即为点(f,0,0)
- 将第二幅图的中心移动到(0,0,1)在齐次坐标系下;
这个平移矩阵为:
(2). 应用一个旋转矩阵:使极点坐标旋转到水平坐标轴上,变为(f, 0, 1)
- 如果e‘在平移后Te’的坐标为:(e1’,e2’,1),旋转矩阵为:
(3). 将极点坐标由(f,0,1)==>(f,0,0)
- 只需要变换矩阵:
经过上面几个步骤。我们可以得到无限极点:这个单应性变换H2为:
- 为了寻找单应性矩阵H1,,需要最小化两个图片对应点的均方差之和来获得H1
求导后,可以得到:
!
计算式子中的未知参数:
(1). 首先计算M
任意3*3的斜对称矩阵:
因为任何向量的叉积矩阵 是一个斜对称矩阵:
如图,a向量的叉乘矩阵为斜对称矩阵;
因此,前面公式中:
合并后,
如果M每一列缩放e,则F也需要变化:
(2). 计算Ha矩阵中的参数a
- 已经知道了H2, M,如果将图片1中的点p变换到图片2中,然后经过H2变换:
这两个点应该是最近点,然后使用最小二乘发来最小化误差:
假设两个点齐次坐标为:
最小化式子为:
因为最后一项两个点在水平线上,则为常数
最终,这个问题变成了解决最小二乘问题:
求得a的参数后,得到了HA,H2,M三个矩阵,根据上面的式子:
最终可以求得H1;
2.2 python 实现
在经过上面的了解:
一、 计算极点
def compute_epipole(points1, points2, F):
# F.Tp2 = l, 求得p2到p1面上的映射直线
line = F.T.dot(points2.T) # 3 * N
lineT = line.T # N * 3
u, s, vt = np.linalg.svd(lineT)
e = vt[-1, :] # 最优解
e /= e[2] # 齐次坐标(x, y, 1)
return e
二、 计算 H1,H2
def compute_matching_homographies(e2, F, im2, points1, points2):
# 首先计算H2
W = im2.shape[1]
H = im2.shape[0]
# 平移矩阵T
T = np.identity(3)
T[0, 2] = -1.0 * W /2
T[1, 2] = -1.0 * H /2
# 旋转矩阵R
e = T.dot(e2) # 极点平移过后形成(x',y',1)
e_x = e[0]
e_y = e[1]
if e_x >= 0:
alpha = 1.0
else:
alpha = -1.0 # 旋转矩阵alpha 正负判断
R = np.identity(3)
R[0, 0] = alpha * e_x / np.sqrt(e_x**2 + e_y**2)
R[0, 1] = alpha * e_y / np.sqrt(e_x**2 + e_y**2)
R[1, 0] = -alpha * e_y / np.sqrt(e_x**2 + e_y**2)
R[1, 1] = alpha * e_x / np.sqrt(e_x**2 + e_y**2)
# 矩阵G
f = R.dot(e)[0] # R变换之后,e==>(f,0,1)
G = np.identity(3)
G[2, 0] = -1.0 / f
H2 = np.linalg.inv(T).dot(G.dot(R.dot(T))) # H2 = T^-1 G R T
# ===============================
# 计算H1 , H1 = HaH2M
# 首先计算M
e_p = np.zeros((3, 3))
e_p[0, 1] = - e2[2]
e_p[0, 2] = e2[1]
e_p[1, 0] = e2[2]
e_p[1, 2] = - e2[0]
e_p[2, 0] = - e2[1]
e_p[2, 1] = e2[0] # skew-symmetric 矩阵
v = np.array([1, 1, 1])
M = e_p.dot(F) + np.outer(e2, v) # e2*VT = (3,3)
# 计算Ha
p1_hat = H2.dot(M.dot(points1.T)).T # p1_hat = H2Mp 3 * N,转置之后 N * 3
p2_hat = H2.dot(points2.T).T # pe_hat = H2p' , 3 * N ,转置之后 N * 3
W = p1_hat / p1_hat[:, 2].reshape(-1, 1) # 齐次坐标系
b = (p2_hat / p2_hat[:, 2].reshape(-1, 1))[:, 0]
# 最小二乘问题
a1, a2, a3 = np.linalg.lstsq(W, b, rcond=None)[0]
HA = np.identity(3)
HA[0] = np.array([a1, a2, a3])
H1 = HA.dot(H2).dot(M) # H1 = HaH2M
return H1, H2
三、 主函数
if __name__ == '__main__':
# Read in the data
im_set = 'data/set1'
im1 = imread(im_set+'/image1.jpg')
im2 = imread(im_set+'/image2.jpg')
points1 = get_data_from_txt_file(im_set+'/pt_2D_1.txt')
points2 = get_data_from_txt_file(im_set+'/pt_2D_2.txt')
assert (points1.shape == points2.shape)
F = normalized_eight_point_alg(points1, points2)
e1 = compute_epipole(points1, points2, F)
e2 = compute_epipole(points2, points1, F.transpose())
print("e1", e1)
print("e2", e2)
# Find the homographies needed to rectify the pair of images
H1, H2 = compute_matching_homographies(e2, F, im2, points1, points2)
print("H1:\n", H1)
print
print("H2:\n", H2)
# Transforming the images by the homographies
new_points1 = H1.dot(points1.T)
new_points2 = H2.dot(points2.T)
new_points1 /= new_points1[2,:]
new_points2 /= new_points2[2,:]
new_points1 = new_points1.T
new_points2 = new_points2.T
rectified_im1, offset1 = compute_rectified_image(im1, H1)
rectified_im2, offset2 = compute_rectified_image(im2, H2)
new_points1 -= offset1 + (0,)
new_points2 -= offset2 + (0,)
# Plotting the image
F_new = normalized_eight_point_alg(new_points1, new_points2)
plot_epipolar_lines_on_images(new_points1, new_points2, rectified_im1, rectified_im2, F_new)
plt.show()
四、 结果
e1 [-1.30071143e+03 -1.42448272e+02 1.00000000e+00]
e2 [1.65412463e+03 4.53021078e+01 1.00000000e+00]
H1:
[[-1.20006316e+01 -4.15501447e+00 -1.23476881e+02]
[ 1.41006481e+00 -1.48704147e+01 -2.84177469e+02]
[-9.21889298e-03 -2.19184511e-03 -1.23033440e+01]]
H2:
[[ 8.09798131e-01 -1.22036874e-01 7.99331183e+01]
[-3.00186699e-02 1.01581538e+00 3.63604348e+00]
[-6.99360915e-04 1.05393946e-04 1.15205554e+00]]
调整过后的图片为: