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 * znearbottom = -topright = tanHalfFovX * znearleft = -rightP = torch.zeros(4, 4)z_sign = 1.0P[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_signP[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 Cameraif 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,      ## 可见的Maskis_training=is_training)

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

    ob_view = anchor - viewpoint_camera.camera_center# distob_dist = ob_view.norm(dim=1, keepdim=True)# viewob_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 的不透明度 alphascales = scaling,         ## 3DGS 的 scaling rotations = rot,         ## 3DGS 的 旋转cov3D_precomp = None)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分布式向量数据库-安装部署

下载 GitHub - pgvector/pgvector: Open-source vector similarity search for Postgres 源码编译 ##文件解压缩 unzip pgvector-0.6.2.zip ##编译 make && make install 功能验证 #安装扩展CREATE EXTENSION vector;#创建测试表CREATE TABLE items (id bigseri…

【算法】哈希表

个人主页 : zxctscl 如有转载请先通知 题目 1. 1. 两数之和1.1 分析1.2 代码 2. 面试题 01.02. 判定是否互为字符重排2.1 分析2.2 代码 3. 217. 存在重复元素3.1 分析3.2 代码 4. 219. 存在重复元素 II4.1 分析4.2 代码 5. 49. 字母异位词分组5.1 分析5.2 代码 1. 1…

Gateway的简单介绍和使用

1、Gateway简介: Gateway 是一种 API 网关(API Gateway)技术,它作为微服务架构中的关键组件,负责为系统的外部请求与内部服务之间提供统一的接入点。Spring Cloud Gateway 是基于 Spring 生态系统实现的一个高性能、易…

2024.4.11

1.思维导图 2.指针形式验证大小端存储 #include<myhead.h>int main(int argc, const char *argv[]) {int num 0x12345678;char* ptr (char *)&num;if(*ptr 0x12){printf("big endian\n");}else if(*ptr 0x78){printf("little endian\n");}r…

MINI2440 开发板 给他干出来了

环境是ubuntu14.04。不要问我为什么是这个版本&#xff0c;因为之前的ubuntu12.04 环境干不出来&#xff0c;你去试试就知道了&#xff01;各种资源包下载不下来。 输入启动参数&#xff1a; 进入MINI2440&#xff1a;别说心里一万个开心&#xff0c;启动完成&#xff0c;输入p…

【电子通识】热风枪的结构与使用方法

热风枪的结构 热风枪是专门用来拆焊、焊接贴片元器件和贴片集成电路的焊接工具&#xff0c;它主要由主机和热风焊枪两大部分构成。 热风枪主要有电源开关、风速设置、温度设置、热风连接等部件组成。根据不同品牌和价位的热风枪&#xff0c;有一些功能齐全的也集成了烙铁功能。…

负荷预测 | Matlab基于TCN-LSTM-Attention单输入单输出时间序列多步预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.负荷预测 | Matlab基于TCN-LSTM-Attention单输入单输出时间序列多步预测&#xff1b; 2.单变量时间序列数据集&#xff0c;采用前12个时刻预测未来96个时刻的数据&#xff1b; 3.excel数据方便替换&#xff0c;运行…

【鸿蒙开发】系统组件Column

Column组件 Column沿垂直方向布局的容器。 接口&#xff1a; Column(value?: {space?: string | number}) 参数&#xff1a; 参数名 参数类型 必填 参数描述 space string | number 否 纵向布局元素垂直方向间距。 从API version 9开始&#xff0c;space为负数或者…

Mongodb入门--头歌实验MongoDB 之滴滴、摩拜都在用的索引

MongoDB 常用于大数据的存储&#xff0c;在庞大的数据中查询出我们所要的信息&#xff0c;如果使用普通查询方法&#xff0c;遍历所有文档查询&#xff0c;花费的时间太久了。 假设现在有个集合 person&#xff0c;查询命令&#xff1a;db.person.find( {age: 18} )&#xff0…

libVLC 视频窗口上叠加透明窗口

很多时候&#xff0c;我们需要在界面上画一些三角形、文字等之类的东西&#xff0c;我们之需要重写paintEvent方法&#xff0c;比如像这样 void Widget::paintEvent(QPaintEvent *event) 以下就是重写的代码。 void Widget::paintEvent(QPaintEvent *event) {//创建QPainte…

振动信号频域图绘制函数(python版)

在实际应用中&#xff0c;不免会看时域图和频域图&#xff0c;封装了绘制时域图和频域图程序&#xff0c;方便调用 ## 导入包 from matplotlib import pyplot as plt from matplotlib import rcParams import numpy as np import pandas as pdconfig {"font.family"…

创新指南|战略衡量的增长组织:用人工智能增强关键绩效指标(KPI)

传统的关键绩效指标 (KPI)越来越无法提供领导者取得成功所需的信息和见解。他们在跟踪进展、协调人员和流程、确定资源优先级以及推进问责制方面存在不足。本文是 2024 年第一份麻省理工学院 SMR - BCG 人工智能和商业战略全球高管学习和研究项目的调查结果——人工智能和业务战…

最新PDD商家端Anti-Content参数逆向分析与纯算法还原

文章目录 1. 写在前面2. 接口分析3. 断点分析4. 扣JS代码 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致…

第十五篇:Mybatis

文章目录 一、什么是MyBatis二、Mybatis入门案例三、配置SQL提示四、数据库连接池四、lombok五、mybatis基础操作5.1 根据id删除5.2 预编译SQL5.3 新增员工5.4 更新员工5.5 查询员工&#xff08;用于页面回显&#xff09;5.6 条件查询 七、XML映射文件八、动态SQL8.1 if语句8.2…

(学习日记)2024.04.12:UCOSIII第四十节:软件定时器函数接口讲解

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

JavaScript_语法--变量

1.4 变量 变量&#xff1a;一小块存储数据的内存空间 Java语言是强类型语言&#xff0c;而JavaScript是弱类型的语言 强类型&#xff1a; 在开辟变量存储空间时&#xff0c;定义了空间将来存储的数据的数据类型。只能存储固定类型的数据 弱类型&#xff1a; 在开辟变量存储空间…

VS中使用QT的UI提升类时,找不到头文件的情况

1、情况简述 在使用VS时&#xff0c;会发现与QCreator存在一些差异。最主要的就是要设置很多东西&#xff0c;如果不配置的话&#xff0c;就会遇到一些问题。下面我分享下我调试过程中遇到的一个问题。使用Qdesigner的UI提升类时&#xff0c;找不到头文件的情况&#xff1a; …

Kivy 学习2

from kivy.app import App from kivy.uix.button import Button from kivy.uix.floatlayout import FloatLayout from kivy.graphics import Rectangle, Colorclass FloatLayoutApp(App):def build(self):def update_rect(layout, *args):设置背景尺寸&#xff0c;可忽略layout…

Spring Cloud学习笔记:Eureka简介,Eureka简单样例

这是本人学习的总结&#xff0c;主要学习资料如下 - 马士兵教育 [TOC](目录)1、Eureka 1.1、架构 Eureka是SpringCloud Nexflix的核心子模块&#xff0c;其中包含Server和Client。 Server提供服务注册&#xff0c;存储所有可用服务节点。 Client用于简化和Server的通讯复杂…

【学习心得】Python中的queue模块使用

一、Queue模块的知识点思维导图 二、Queue模块常用函数介绍 queue模块是内置的&#xff0c;不需要安装直接导入就可以了。 &#xff08;1&#xff09;创建一个Queue对象 import queue# 创建一个队列实例 q queue.Queue(maxsize20) # 可选参数&#xff0c;默认为无限大&am…