Scaffold-GS 代码阅读笔记

1. 系统启动部分

使用 python 中的 parser 库 为配置系统的参数设定, 和3DGS 类似,并且使用safe_state(args.quiet) 函数 为每一次的 log 输出加上对应的 时间戳

## 配置参数的设定
 lp = ModelParams(parser)
 op = OptimizationParams(parser)
 pp = PipelineParams(parser)

## 指定随机数的种子,并且将 log 的 std::out 输出 加上对应的 时间戳
safe_state(args.quiet)

–lod 用于对 Train/Test 的图像进行划分,表示Test 的Image 的数量。 比如, lod=40, 那么表示 选择40张图像作为 Test,剩下的图像作为 Train

2. Training 函数

2.1 初始化 Gaussian 的设定:

gaussians = GaussianModel(dataset.feat_dim, dataset.n_offsets, dataset.voxel_size, dataset.update_depth, dataset.update_init_factor, dataset.update_hierachy_factor, dataset.use_feat_bank, 
                              dataset.appearance_dim, dataset.ratio, dataset.add_opacity_dist, dataset.add_cov_dist, dataset.add_color_dist)

定义了网络的结构:
MLP_opacity:
在这里插入图片描述
MLP_cov:
在这里插入图片描述

MLP_color
在这里插入图片描述
2.2 读取位姿和图像

读取 colmap 生成的图像和位姿:
首先对于colmap 图像的 所有图像和 Pose 进行 Train/Test 的划分, 其中默认是 每隔8张选择一张作为 Test Image( LLFF 的划分依据).

代码里也设置了 – lod 参数来指定 Test Image 的个数, 比如 设置 –lod = 20 , 那么就代表由20张图像作为 TestImage; 剩下的 图像作为 Train Image.

Pose 的 Normalize. [ 所有的相机相对于中心点来说 ]

之后,需要在 Mipnerf360 这种环绕拍摄的setting 对 Train Camera 的位姿进行处理,其目的是根据所有 camera 的 位置,确定 整个场景的 几何中心(center) 和整个场景的 半径 radius. 然后所有的相机的位置都要 减去这个 center 的坐标, 相对于对于Pose 进行了 【-1,1】 之间的映射。

直接读取了 PLY 格式的 3D Colmap 重建的点云

点云和相机的参数 都保存在 scene_info 这个对象里面,对应着点云的3个属性:
在这里插入图片描述

对于图像进行 降采样

降采样的参数是通过命令行的 参数 -r 去实现的. 将 -r 设置成4, 我们对于图像进行降采样 4倍;

需要注意的是,根据 视场角 fov 的定义,对于图像进行长和宽等比例的降采样之后,视场角FOV 是保持不变的 (如果考虑相机的主点不存在偏移的话)。因此 3DGS 使用的 projection Matrix 是没有变换的

根据相机的 Fov_x, Fov_y, z_near, z_far 构建相机透视投影矩阵:

透视投影矩阵 往往假设 视锥,假设一个对称的视锥,不直接考虑主点偏移, (cx,cy 位于图像的中心的地方)。

def getProjectionMatrix(znear, zfar, fovX, fovY):
    tanHalfFovY = math.tan((fovY / 2))
    tanHalfFovX = math.tan((fovX / 2))

    top = tanHalfFovY * znear
    bottom = -top
    right = tanHalfFovX * znear
    left = -right

    P = torch.zeros(4, 4)

    z_sign = 1.0

    P[0, 0] = 2.0 * znear / (right - left)
    P[1, 1] = 2.0 * znear / (top - bottom)
    P[0, 2] = (right + left) / (right - left)
    P[1, 2] = (top + bottom) / (top - bottom)
    P[3, 2] = z_sign
    P[2, 2] = z_sign * zfar / (zfar - znear)
    P[2, 3] = -(zfar * znear) / (zfar - znear)
    return P

为每个相机计算 内参 ProjectionMatrix外参 world_view_transform,两个4*4的矩阵。

2.3 从点云去创建场景的 3D Gaussian

首先对于 redundancy 点云 进行删除:
  points = self.voxelize_sample(points, voxel_size=self.voxel_size)

在这里插入图片描述
然后去初始化 高斯球的一些属性, scale 的初始化 用到了 KNN 算法 去寻找最近的点。 旋转 rot 从 0 开始初始化, opacity 随机给定一个固定数值从 0.1 初始化. 初始化的 代码和原始的 3DGS 相似, 但是 却多了3个物理量
anchor: 实际上就是3D 点云的坐标 xyz

offset:: 一个 anchor point 会生成 k个 Gaussian, 其位置是 anchor point 的位置加上 offset 偏移量

**scaling ** : 每一个 anchor_point 额外有一个 scaling 的属性, 其初始化时每个3D点到最近3D点的距离, 但是却 repeat 了6次,因此 shape 时 (N,6). 这个 scaleing factor 不是高斯的属性,不能理解为 协方差中的 scale,而是一个缩放因子。

## 这里的 anchor 其实就是高斯球的中心点,由点云得到的
self._anchor = nn.Parameter(fused_point_cloud.requires_grad_(True))

## 代码里 offset 初始为10.  offset shape 【N,10,3】
self._offset = nn.Parameter(offsets.requires_grad_(True))
self._anchor_feat = nn.Parameter(anchors_feat.requires_grad_(True))
self._scaling = nn.Parameter(scales.requires_grad_(True))  
self._rotation = nn.Parameter(rots.requires_grad_(False))
self._opacity = nn.Parameter(opacities.requires_grad_(False))
## max_radii2D shape [N] 
self.max_radii2D = torch.zeros((self.get_anchor.shape[0]), device="cuda")

2.3 每次随机选择一个相机 进行训练

# Pick a random Camera
 if not viewpoint_stack:
     viewpoint_stack = scene.getTrainCameras().copy()
 viewpoint_cam = viewpoint_stack.pop(randint(0, len(viewpoint_stack)-1))
Mask 掉 frustum 之外的 Gaussian, 并且对于 alpha 的阈值具有一定的要求

为每一个 anchor point 生成 一个 Mask

voxel_visible_mask = prefilter_voxel(viewpoint_cam, gaussians, pipe,background)

根据 anchor_point 生成 新的 3D Gaussian

xyz, color, opacity, scaling, rot, neural_opacity, mask = generate_neural_gaussians(
viewpoint_camera,  ## 相机的属性
pc,                ## 3D高斯输入
visible_mask,      ## 可见的Mask
 is_training=is_training)

计算每个 3D gaussian 球到 相机的 距离 dist 和方向
在这里插入图片描述

    ob_view = anchor - viewpoint_camera.camera_center
    # dist
    ob_dist = ob_view.norm(dim=1, keepdim=True)
    # view
    ob_view = ob_view / ob_dist

每个 anchor point 有 dim=32 的feature , 将这个 feature 和 距离 dist, 方向dir concat 起来。 实际的实现里面
pc.add_opacity_dist = False , 因此 预测 opacity 的 输入 ,只有 方向 dir 和 feature concat 起来,组成了 35 维度的 vector,

预测 Neural Gaussian 的 opacity

cat_local_view = torch.cat([feat, ob_view, ob_dist], dim=1) # [N, c+3+1]
cat_local_view_wodist = torch.cat([feat, ob_view], dim=1) # [N, c+3]
## MLP 预测,将feature 转换成 opacity
neural_opacity = pc.get_opacity_mlp(cat_local_view_wodist)

预测 Neural Gaussian 的 color

和前面一张,使用的 feature 是35 维度的, 不包括 dist ;
同样是 输入 35维度的向量,我们可以直接 通过MLP 推理得到 color 的数值:

## color 的output dim = 30
color = pc.get_color_mlp(cat_local_view_wodist)
## 将30 dim 的feature , reshape 成 [N,10,3]. 因为每一个 anchor point 会生成10个 Gaussian, 每个 Gaussian 有3个维度的 color 
color = color.reshape([anchor.shape[0]*pc.n_offsets, 3])# [mask]

预测 Neural Gaussian 的 cov [ 旋转Rot 和缩放 scale ]

在这里插入图片描述
预测 协方差的 Cov_mlp 输入时35 维度(和前面保持一致),输出是70维度。

scale_rot = pc.get_cov_mlp(cat_local_view_wodist)
## reshape 成 [N,10,7]
scale_rot = scale_rot.reshape([anchor.shape[0]*pc.n_offsets, 7]) # [mask]

对于 Cov 进行后处理,得到每个高斯球的 scale 和 rot:

scaling repeat 是每一个 anchor point 的属性, shape 是 [N,6]. 6 个数字是一样的。 对应公式中的 l v l_v lv

scaling = scaling_repeat[:,3:] * torch.sigmoid(scale_rot[:,:3]) # 对于协方差的 scale 需要进行scaling
rot = pc.rotation_activation(scale_rot[:,3:7]) # 对于协方差的 rot 可以直接使用激活函数,进行激活

预测 Neural Gaussian 的 位置 xyz

从一个 anchor point 出发,加上 缩放之后的 offset, 可以确定 Neural Gaussian 的位置

# post-process offsets to get centers for gaussians
offsets = offsets * scaling_repeat[:,:3]  ## 对于offset 同样需要 乘以 scaling 
xyz = repeat_anchor + offsets

在这里插入图片描述

2. Render 函数. 根据生成的 3D Neural Gaussian 进行 Rasterize. 这一部分主要和3D GS 的实现保持一致。

这一部分是 CUDA 的代码,和3DGS 的渲染过程是一致的。

# Rasterize visible Gaussians to image, obtain their radii (on screen). 
rendered_image, radii = rasterizer(
      means3D = xyz,  ## 3D Gaussian 的中心点
      means2D = screenspace_points, ## output: 3DGS 投影到2D screen 上的点,用来记录梯度
      shs = None,
      colors_precomp = color,   ## 3DGS 的颜色
      opacities = opacity,      ## 3DGS 的不透明度 alpha
      scales = scaling,         ## 3DGS 的 scaling 
      rotations = rot,         ## 3DGS 的 旋转
      cov3D_precomp = None)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/535201.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式linux系统链接腾讯云的方法

各位开发者大家好,今天主要给大家分享一个,如何使用linux系统链接腾讯云的方法,因为微信小程序越来越普遍,链接腾讯云也是日常必须掌握的一个技能。 第一:【实验目的】 1、linux 系统连接腾讯云的方法 第二:【实验原理】 涉及到原理图添加原理图 2、linux开发板 …

Windows:Redis数据库图形化中文工具软件——RESP(3)

这个是用于连接redis数据库的软件工具,安装在windows上的图形化界面,并且支持中文,是在github上的一个项目 1.获取安装包 发布 lework/RedisDesktopManager-Windows (github.com)https://github.com/lework/RedisDesktopManager-Windows/rel…

6.11物联网RK3399项目开发实录-驱动开发之定时器的使用(wulianjishu666)

嵌入式实战开发例程【珍贵收藏,开发必备】: 链接:https://pan.baidu.com/s/1tkDBNH9R3iAaHOG1Zj9q1Q?pwdt41u 定时器使用 前言 RK3399有 12 个 Timers (timer0-timer11),有 12 个 Secure Timers(stimer0~stimer11) 和 2 个 …

学习JavaEE的日子 Day35 字节流

5.字节流 应用场景:操作二进制数据(音频、视频、图片) abstract class InputStream – 字节输入流的基类(抽象类) abstract class OutputStream – 字节输出流的基类(抽象类) class FileInputSt…

JVM 垃圾回收算法

JVM 垃圾回收算法 标记清除算法复制算法标记整理算法分代算法 标记清除算法 标记-清除(Mark-Sweep)算法属于早期的垃圾回收算法,它是由标记阶段和清除阶段构成的。标记阶段会给所有的存活对象做上标记,而清除阶段会把没有被标记的…

记录一次浅拷贝导致的缺陷

背景:假期表查询,表中存放的工作日信息是按照月份维度的,例如1月的假期表信息是NNNYYYYYNN.....一共31天,如果是工作日那么就是Y,如果非工作日那就是N。获取指定日期的下一个工作日,就会先查出这个月份的这…

史上首位阿贝尔奖、图灵奖双得主!2023图灵奖授予随机性大佬Avi Wigderson

ChatGPT狂飙160天,世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 这位多产的研究者发现了随机性和计算之间的深刻联系,其贡献影响了密码学、复杂性…

LLM激活稀疏性加速

相关工作 Deja vu Contextual sparsity for efficient llms at inference time LLM in a flash Efficient Large Language Model Inference with Limited Memory ReLU Strikes Back Exploiting Activation Sparsity in Large Language Models ReLU2 Wins: Discovering Effi…

家居网购项目(一)

文章目录 1.前置知识1.项目开发阶段2.Java经典三层架构3.项目具体分层(包方案)4.MVC 2.开发环境搭建1.新建普通javaweb项目,导入jar包2.创建项目结构3.搭建前端页面 3.会员注册前端js校验1.需求分析2.代码login.html 3.结果4.调试阶段1.验证信…

[目标检测] OCR: 文字检测、文字识别、text spotter

概述 OCR技术存在两个步骤:文字检测和文字识别,而end-to-end完成这两个步骤的方法就是text spotter。 文字检测数据集摘要 daaset语言体量特色MTWI中英文20k源于网络图像,主要由合成图像,产品描述,网络广告(淘宝)MS…

Linux下使用C语言实现高并发服务器

高并发服务器 这一个课程的笔记 相关文章 协议 Socket编程 高并发服务器实现 线程池 使用多进程并发服务器时要考虑以下几点: 父进程最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符)系统内创建进程个数(与内存大小相关)进程创建过多是否降低整体…

代码随想录训练营day36

第八章 贪心算法 part05 1.LeetCode. 无重叠区间 1.1题目链接:435. 无重叠区间 文章讲解:代码随想录 视频讲解:B站卡哥视频 1.2思路:我来按照右边界排序,从左向右记录非交叉区间的个数。最后用区间总数减去非交叉区…

yolov8训练自己数据集的一些小细节

例如我的路径格式如下: 这里要保证两个对齐, train/images/img1.jpg,2,3,xxx train/labels/img1.txt,2,3,xxx val/images/img1.jpg,2,3,xxx val/labels/img1.txt,2,3,xxxyaml文件读取路径的时候,个人猜测是依靠替换字符串找标签的, 因为yaml文件里没有指明如何加载labels,它后…

MobX原理剖析:基于可观察状态和自动依赖追踪的响应式状态管理

我们用代码示例来说明 MobX 的核心原理。 首先,我们定义一个简单的 Store 类,其中包含一个可观察的计数器状态: import { observable, action } from mobx;class CounterStore {observable count 0;actionincrement () > {this.count;};actiondecrement () > {this.…

【STM32G431RBTx】备战蓝桥杯嵌入式→省赛试题→第十四届

文章目录 前言一、题目二、模块初始化三、代码实现interrupt.h:interrupt.c:main.h:main.c: 四、完成效果五、总结 前言 无 一、题目 二、模块初始化 1.LCD这里不用配置,直接使用提供的资源包就行 2.KEY, 四个按键IO口都要配置,分别是PB0, PB1,PB2,PA…

【端云一体化开发】云函数本地运行/调试启动失败的两种解决方案

最近本地调试云函数一直出现这个错误:Before launch task execute failed! details:java.lang.lllegalStateException: npm installfailed 这个问题的原因似乎是运行云函数的时候会重新下载 npm 及相关依赖文件,但是 DevEco 的 npm 模块出错导致这个步骤…

软考121-上午题-【软件工程】-敏捷方法

一、敏捷方法 敏捷开发的总体目标是通过“尽可能早地、持续地对有价值的软件的交付”使客户满意。通过在软件开发过程中加入灵活性,敏捷方法使用户能够在开发周期的后期增加或改变需求。 敏捷过程的典型方法有很多,每一种方法基于一套原则,这…

内核驱动更新

1.声明我们是开源的 .c 文件末尾加上 2.在Kconfig里面修改设备,bool(双态)-----》tristate(三态) 3.进入menuconfig修改为M 4.编译内核 make modules 也许你会看到一个 .ko 文件 5.复制到根目录文件下 在板子…

【Linux的进程篇章 - 进程终止和进程等待的理解】

Linux学习笔记---008 Linux之fork函数、进程终止和等待的理解1、fork函数1.1、什么是fork?1.2、fork的功能介绍1.3、fork函数返回值的理解1.4、fork函数的总结 2、进程的终止2.1、终止是在做什么?2.2、进程终止的3种情况 3、进程的终止3.1、进程终止的三种情况3.2、…

深度学习简介

深度学习简介 一、引言:深度学习的兴起 简短介绍深度学习的历史背景 深度学习,作为人工智能领域的一颗冉冉升起的新星,其根源可以追溯到上世纪的感知机学习算法。这种算法模拟人类的神经元行为,是最早期的尝试之一。然而&#x…