paper:NeRF−−: Neural Radiance Fields Without Known Camera Parameters
如何优化Pose
pose:相机转世界坐标系的变换矩阵T = [R|t]
, 可直接优化平移向量t
,因为它是定义在SE(3)欧式空间(x,y,z)上; 而代表相机旋转的R
并不是在欧式空间上,而用旋转轴和角表示的(类似球坐标系,极坐标系?),所以要优化R,首先把旋转角度转换为旋转矩阵,这里是利用经典的Rodrigues公式
参考链接:SO(3),SE(3)基础;Rodrigues公式
code
1.先看make_c2w(r, t)
输入的是(3,) 的轴角(axis-angle)向量,首先利用函数 Exp(r)
是将一个 so(3) 空间的向量转换为 SO(3) 空间的旋转矩阵。
2.r—>R: 调用 vec2skew(r)
将轴角向量转换为一个 (3, 3) 的斜对称矩阵(skew-symmetric matrix),计算轴角向量的模长 norm_r,并创建一个 (3, 3) 的单位矩阵 eye,用于表示 SO(3) 空间中的恒等变换,最后旋转矩阵由Rodrigues公式计算
def SO3_to_quat(R):
"""
:param R: (N, 3, 3) or (3, 3) np
:return: (N, 4, ) or (4, ) np
"""
x = RotLib.from_matrix(R)
quat = x.as_quat()
return quat
def quat_to_SO3(quat):
"""
:param quat: (N, 4, ) or (4, ) np
:return: (N, 3, 3) or (3, 3) np
"""
x = RotLib.from_quat(quat)
R = x.as_matrix()
return R
def convert3x4_4x4(input):
"""
:param input: (N, 3, 4) or (3, 4) torch or np
:return: (N, 4, 4) or (4, 4) torch or np
"""
if torch.is_tensor(input):
if len(input.shape) == 3:
output = torch.cat([input, torch.zeros_like(input[:, 0:1])], dim=1) # (N, 4, 4)
output[:, 3, 3] = 1.0
else:
output = torch.cat([input, torch.tensor([[0,0,0,1]], dtype=input.dtype, device=input.device)], dim=0) # (4, 4)
else:
if len(input.shape) == 3:
output = np.concatenate([input, np.zeros_like(input[:, 0:1])], axis=1) # (N, 4, 4)
output[:, 3, 3] = 1.0
else:
output = np.concatenate([input, np.array([[0,0,0,1]], dtype=input.dtype)], axis=0) # (4, 4)
output[3, 3] = 1.0
return output
def vec2skew(v):
"""
:param v: (3, ) torch tensor
:return: (3, 3)
"""
zero = torch.zeros(1, dtype=torch.float32, device=v.device)
skew_v0 = torch.cat([ zero, -v[2:3], v[1:2]]) # (3, 1)
skew_v1 = torch.cat([ v[2:3], zero, -v[0:1]])
skew_v2 = torch.cat([-v[1:2], v[0:1], zero])
skew_v = torch.stack([skew_v0, skew_v1, skew_v2], dim=0) # (3, 3)
return skew_v # (3, 3)
def Exp(r):
"""so(3) vector to SO(3) matrix
:param r: (3, ) axis-angle, torch tensor
:return: (3, 3)
"""
skew_r = vec2skew(r) # (3, 3)
norm_r = r.norm() + 1e-15
eye = torch.eye(3, dtype=torch.float32, device=r.device)
R = eye + (torch.sin(norm_r) / norm_r) * skew_r + ((1 - torch.cos(norm_r)) / norm_r**2) * (skew_r @ skew_r)#Rodrigues公式
return R
def make_c2w(r, t):
"""
:param r: (3, ) axis-angle torch tensor
:param t: (3, ) translation vector torch tensor
:return: (4, 4)
"""
R = Exp(r) # (3, 3)
c2w = torch.cat([R, t.unsqueeze(1)], dim=1) # (3, 4)
c2w = convert3x4_4x4(c2w) # (4, 4)
return c2w