当前位置: 首页 > news >正文

100行Pytorch代码实现三维重建技术神经辐射场 (NeRF)

提起三维重建技术,NeRF是一个绝对绕不过去的名字。这项逆天的技术,一经提出就被众多研究者所重视,对该技术进行深入研究并提出改进已经成为一个热点。不到两年的时间,NeRF及其变种已经成为重建领域的主流。本文通过100行的Pytorch代码实现最初的 NeRF 论文。

NeRF全称为Neural Radiance Fields(神经辐射场),是一项利用多目图像重建三维场景的技术。该项目的作者来自于加州大学伯克利分校,Google研究院,以及加州大学圣地亚哥分校。NeRF使用一组多目图作为输入,通过优化一个潜在连续的体素场景方程来得到一个完整的三维场景。该方法使用一个全连接深度网络来表示场景,使用的输入是一个单连通的5D坐标(空间位置x,y,z以及观察视角θ,),输出为一个体素场景,可以以任意视角查看,并通过体素渲染技术,生成需要视角的照片。该方法同样支持视频合成。

该方法是一个基于体素重建的方法,通过在多幅图片中的五维坐标建立一个由粗到细的对应,进而恢复出原始的三维体素场景。

NeRF 和神经渲染的基本概念

Rendering

渲染是从 3D 模型创建图像的过程。该模型将包含纹理、阴影、阴影、照明和视点等特征,渲染引擎的作用是处理这些特征以创建逼真的图像。

三种常见的渲染算法类型是光栅化,它根据模型中的信息以几何方式投影对象,没有光学效果;光线投射,使用基本的光学反射定律从特定角度计算图像;和光线追踪,它使用蒙特卡罗技术在更短的时间内获得逼真的图像。光线追踪用于提高 NVIDIA GPU 中的渲染性能。

Volume Rendering

立体渲染使能够创建 3D 离散采样数据集的 2D 投影。

对于给定的相机位置,立体渲染算法为空间中的每个体素获取 RGBα(红色、绿色、蓝色和 Alpha 通道),相机光线通过这些体素投射。RGBα 颜色转换为 RGB 颜色并记录在 2D 图像的相应像素中。对每个像素重复该过程,直到呈现整个 2D 图像。

View Synthesis

视图合成与立体渲染相反——它涉从一系列 2D 图像创建 3D 视图。这可以使用一系列从多个角度显示对象的照片来完成,创建对象的半球平面图,并将每个图像放置在对象周围的适当位置。视图合成函数尝试在给定一系列描述对象不同视角的图像的情况下预测深度。

NeRF是如何工作的

NeRF使用一组稀疏的输入视图来优化连续的立体场景函数。这种优化的结果是能够生成复杂场景的新视图。

NeRF使用一组多目图作为输入:

输入为一个单连通的5D坐标(空间位置x,y,z以及观察视角(θ; Φ)

输出为一个体素场景 c = (r; g; b) 和体积密度 (α)。

下面是如何从一个特定的视点生成一个NeRF:

  • 通过移动摄像机光线穿过场景生成一组采样的3D点
  • 将采样点及其相应的2D观察方向输入神经网络,生成密度和颜色的输出集
  • 通过使用经典的立体渲染技术,将密度和颜色累积到2D图像中

上述过程深度的全连接、多层感知器(MLP)进行优化,并且不需要使用卷积层。它使用梯度下降来最小化每个观察到的图像和从表示中呈现的所有相应视图之间的误差。

Pytorch代码实现

渲染

神经辐射场的一个关键组件,是一个可微分渲染,它将由NeRF模型表示的3D表示映射到2D图像。该问题可以表述为一个简单的重构问题

这里的A是可微渲染,x是NeRF模型,b是目标2D图像。

代码如下:

 defrender_rays(nerf_model, ray_origins, ray_directions, hn=0, hf=0.5, nb_bins=192):device=ray_origins.devicet=torch.linspace(hn, hf, nb_bins, device=device).expand(ray_origins.shape[0], nb_bins)# Perturb sampling along each ray.mid= (t[:, :-1] +t[:, 1:]) /2.lower=torch.cat((t[:, :1], mid), -1)upper=torch.cat((mid, t[:, -1:]), -1)u=torch.rand(t.shape, device=device)t=lower+ (upper-lower) *u  # [batch_size, nb_bins]delta=torch.cat((t[:, 1:] -t[:, :-1], torch.tensor([1e10], device=device).expand(ray_origins.shape[0], 1)), -1)x=ray_origins.unsqueeze(1) +t.unsqueeze(2) *ray_directions.unsqueeze(1)   # [batch_size, nb_bins, 3]ray_directions=ray_directions.expand(nb_bins, ray_directions.shape[0], 3).transpose(0, 1)colors, sigma=nerf_model(x.reshape(-1, 3), ray_directions.reshape(-1, 3))colors=colors.reshape(x.shape)sigma=sigma.reshape(x.shape[:-1])alpha=1-torch.exp(-sigma*delta)  # [batch_size, nb_bins]weights=compute_accumulated_transmittance(1-alpha).unsqueeze(2) *alpha.unsqueeze(2)c= (weights*colors).sum(dim=1)  # Pixel valuesweight_sum=weights.sum(-1).sum(-1)  # Regularization for white backgroundreturnc+1-weight_sum.unsqueeze(-1)

渲染将NeRF模型和来自相机的一些光线作为输入,并使用立体渲染返回与每个光线相关的颜色。

代码的初始部分使用分层采样沿射线选择3D点。然后在这些点上查询神经辐射场模型(连同射线方向)以获得密度和颜色信息。模型的输出可以用蒙特卡罗积分计算每条射线的线积分。

累积透射率(论文中Ti)用下面的专用函数中单独计算。

 defcompute_accumulated_transmittance(alphas):accumulated_transmittance=torch.cumprod(alphas, 1)returntorch.cat((torch.ones((accumulated_transmittance.shape[0], 1), device=alphas.device),accumulated_transmittance[:, :-1]), dim=-1)

NeRF

我们已经有了一个可以从3D模型生成2D图像的可微分模拟器,下面就是实现NeRF模型。

根据上面的介绍,NeRF非常的复杂,但实际上NeRF模型只是多层感知器(MLPs)。但是具有ReLU激活函数的mlp倾向于学习低频信号。当试图用高频特征建模物体和场景时,这就出现了一个问题。为了抵消这种偏差并允许模型学习高频信号,使用位置编码将神经网络的输入映射到高维空间。

 classNerfModel(nn.Module):def__init__(self, embedding_dim_pos=10, embedding_dim_direction=4, hidden_dim=128):super(NerfModel, self).__init__()self.block1=nn.Sequential(nn.Linear(embedding_dim_pos*6+3, hidden_dim), nn.ReLU(),nn.Linear(hidden_dim, hidden_dim), nn.ReLU(),nn.Linear(hidden_dim, hidden_dim), nn.ReLU(),nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), )self.block2=nn.Sequential(nn.Linear(embedding_dim_pos*6+hidden_dim+3, hidden_dim), nn.ReLU(),nn.Linear(hidden_dim, hidden_dim), nn.ReLU(),nn.Linear(hidden_dim, hidden_dim), nn.ReLU(),nn.Linear(hidden_dim, hidden_dim+1), )self.block3=nn.Sequential(nn.Linear(embedding_dim_direction*6+hidden_dim+3, hidden_dim//2), nn.ReLU(), )self.block4=nn.Sequential(nn.Linear(hidden_dim//2, 3), nn.Sigmoid(), )self.embedding_dim_pos=embedding_dim_posself.embedding_dim_direction=embedding_dim_directionself.relu=nn.ReLU()@staticmethoddefpositional_encoding(x, L):out= [x]forjinrange(L):out.append(torch.sin(2**j*x))out.append(torch.cos(2**j*x))returntorch.cat(out, dim=1)defforward(self, o, d):emb_x=self.positional_encoding(o, self.embedding_dim_pos)emb_d=self.positional_encoding(d, self.embedding_dim_direction)h=self.block1(emb_x)tmp=self.block2(torch.cat((h, emb_x), dim=1))h, sigma=tmp[:, :-1], self.relu(tmp[:, -1])h=self.block3(torch.cat((h, emb_d), dim=1))c=self.block4(h)returnc, sigma

训练

训练循环也很简单,因为它也是监督学习。我们可以直接最小化预测颜色和实际颜色之间的L2损失。

 deftrain(nerf_model, optimizer, scheduler, data_loader, device='cpu', hn=0, hf=1, nb_epochs=int(1e5),nb_bins=192, H=400, W=400):training_loss= []for_intqdm(range(nb_epochs)):forbatchindata_loader:ray_origins=batch[:, :3].to(device)ray_directions=batch[:, 3:6].to(device)ground_truth_px_values=batch[:, 6:].to(device)regenerated_px_values=render_rays(nerf_model, ray_origins, ray_directions, hn=hn, hf=hf, nb_bins=nb_bins)loss= ((ground_truth_px_values-regenerated_px_values) **2).sum()optimizer.zero_grad()loss.backward()optimizer.step()training_loss.append(loss.item())scheduler.step()forimg_indexinrange(200):test(hn, hf, testing_dataset, img_index=img_index, nb_bins=nb_bins, H=H, W=W)returntraining_loss

测试

训练过程完成,NeRF模型就可以用于从任何角度生成图像。测试函数通过使用来自测试图像的射线数据集进行操作,然后使用渲染函数和优化的NeRF模型为这些射线生成图像。

 @torch.no_grad()deftest(hn, hf, dataset, chunk_size=10, img_index=0, nb_bins=192, H=400, W=400):ray_origins=dataset[img_index*H*W: (img_index+1) *H*W, :3]ray_directions=dataset[img_index*H*W: (img_index+1) *H*W, 3:6]data= []foriinrange(int(np.ceil(H/chunk_size))):ray_origins_=ray_origins[i*W*chunk_size: (i+1) *W*chunk_size].to(device)ray_directions_=ray_directions[i*W*chunk_size: (i+1) *W*chunk_size].to(device)regenerated_px_values=render_rays(model, ray_origins_, ray_directions_, hn=hn, hf=hf, nb_bins=nb_bins)data.append(regenerated_px_values)img=torch.cat(data).data.cpu().numpy().reshape(H, W, 3)plt.figure()plt.imshow(img)plt.savefig(f'novel_views/img_{img_index}.png', bbox_inches='tight')plt.close()

所有的部分都可以很容易地组合起来。

 if__name__=='main':device='cuda'training_dataset=torch.from_numpy(np.load('training_data.pkl', allow_pickle=True))testing_dataset=torch.from_numpy(np.load('testing_data.pkl', allow_pickle=True))model=NerfModel(hidden_dim=256).to(device)model_optimizer=torch.optim.Adam(model.parameters(), lr=5e-4)scheduler=torch.optim.lr_scheduler.MultiStepLR(model_optimizer, milestones=[2, 4, 8], gamma=0.5)data_loader=DataLoader(training_dataset, batch_size=1024, shuffle=True)train(model, model_optimizer, scheduler, data_loader, nb_epochs=16, device=device, hn=2, hf=6, nb_bins=192, H=400,W=400)

这样一个简单的NeRF就完成了,看看效果:

希望本文对你有所帮助,如果你对NeRF感兴趣可以看看这个项目:

https://avoid.overfit.cn/post/3d89b7ed625b437993e3fde57f36c70a

相关文章:

100行Pytorch代码实现三维重建技术神经辐射场 (NeRF)

提起三维重建技术,NeRF是一个绝对绕不过去的名字。这项逆天的技术,一经提出就被众多研究者所重视,对该技术进行深入研究并提出改进已经成为一个热点。不到两年的时间,NeRF及其变种已经成为重建领域的主流。本文通过100行的Pytorch…...

linux操作系统篇

目录 操作系统概述基本特征并发共享虚拟异步进程管理内存管理文件管理设备管理宏内核和微内核宏内核微内核中断分类外中断异常陷入(系统调用)进程管理进程与线程的区别进程状态切换进程调度算法**批处理系统****交互式系统**进程同步临界...

redis+token实现登录校验,前后端分离,及解跨域问题的4种方法

目录 一、使用自定义filter实现跨域 1、客户端向服务端发送请求 2、服务端做登录验证了,并生成登路用户对应的token,保存到redis 3、响应(报错)-----跨域问题 4、解决跨域问题--------服务器端添加过滤器,设置请求…...

怎么解密MD5,常见的MD5解密方法,一看就会

MD5是一种被广泛使用的密码散列函数,曾在计算机安全领域使用很广泛,但是也因为它容易发生碰撞,而被人们认为不安全。那么,MD5应用场景有哪些,我们怎么解密MD5,本文将带大家了解MD5的相关知识,以…...

Vue3 目录结构

Vue3 目录结构 架构搭建 请确保你的电脑上成功安装 Node.js,本项目使用 Vite 构建工具,需要 Node.js 版本 > 12.0.0。 查看 Node.js 版本: node -v建议将 Node.js 升级到最新的稳定版本: 使用 nvm 安装最新稳定版 Node.js…...

Tsp_nurrec表空间满处理记录20230215

Tsp_nurrec表空间满处理记录20230215 一、问题: 问题:护理病历表空间不足。 二、解决过程:1.查询表空间使用效率 SELECT UPPER(F.TABLESPACE_NAME) “表空间名”, D.TOT_GROOTTE_MB "表空间大小(M)",D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)"…...

影像测量设备都有什么?有哪些影像仪器?

影像测量仪器是广泛应用于机械、电子、仪表的仪器。主要由机械主体、标尺系统、影像探测系统、驱动控制系统和测量软件等与高精密工作台结构组成的光电测量仪器。一般分为三大类:手动影像仪、自动影像仪和闪测影像仪。测量元素主要有:长度、宽度、高度、…...

Transformer:开启CV研究新时代

来源:投稿 作者:魔峥 编辑:学姐 起源回顾 有关Attention的论文早在上世纪九十年代就提出了。 在2012年后的深度学习时代,Attention再次被翻了出来,被用在自然语言处理任务,提高RNN模型的训练速度。但是由…...

Flink X Hologres构建企业级Streaming Warehouse

摘要:本文整理自阿里云资深技术专家,阿里云Hologres负责人姜伟华,在FFA实时湖仓专场的分享。点击查看>>本篇内容主要分为四个部分: 一、实时数仓分层的技术需求 二、阿里云一站式实时数仓Hologres介绍 三、Flink x Hologres…...

关于 mysql数据库插入中文变空白 的解决方法

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/129048030 红胖子网络科技的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…...

不可错过的SQL优化干货分享-sql优化、索引使用

本文是向大家介绍在sql调优的几个操作步骤,它能够在日常遇到慢sql时有分析优化思路,能够让开发者更好的了解sql执行的顺序和原理。一、前言在日常开发中,我们经常遇到一些数据库相关的问题,比方说:SQL已经走了索引了&a…...

vue3:直接修改reative的值,页面却不响应,这是什么情况?

目录 前言 错误示范: 解决办法: 1.使用ref 2.reative多套一层 3.使用Object.assign 前言: 今天看到有人在提问,问题是这样的,我修改了reative的值,数据居然失去了响应性,页面毫无变化&…...

从Vue2 到 Vue3,这些路由差异你需要掌握!

✨ 个人主页:山山而川~xyj ⚶ 作者简介:前端领域新星创作者,专注于前端各领域技术,共同学习共同进步,一起加油! 🎆 系列专栏: vue系列 🚀 学习格言:与其临渊羡…...

Maxwell简介、部署、原理和使用介绍

Maxwell简介、部署、原理和使用介绍 1.Maxwell概述简介 1-1.Maxwell简介 ​ Maxwell是由美国Zendesk公司开源,使用Java编写的MySQL变更数据抓取软件。他会实时监控Mysql数据库的数据变更操作(包括insert、update、delete),并将变…...

20230215_数据库过程_渠道业务清算过程

----2023-0131-清算过程 zhyw.shc_drop_retable(upper(‘xc_qdcn_pgtx_qsqdtype_sja’),‘SHZC’); SQL_STRING:‘create table shzc.xc_qdcn_pgtx_qsqdtype_sja as select * from shzc.xc_qdcn_pgtx_qdtype a where a.in_time ( select max(a.in_time) from shzc.xc_qdcn_pg…...

webpack(高级)--性能优化-代码分离

webpack webpack性能优化 优化一:打包后的结果 上线时的性能优化 (比如分包处理 减少包体积 CDN服务器) 优化二:优化打包速度 开发或者构建优化打包速度 (比如exclude cache-loader等) 大多数情况下我们侧…...

借助docker, 使用verdaccio搭建npm私服

为何要搭建npm私服 搭建npm私服好处多多,网上随便一篇教程搜出来都罗列了诸多好处,譬如: 公司内部开发环境与外网隔离,内部开发的一些库高度隐私不便外传,内网搭建npm服务保证私密性同属内网,可以确保使用npm下载依赖…...

c/c++开发,无可避免的模板编程实践(篇二)

一、开发者需要对模板参数负责 1.1 为您模板参数提供匹配的操作 在进行模板设计时,函数模板或类模板一般只做模板参数(typename T)无关的操作为主,但是也不见得就不会关联模板参数自身的操作,尤其是在一些自定义的数据…...

【2023】【standard-products项目】中查找的问题与解决方案 (未完待续)

10、el-table 判断是多选操作还是单选操作 9、判断数组对象中是否包含某个指定值 需求:修改时数据回填el-select下拉数据,发现当前id在原数组里没有找到,就显示了id值,应该显示name名, 处理:当查找到id…...

力扣sql简单篇练习(十六)

力扣sql简单篇练习(十六) 1 产品销售分析|| 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 SELECT p.product_id,sum(s.quantity) total_quantity FROM Product p INNER JOIN Sales s ON p.product_ids.product_id GROUP BY p.product_id1.3 运行截…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...

在rocky linux 9.5上在线安装 docker

前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...

Ubuntu系统多网卡多相机IP设置方法

目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...

书籍“之“字形打印矩阵(8)0609

题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...