目录
论文地址:https://dl.acm.org/doi/pdf/10.1145/3503250
代码地址:https://github.com/yenchenlin/nerf-pytorch
不同视角的图片怎么输入到NeRF中的神经网络中,也即是图片怎么转换为论文中提到的5D向量,我们将这部分看为模型的预处理部分;其次,论文中还提到了低纬向量输入到模型中,细节信息会丢失,因此预处理部分还包括了将5D低纬信息扩展到高维信息,即位置编码。
因此,预处理过程包括:图片转5D向量+位置编码
1、预处理部分
1.1 图像数据转5D向量
论文中提到的5D向量,具体解释为空间中的位姿。其中,非常好理解,就是物体在三维空间中的具体坐标;分别为俯仰角和偏航角,这里指观测角度。这里的位姿是粒子的位姿,也就是说整个模型的输入是粒子的5D位姿。
1.1.1 NeRF中粒子理解
以相机位置为原点,观测角度为行进方向找一条射线,抽象为数学公式为:
其中为距离。粒子就是通过对射线进行采样得到的。
1.1.2 射线代码理解
def get_rays(H, W, K, c2w):
i, j = torch.meshgrid(torch.linspace(0, W-1, W), torch.linspace(0, H-1, H)) # pytorch's meshgrid has indexing='ij'
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)
# Rotate ray directions from camera frame to the world frame
rays_d = torch.sum(dirs[..., np.newaxis, :] * c2w[:3,:3], -1) # dot product, equals to: [c2w.dot(dir) for dir in dirs]
# Translate camera frame's origin to the world frame. It is the origin of all rays.
rays_o = c2w[:3,-1].expand(rays_d.shape)
return rays_o, rays_d
从上面的理解我们可以知道每个像素对应一条像素,那么一张图像总共产生条射线。那么首先产生这么多的射线,也就是代码的第一行:
产生每个像素的坐标,我们假设图像宽和高都为400:
这样和表示这个像素坐标系下任意一个像素坐标。
下面这行代码表示,像素坐标系转换到相机坐标系中过程:
dirs = torch.stack([(i-K[0][2])/K[0][0], -(j-K[1][2])/K[1][1], -torch.ones_like(i)], -1)
下面通过相机坐标系转世界坐标系得到物体实际的3维空间坐标以及相机原点。这样每个像素对应的射线就全部产生了。具体公式见【NeRF系列文章一】预备知识-CSDN博客
1.1.3 对射线上粒子进行采样
对于全部射线,我们只需要采样一部分就可以,代码中设置的是1024。也可以理解为对于一张图片进行像素采样,采样点为1024个像素。
对于随机采样得到的射线,在对这些射线进行采样得到粒子,论文中给到的是
代码中设置的是near=2,far=6,均匀采样64点。
那么最终输入模型为[1024,64,3]
1.2 位置编码
因为我们给模型输入数据的维度为5维,包括位置和姿态,但是姿态一般也使用三维坐标表示,因此实际输入模型为6维数据。但是低纬度数据输入到模型后,不能有效学习到高频信息,需要将其添加其他维度信息,进行升高维度,位置编码就是干这一件事情的。
论文中在位置处将L设置为10,因此维度变为了3*20=60。
在姿态处将L设置为4,因此维度变为了3*8=24。
说明:L=10时候,因为每一对都会有sin和cos两个信息,因此会变为20。