nerf说:一条光线上所有位置上的颜色和密度的合成,就是成像图上的像素RGB值; 我们来看看这条光线怎么表示? 以及怎么在光线上取一些点?
光线是一条空间直线,准确的说是一条空间射线,定义公式如下:
- 起点坐标 o:相机中心点。
- 方向向量 d:从相机中心点出发,到图像某个像素坐标的向量,由两点坐标相减就得到。
- t:光线上的点到起点的水平距离。 t取不同的值就是光线上不同的采样点。
- 400x400的图像可以生成160000条光线。
P是空间直线上一点,S是方向向量,有如图的三种表示法
进一步证明:因为Nerf的t取得是z轴距离,而不是光线的距离;而且只有中心光线方向是单位向量。
- t=|z|:光线上的点到起点(相机中心)的距离。 t取不同的值就是光线上不同的采样点。nerf默认取61个点,60段。
- r(t):光线上点的三维坐标xyz;
- d:光线方向向量,也是三个值;中心光线向量是单位向量。
- 先看代码
#计算光线的起点和方向向量 def get_rays(H, W, K, c2w): i, j = torch.meshgrid(torch.linspace(0, W-1, W), torch.linspace(0, H-1, H)) i = i.t() j = j.t() dirs = torch.stack([(i-K[0][2])/K[0][0], -(j-K[1][2])/K[1][1], -torch.ones_like(i)], -1) rays_d = torch.sum(dirs[..., np.newaxis, :] * c2w[:3,:3], -1) rays_o = c2w[:3,-1].expand(rays_d.shape) return rays_o, rays_d
#计算光线采样 z_vals = tf.linspace(near, far, N_samples) pts = rays_o[...,None,:] + rays_d[...,None,:] * z_vals[...,:,None]
- 代码阅读
- dirs是相机坐标系下的光线方向。
- rays_d是世界坐标系下的光线方向,为什么用点乘+求和:因为输入是行向量(python没有一维列向量)不能直接像列向量那样用矩阵乘法。
- rays_o是世界坐标系下的光线起点。
- 代码分析:
- c2w:相机坐标系到世界坐标系的转换:只包含旋转和位移。
- 证明表示,中心光线方向向量d需要是单位向量,而且nerf使用的是右手三维坐标系,所以nerf取-1代码如下: -torch.ones_like(i)
- 方向是向量:整体位移方向还是不变,所以只需要旋转, 所以只需乘旋转矩阵R=c2w[:3,:3]。
- 光心是原点:(0,0,0)怎么旋转都在原地,所以只需要位移, 所以只需乘位移矩阵T=c2w[:3,-1]。