nerf论文代码理解

news/2024/9/19 0:53:19/ 标签: 人工智能

        近年来,生成式AI(AGI)快速发展,各类生成式模型层出不群,但我更觉得具有物理意义的生成式AI将是未来革命性技术。因此也在抽空看看关于三维重建的知识,这篇文章就是记录我对nerf的理解。

一、论文理解

        首先,需要知道nerf的输入和输出是什么?

        做cv的朋友都肯定会觉得输入必然是图像,其实图像的输入只是为了后续的loss监督使用,网络的输入是5D向量,包含空间位置xyz和角度theta和phi。

        (1)是什么的空间位置xyz和角度theta和phi?

        粒子,nerf假设空间中的粒子是自发光的,所以图像的渲染是通过这些自发光粒子得到的。

        (2)网络的结构是什么样?

       (3)怎样得到这些粒子?

        根据像素位置转换到归一化相机坐标系,然后再转换到统一的世界坐标系,沿着射线在2~6的范围内均匀采样64个点作为粒子。世界坐标系的转换矩阵,也就是pose是通过SFM(运动结构恢复)得到的(经典的方法是COLMAP)

        (4e)xyz是怎么变为63维的? 

        通过傅里叶级数将输入的xyz变为高频信号,就像transfomer里面的位置编码一样。这样做的好处是能够区别像素间的差异,对于空间重建比较重要,相邻的两个像素,在空间中的距离也可能距离很大。论文中设的embedding的维度是10,所以10*2*3+3=63。其中2表示sin和cos,3是xyz。

        (5)在第5层为什么要加入原始信息?

        为了保持更为准确的空间位置。

        (6)输出的theta是什么?

        在对应的粒子采样点处光线被粒子阻碍的概率密度。

        (7)视角的输入维度为什么是3,又怎么变为27?

        实际网络的输入是向量,是单位向量表示方向。embedding的维度是4,所以3*2*4+3=27.

        (8)为什么视角输入只是在最后加入?

        概率密度只和位置相关,颜色和视角相关。

        (9)最后怎么样渲染得到图像?

        体渲染技术。

        (10)nerf的核心是什么?

        前处理得到网络输入,后处理体渲染技术,分层采样。

        (11)分层采样指的是?

        nerf的模型包括corse模型和fine模型,corse模型的采样是(2)中的均匀等距采样,fine模型会根据corse模型输出的weight,采样逆变换采样的方式重新采样得到128个粒子,使得采样更加关注空间中不为空的区域,128+64=192个粒子作为fine模型的输入。

        (12)还有其他细节嘛?

        为了节省显存,不会整张图对应的射线粒子都会一股脑进入网络,会随机采样1024个像素对应的射线粒子进入网络。

二、代码理解。

获取输入粒子的坐标和方向主要关注以下代码。

    def initialize(self):warange = torch.arange(self.width,  dtype=torch.float32, device=self.device)harange = torch.arange(self.height, dtype=torch.float32, device=self.device)y, x = torch.meshgrid(harange, warange)self.transformed_x = (x - self.width * 0.5) / self.focalself.transformed_y = (y - self.height * 0.5) / self.focal #normailization coord# pre center cropself.precrop_index = torch.arange(self.width * self.height).view(self.height, self.width)dH = int(self.height // 2 * self.precrop_frac)dW = int(self.width  // 2 * self.precrop_frac)self.precrop_index = self.precrop_index[self.height // 2 - dH:self.height // 2 + dH, self.width  // 2 - dW:self.width  // 2 + dW].reshape(-1)poses = torch.FloatTensor(self.poses, device=self.device) #torch.cuda.FloatTensor(self.poses, device=self.device)all_ray_dirs, all_ray_origins = [], []for i in range(len(self.images)):ray_dirs, ray_origins = self.make_rays(self.transformed_x, self.transformed_y, poses[i])all_ray_dirs.append(ray_dirs)all_ray_origins.append(ray_origins)self.all_ray_dirs    = torch.stack(all_ray_dirs, dim=0)self.all_ray_origins = torch.stack(all_ray_origins, dim=0)self.images          = torch.FloatTensor(self.images, device=self.device).view(self.num_image, -1, 3)#torch.cuda.FloatTensor(self.images, device=self.device).view(self.num_image, -1, 3)def make_rays(self, x, y, pose):# 100, 100, 3# 坐标系在-y,-z方向上directions    = torch.stack([x, -y, -torch.ones_like(x)], dim=-1)camera_matrix = pose[:3, :3]# 10000 x 3ray_dirs = directions.reshape(-1, 3) @ camera_matrix.Tray_origin = pose[:3, 3].view(1, 3).repeat(len(ray_dirs), 1)return ray_dirs, ray_origin # xyz theta phi

体渲染主要关注以下代码。

def predict_to_rgb(sigma, rgb, z_vals, raydirs, white_background=False):device         = sigma.devicedelta_prefix   = z_vals[..., 1:] - z_vals[..., :-1] #0.0635 sample point delta delta_addition = torch.full((z_vals.size(0), 1), 1e10, device=device)delta = torch.cat([delta_prefix, delta_addition], dim=-1)delta = delta * torch.norm(raydirs[..., None, :], dim=-1)alpha    = 1.0 - torch.exp(-sigma * delta) # 1 - e**-sigma*deltaexp_term = 1.0 - alphaepsilon  = 1e-10exp_addition = torch.ones(exp_term.size(0), 1, device=device)exp_term = torch.cat([exp_addition, exp_term + epsilon], dim=-1)transmittance = torch.cumprod(exp_term, axis=-1)[..., :-1] #(1-alpha0)weights       = alpha * transmittancergb           = torch.sum(weights[..., None] * rgb, dim=-2)depth         = torch.sum(weights * z_vals, dim=-1)acc_map       = torch.sum(weights, -1)if white_background:rgb       = rgb + (1.0 - acc_map[..., None])return rgb, depth, acc_map, weights

体渲染的公式:

连续的:

离散的:

 

不想打字了,去上班挣窝囊费了.....

推荐代码:

shouxieai/nerf: nerf (github.com)

推荐教学视频(讲的真的很好):

【较真系列】讲人话-NeRF全解(原理+代码+公式)_哔哩哔哩_bilibili

推荐b站博主(有时候会去直播,但是看我直播的只有一个人机粉丝):

奈阿伊超


http://www.ppmy.cn/news/1519458.html

相关文章

如何防范ddos 攻击

防护DDoS(分布式拒绝服务)攻击是一个复杂且多方面的任务,需要综合考虑网络架构、硬件设备、软件配置以及安全策略等多个方面。以下是一些主要的防护DDoS攻击的方法: 1. 流量清洗(Traffic Scrubbing) 定义…

Spring AOP切面类的封装与解析

Spring AOP切面类的封装与解析 一、引言 在软件开发中,随着系统复杂度的增加,代码中会频繁出现一些横切关注点(Cross-cutting Concerns),如日志记录、安全认证、事务管理等。这些关注点并非业务逻辑的一部分&#xf…

Java笔试面试题AI答之面向对象(10)

文章目录 55.解释Java可以覆盖静态方法吗?如果我在子类中创建相同的方法会有编译时错误吗?56.解释为什么Java不支持运算符重载?57.实现Java写一个Singleton案例 ?58.简述如何使用Java实现内部类 ?实现内部类的基本语法…

django外键表查询存储删除

查询 之前用get 现在用filter,get返回对象,filter返回列表django model的get和filter方法的区别_django模型objects.get-CSDN博客 存储 删除

django外键表查询

Django外键(ForeignKey)操作以及related_name的作用-CSDN博客 django模型中外键操作_django的model的contain外键-CSDN博客 通过基本表可以查外键表 删基本表可以删外键表

神策埋点 sensorsdata.es6.min.js、sensorsdata.min.js 触发eslint 语法检查,导致打包不成功

问题描述: 在使用神策埋点时,下载的web js sdk,打包时eslint 语法检查,会导致打包不成功。npm start没问题。 主要错误是: Line 1:204272: Expected an assignment or function call and instead saw an expression …

自治系统与局域网的区别

自治系统与局域网在本质上有明显的区别。‌ 自治系统(AS)是一个有权自主地决定在本系统中应采用各种路由协议的小型单位,它是一个单独的可管理的网络单元,可以是一个简单的网络也可以是一个由一个或多个普通的网络管理员来控制的…

搜维尔科技:‌XSENS高精度惯性动作捕捉系统,人形机器人Al训练专用设备

为人型机器人提供高质量人体运动数据 , 让人型机器人的运动更真实 、更自然! Xsens惯性动作捕捉系统 Xsens惯性动作捕捉系统是一套由惯性传感器驱动的可穿戴式的全身动作捕捉系统,可精确捕捉人体运动中的各种精细动作,Xsens惯性动作捕捉系统拥有穿戴方…

【JUC】09-线程等待与唤醒

1. Object wait和notify实现等待与唤醒 没有锁会报错。 public class demo01 {public static void main(String[] args) {Object objectLock new Object();new Thread(()->{synchronized (objectLock) {try {// 释放当前锁, 等待notify, 必须先使用wait才能使用notifyobj…

fpga图像处理实战-双线性插值算法

FPGA实现 `timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2024/08/29 19:10:23 // Design Name: // Module Name: image_line_buffer // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Re…

Docker使用指南:从入门到实践

Docker是一种开源的容器化技术,旨在为开发人员和系统管理员提供一种轻量级、可移植的环境,以便于应用程序的开发、部署和运行。通过Docker,你可以将应用程序及其依赖项打包在一个可移植的容器中,并在任何环境中一致地运行。本文将…

七. 部署YOLOv8检测器-load-save-tensor

目录 前言0. 简述1. 案例运行2. 补充说明3. 代码分析3.1 main.cpp3.2 create_data.py 结语下载链接参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》,链接。记录下个人学习笔记,仅供自己参考 本次课程我们来学习课程第六章—部署分类器&…

kali——nikto的使用

目录 前言 使用方法 查看帮助(--help) 常规扫描(-h) 指定端口扫描(-h -p) 目录猜解(-h -C) 扫描敏感目录(-h) 保存扫描信息 前言 linux自带的nikto工…

PDF-Extract-Kit提取PDF数据

链接: https://github.com/opendatalab/PDF-Extract-Kit 记录一下 首先是clone该项目, 然后新建一个虚拟环境 进入环境,进入项目 https://github.com/opendatalab/PDF-Extract-Kit?tabreadme-ov-file#installation-guide 如果报错没有PIL…

【HarmonyOS NEXT开发】鸿蒙开发环境准备,ArkTS基础语法入门

文章目录 鸿蒙开发环境准备,ArkTS基础语法入门大纲简介DevEco Studio简介运行环境要求 安装与配置开发工具下载Harmony OS 和 OpenHarmony 的区别Previewer汉化插件的配置 ArkTS基础快速入门1. 解释说明2. 变量与常量3. 变量命名规则4. 数组5. 函数定义函数调用函数…

19. 排序dataframe:掌握这些技巧,让你的数据更有序

哈喽,大家好,我是木头左! 使用sort_values()函数进行排序 Pandas库提供了sort_values()函数,用于对dataframe进行排序。该函数的基本语法如下: df.sort_values(by, axis0, ascendingTrue, inplaceFalse, kindquickso…

C语言典型例题58

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 例题4.10 求100~200中的全部素数。 代码&#xff1a; //《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 //例题4.10 求100~200中的全部素数。#include <stdio.h> #include <math.h>int m…

k8s ingress-nginx

ingress-nginx 基于域名7层代理 1.安装 # 仓库下载 helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm pull ingress-nginx/ingress-nginx# 导入ningress-nginx [rootmaster 2、ingress-nginx]# tree -l . ├── chart │ └── ingress-ng…

jsmn输出

对应c程序&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include "jsmn.h"#define my_printf(format, ...) printf(format, ##__VA_ARGS__) //#define my_printf(format, ...) typedef unsigned char uint8_t; typed…

docker部署流程

1、安装python容器 docker pull python:3.12.4 2、挂载本地目录及容器目录并分配一个伪输入输出&#xff0c;进入容器命令行 docker run -it --name pytest -v /Users/python_work/ai:/root/text_similar python:3.12.4 bash 3、拉取python项目需要依赖包 pip3 install XXX …