NeRF 源码分析解读(三)

这篇具有很好参考价值的文章主要介绍了NeRF 源码分析解读(三)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

NeRF 源码分析解读(三)

光线的生成

上一章节我们对 NeRF 模型的初始化代码进行了分析,即 create_nerf() 部分,本章节我们继续对 NeRF 代码进行分析注释。
我们回顾一下前两节的内容:

def train():
	
	# 1、加载数据
	if args.dataset_type == 'llff':
	elif ...
	...

	# 2、初始化网络模型
	render_kwargs_train, render_kwargs_test, start, grad_vars, optimizer = create_nerf(args)
	...
	
	if args.render_only: ...

初始化网络模型之后我们继续向下分析代码,会发现一个渲染操作的判断 if args.render_only 。在网络模型训练好以后我们保存整个网络,在测试渲染时只需要将 render_only 参数置 True,不再对网络进行训练,直接得到渲染结果。核心代码在于渲染函数,我们先不对这一块儿代码进行分析,按照训练的流程,在初始化光线以后需要渲染得到像素值,因此我们对渲染函数的分析留在光线生成之后。我们继续向下分析代码。
下面的代码会涉及到光线的生成部分,比较重要

def train():

	...
	
	# 开始读取光线以及光线对应的像素值
	N_rand = args.N_rand
	# 是否以批处理的形式生成光线
    use_batching = not args.no_batching
    if use_batching:
    	...

use_batching 参数决定了是否从多个角度进行光线投射。源代码中对 lego 小车重建时参数为 False,这里我们为了读者能够更好的理解,同样对这部分代码进行解析。

def train():

	...
	
    if use_batching:
        print('get rays')
        rays = np.stack([get_rays_np(H, W, K, p) for p in poses[:,:3,:4]], 0) # [N, ro+rd, H, W, 3]
        print('done, concats')
        rays_rgb = np.concatenate([rays, images[:, None]], 1)  # [N, ro+rd+rgb, H, W, 3]  这里把光线的原点、方向、以及这条光线对应的像素颜色结合到一起,便于后面的 shuffle 操作
        rays_rgb = np.transpose(rays_rgb, [0,2,3,1,4])  # [N, H, W, ro+rd+rgb, 3]
        rays_rgb = np.stack([rays_rgb[i] for i in i_train], 0)  # train images only
        rays_rgb = np.reshape(rays_rgb, [-1,3,3])  # [(N-1)*H*W, ro+rd+rgb, 3]
        rays_rgb = rays_rgb.astype(np.float32)
        print('shuffle rays')
        np.random.shuffle(rays_rgb)

        print('done')
        i_batch = 0

我们可以看到,这段代码的核心在于 get_rays_np() 函数,其他的操作都是一些数据的变换,因此我们对 get_rays_np() 函数进行代码分析。

def get_rays_np(H, W, K, c2w):
    i, j = np.meshgrid(np.arange(W, dtype=np.float32), np.arange(H, dtype=np.float32), indexing='xy')
    dirs = np.stack([(i-K[0][2])/K[0][0], -(j-K[1][2])/K[1][1], -np.ones_like(i)], -1)
    # Rotate ray directions from camera frame to the world frame
    rays_d = np.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 = np.broadcast_to(c2w[:3,-1], np.shape(rays_d))
    return rays_o, rays_d

np.meshgrid(a, b,indexing = "xy") 函数会返回 b.shape() 行 ,a.shape() 列的二维数组。因此 i, j 都是 [H, W] 的二维数组。i 的每一行代表 x 轴坐标,j 的每一行代表 y 轴坐标。如此一来我们的到了一个图片的每个像素点的笛卡尔坐标。
我们回到第二节提到的相机内参 K

K = np.array([
           [focal, 0, 0.5*W],
           [0, focal, 0.5*H],
           [0, 0, 1]

我们利用相机内参 K 计算每个像素坐标相对于光心的单位方向:

dirs = np.stack([(i-K[0][2])/K[0][0], -(j-K[1][2])/K[1][1], -np.ones_like(i)], -1)

我们对计算公式进行分析。如下图所示,在相机坐标系下根据小孔成像原理求解像素平面上一点到相机光心的方向:
NeRF 源码分析解读(三)

如图,空间中一点 P 经过光心 O (小孔)在成像平面上呈一点 P’ ,并且呈一个倒立的像。我们以光心所在的面建立相机坐标系,那么光心所在的位置可以表示为 ( W 2 , H 2 , 0 ) (\frac{W}{2} ,\frac{H}{2}, 0 ) (2W,2H,0) ,成像点 P’ 的位置可以表示为 ( i , j , − f ) (i ,j,-f) (i,j,f)
由此两点位置,我们可以确定一个方向向量 O P ′ → = ( i − W 2 , j − H 2 , − f ) \overrightarrow{OP'} = (i - \frac{W}{2}, j - \frac{H}{2}, -f) OP =(i2W,j2H,f) 。由于小孔成像呈一个倒立的像,因此我们对 O P ′ → \overrightarrow{OP'} OP 的 Y 轴坐标取反,并对 O P ′ → \overrightarrow{OP'} OP 的 Z 轴归一化。我们得到一个新的方向向量: ( ( i − W 2 ) / f , − ( j − H 2 ) / f , − 1 ) ((i - \frac{W}{2})/f, -(j - \frac{H}{2})/f, -1) ((i2W)/f,(j2H)/f,1)
由此公式我们得到每个像素点关于光心 O 的方向 dirs 。随后我们利用相机外参转置矩阵将相机坐标转换为世界坐标。

rays_d = np.sum(dirs[..., np.newaxis, :] * c2w[:3,:3], -1)

事实上 get_rays() 函数与 get_rays_np() 函数基本是一致的,只不过是 torch.meshgrid(a, b) 返回的是 a.shape() 行 ,b.shape() 列的二维数组。因此需要一个转置操作 i.t() ,其余步骤相同。
至此我们生成了每个方向下的像素点到光心的单位方向(Z 轴为 1)。我们有了这个单位方向就可以通过调整 Z 轴坐标生成空间中每一个点坐标,借此模拟一条光线。
光线生成步骤基本结束,后续我们开始分析训练步骤中关于批处理光线以及空间中位置生成的部分 NeRF 源码分析解读(四)。文章来源地址https://www.toymoban.com/news/detail-447687.html

到了这里,关于NeRF 源码分析解读(三)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flink 深入理解任务执行计划,即Graph生成过程(源码解读)

    我们先看一下,Flink 是如何描述作业的执行计划的。以这个 DataStream 作业为例,Flink 会基于它先生成一个 StreamGraph。这是一个有向无环图,图中的节点对应着计算逻辑,图中的边则对应着数据的分发方式。 Flink 会根据节点的并行度以及他们之间的连边方式,把一些计算节点进

    2024年02月22日
    浏览(45)
  • Spring Boot源码解读与原理分析

      最近机缘巧合之下,读到了 LinkedBear 编写的《Spring Boot源码解读与原理分析》这本书,本人花了一周的时间认真研读了一下这本书,真的是受益匪浅,特此推荐给大家,好书不容错过啊。 LinkedBear 是一名资深的Java开发工程师,常年致力于底层技术的研究,同时也通过技术

    2024年02月08日
    浏览(46)
  • 《Spring Boot源码解读与原理分析》书籍推荐

    Spring Boot 1.0.0 早在2014年就已经发布,只不过到了提倡“降本增效”的今天,Spring Boot才引起了越来越多企业的关注。Spring Boot是目前Java EE开发中颇受欢迎的框架之一。依托于底层Spring Framework的基础支撑,以及完善强大的特性设计,Spring Boot已成为业界流行的应用和微服务开发

    2024年02月14日
    浏览(37)
  • Diffusion Models可控视频生成Control-A-Video:论文和源码解读

    Diffusion Models专栏文章汇总:入门与实战 前言: Diffusion视频生成的时间连贯性问题是可控视频生成问题最大的挑战。Control-A-Video提出的时空一致性建模法、残差噪声初始化法和首帧定型法能有效解决这一问题,非常值得我们借鉴。博主详细解读论文和代码,并给出一些自己的

    2024年02月06日
    浏览(45)
  • 【论文解读】基于神经辐射场NeRF的像素级交互式编辑(Seal-3D)

    来源:投稿 作者:橡皮 编辑:学姐 论文链接:https://arxiv.org/pdf/2307.15131 项目主页:https://windingwind.github.io/seal-3d/ 随着隐式神经表征或神经辐射场(NeRF)的普及,人们迫切需要与隐式三维模型交互的编辑方法,以完成重建场景的后期处理和三维内容创建等任务。虽然以前的作

    2024年02月03日
    浏览(46)
  • SpringBoot源码解读与原理分析(五)SpringBoot的装配机制

    前面三小节分别介绍了Spring Framewoek的模块装配、条件装配和SPI机制。下面正式进入Spring Boot的装配机制。 实际上, Spring Boot的自动装配是模块装配+条件装配+SPI机制的组合使用 ,而这一切都凝聚在Spring Boot主启动类的@SpringBootApplication注解上。 @SpringBootApplication注解是由三个注

    2024年02月19日
    浏览(50)
  • SpringBoot源码解读与原理分析(二十七)嵌入式Tomcat

    当Web应用需要部署运行时,传统的做法是将项目打包成war包,然后部署到外置的Web容器中(如最常用的Tomcat容器)。 SpringBoot的一大重要特性是支持嵌入式Web容器,基于SpringBoot的Web应用仅凭一个单独的jar包即可独立运行。 8.1.1 嵌入式Tomcat与普通Tomcat 嵌入式Tomcat是一种可以嵌

    2024年02月22日
    浏览(50)
  • SpringBoot源码解读与原理分析(六)WebMvc场景的自动装配

    了解了SpringBoot的自动装配机制之后,研究一个常见且实用的场景:当项目整合SpringWebMvc后SpringBoot的自动装配都做了什么? 2.6.1 WebMvcAutoConfiguration 引入spring-boot-starter-web依赖后,SpringBoot会进行WebMvc的自动装配,处理的核心是一个叫WebMvcAutoConfiguration的自动配置类。 由以上源码

    2024年02月21日
    浏览(51)
  • 伪随机生成器(rand函数),随机数种子(srand函数)详细解读与分析:

    a.生成随机数; b.生成0~100以内的随机数 c.随机数的连续输出及其连续输出情况讲解与分析 首先我们来看一下rand函数(伪随机数生成器):   rand函数,即伪随机数生成器,该函数返回类型为整型,没有参数,即产生一个在(0-rand_max(十六进制的ox7ffff转化为整数即32767)的一个

    2024年02月11日
    浏览(52)
  • Java进阶(HashMap)——面试时HashMap常见问题解读 & 结合源码分析

    List、Set、HashMap作为Java中常用的集合,需要深入认识其原理和特性。 本篇博客介绍常见的关于Java中HashMap集合的面试问题,结合源码分析题目背后的知识点。 关于List的博客文章如下: Java进阶(List)——面试时List常见问题解读 结合源码分析 关于的Set的博客文章如下: Jav

    2024年02月08日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包