3D Gaussian Splatting代码详解(三):模型构建,实现3D 高斯椭球体的克隆和分裂

3 模型构建

3.4 根据梯度对3D gaussian 进行增加或删减

(1) 对3D高斯分布进行密集化和修剪的操作 

def densify_and_prune(self, max_grad, min_opacity, extent, max_screen_size):"""对3D高斯分布进行密集化和修剪的操作:param max_grad: 梯度的最大阈值,用于判断是否需要克隆或分割。:param min_opacity: 不透明度的最小阈值,低于此值的3D高斯将被删除。:param extent: 场景的尺寸范围,用于评估高斯分布的大小是否合适。:param max_screen_size: 最大屏幕尺寸阈值,用于修剪过大的高斯分布。"""# 计算3D高斯中心的累积梯度并修正NaN值grads = self.xyz_gradient_accum / self.denomgrads[grads.isnan()] = 0.0# 根据梯度和尺寸阈值进行克隆或分割操作self.densify_and_clone(grads, max_grad, extent)self.densify_and_split(grads, max_grad, extent)# 创建修剪掩码以删除不必要的3D高斯分布prune_mask = (self.get_opacity < min_opacity).squeeze()if max_screen_size:big_points_vs = self.max_radii2D > max_screen_sizebig_points_ws = self.get_scaling.max(dim=1).values > 0.1 * extentprune_mask = torch.logical_or(torch.logical_or(prune_mask, big_points_vs), big_points_ws)# 应用修剪掩码self.prune_points(prune_mask)# 清理CUDA缓存以释放资源torch.cuda.empty_cache()

这是一个用于密集化和修剪3D高斯分布的函数 densify_and_prune,其作用是根据梯度、不透明度、尺寸范围以及屏幕尺寸等参数来动态调整和优化3D高斯分布。 

函数参数

  1. max_grad: 定义梯度的最大阈值,用于判断高斯分布是否需要进一步克隆或分割。
  2. min_opacity: 定义不透明度的最小阈值,低于该值的高斯分布将被删除。
  3. extent: 定义场景的总体尺寸范围,用来评估高斯分布的大小是否在合理范围内。
  4. max_screen_size: 定义屏幕上的最大显示尺寸阈值,用于修剪尺寸过大的高斯分布。

功能描述

  1. 计算梯度并处理 NaN 值

    • 函数首先计算每个3D高斯中心点的累积梯度,并将任何 NaN 值替换为 0,以避免异常值影响密集化过程。
  2. 密集化操作

    • 使用 densify_and_clonedensify_and_split 函数,根据梯度和尺寸范围的条件,来进行高斯分布的克隆和分割操作,使得数据表示更加密集,并有利于提高信息捕获效率。
  3. 修剪掩码的创建

    • 生成一个 prune_mask 掩码,根据不透明度阈值 min_opacity 来筛选出不符合条件的3D高斯。
    • max_screen_size 存在,函数会额外考虑屏幕尺寸阈值,确保尺寸过大的高斯点也会被修剪掉。这里 big_points_vsbig_points_ws 用于检测高斯在屏幕和世界坐标下的尺寸是否超过限制。
  4. 应用修剪掩码

    • 使用 prune_points 方法删除符合掩码条件的3D高斯分布,减少冗余并优化性能。
  5. 清理 CUDA 缓存

    • 最后,通过 torch.cuda.empty_cache() 清理 GPU 缓存,释放未使用的显存资源,以确保内存占用最小化并提高计算效率。

此函数适用于3D场景的稠密表示和资源优化,通过密集化和修剪操作,有效提升了3D高斯分布的适应性和计算性能,适合动态场景中的高效数据处理。

 

  (2)删除不符合要求的3D高斯分布

def prune_points(self, mask):"""删除不符合要求的3D高斯分布。:param mask: 一个布尔张量,表示需要删除的3D高斯分布。"""# 生成有效点的掩码并更新优化器中的参数valid_points_mask = ~maskoptimizable_tensors = self._prune_optimizer(valid_points_mask)# 更新各参数self._xyz = optimizable_tensors["xyz"]self._features_dc = optimizable_tensors["f_dc"]self._features_rest = optimizable_tensors["f_rest"]self._opacity = optimizable_tensors["opacity"]self._scaling = optimizable_tensors["scaling"]self._rotation = optimizable_tensors["rotation"]# 更新累积梯度和其他相关张量self.xyz_gradient_accum = self.xyz_gradient_accum[valid_points_mask]self.denom = self.denom[valid_points_mask]self.max_radii2D = self.max_radii2D[valid_points_mask]

(3) 删除不符合要求的3D高斯分布在优化器中对应的参数 

def _prune_optimizer(self, mask):"""删除不符合要求的3D高斯分布在优化器中对应的参数:param mask: 一个布尔张量,表示需要保留的3D高斯分布。:return: 更新后的可优化张量字典。"""optimizable_tensors = {}for group in self.optimizer.param_groups:stored_state = self.optimizer.state.get(group['params'][0], None)if stored_state is not None:# 更新优化器状态stored_state["exp_avg"] = stored_state["exp_avg"][mask]stored_state["exp_avg_sq"] = stored_state["exp_avg_sq"][mask]# 删除旧状态并更新参数del self.optimizer.state[group['params'][0]]group["params"][0] = nn.Parameter((group["params"][0][mask].requires_grad_(True)))self.optimizer.state[group['params'][0]] = stored_stateoptimizable_tensors[group["name"]] = group["params"][0]else:group["params"][0] = nn.Parameter(group["params"][0][mask].requires_grad_(True))optimizable_tensors[group["name"]] = group["params"][0]return optimizable_tensors

(4)对那些梯度超过一定阈值且尺度小于一定阈值的3D高斯进行克隆操作。 

def densify_and_clone(self, grads, grad_threshold, scene_extent):"""对那些梯度超过一定阈值且尺度小于一定阈值的3D高斯进行克隆操作。这意味着这些高斯在空间中可能表示的细节不足,需要通过克隆来增加细节。"""# 选择满足条件的点selected_pts_mask = torch.where(torch.norm(grads, dim=-1) >= grad_threshold, True, False)selected_pts_mask = torch.logical_and(selected_pts_mask,torch.max(self.get_scaling, dim=1).values <= self.percent_dense * scene_extent)# 提取这些点的属性new_xyz = self._xyz[selected_pts_mask]  # 位置new_features_dc = self._features_dc[selected_pts_mask]  # 直流分量(基本颜色)new_features_rest = self._features_rest[selected_pts_mask]  # 其他球谐分量new_opacities = self._opacity[selected_pts_mask]  # 不透明度new_scaling = self._scaling[selected_pts_mask]  # 尺度new_rotation = self._rotation[selected_pts_mask]  # 旋转# 将克隆得到的新高斯分布的属性添加到模型中self.densification_postfix(new_xyz, new_features_dc, new_features_rest, new_opacities, new_scaling, new_rotation)

(5)对那些梯度超过一定阈值且尺度大于一定阈值的3D高斯进行分割操作。

def densify_and_split(self, grads, grad_threshold, scene_extent, N=2):"""对那些梯度超过一定阈值且尺度大于一定阈值的3D高斯进行分割操作。这意味着这些高斯可能过于庞大,覆盖了过多的空间区域,需要分割成更小的部分以提升细节。"""# 初始化n_init_points = self.get_xyz.shape[0]padded_grad = torch.zeros((n_init_points), device="cuda")padded_grad[:grads.shape[0]] = grads.squeeze()# 选择满足条件的点selected_pts_mask = torch.where(padded_grad >= grad_threshold, True, False)selected_pts_mask = torch.logical_and(selected_pts_mask,torch.max(self.get_scaling, dim=1).values > self.percent_dense * scene_extent)# 计算新高斯分布的属性stds = self.get_scaling[selected_pts_mask].repeat(N, 1)  # 尺度means = torch.zeros((stds.size(0), 3), device="cuda")  # 均值(新分布的中心点)samples = torch.normal(mean=means, std=stds)  # 随机采样新的位置rots = build_rotation(self._rotation[selected_pts_mask]).repeat(N, 1, 1)  # 旋转# 计算新的位置new_xyz = torch.bmm(rots, samples.unsqueeze(-1)).squeeze(-1) + self.get_xyz[selected_pts_mask].repeat(N, 1)# 调整尺度并保持其他属性new_scaling = self.scaling_inverse_activation(self.get_scaling[selected_pts_mask].repeat(N, 1) / (0.8 * N))new_rotation = self._rotation[selected_pts_mask].repeat(N, 1)new_features_dc = self._features_dc[selected_pts_mask].repeat(N, 1, 1)new_features_rest = self._features_rest[selected_pts_mask].repeat(N, 1, 1)new_opacity = self._opacity[selected_pts_mask].repeat(N, 1)# 将分割得到的新高斯分布的属性添加到模型中self.densification_postfix(new_xyz, new_features_dc, new_features_rest, new_opacity, new_scaling, new_rotation)# 删除原有过大的高斯分布prune_filter = torch.cat((selected_pts_mask, torch.zeros(N * selected_pts_mask.sum(), device="cuda", dtype=bool)))self.prune_points(prune_filter)

 (5) 将新生成的3D高斯分布的属性添加到模型的参数中。 

def densification_postfix(self, new_xyz, new_features_dc, new_features_rest, new_opacities, new_scaling, new_rotation):"""将新生成的3D高斯分布的属性添加到模型的参数中。"""d = {"xyz": new_xyz,"f_dc": new_features_dc,"f_rest": new_features_rest,"opacity": new_opacities,"scaling": new_scaling,"rotation": new_rotation}optimizable_tensors = self.cat_tensors_to_optimizer(d)self._xyz = optimizable_tensors["xyz"]self._features_dc = optimizable_tensors["f_dc"]self._features_rest = optimizable_tensors["f_rest"]self._opacity = optimizable_tensors["opacity"]self._scaling = optimizable_tensors["scaling"]self._rotation = optimizable_tensors["rotation"]self.xyz_gradient_accum = torch.zeros((self.get_xyz.shape[0], 1), device="cuda")self.denom = torch.zeros((self.get_xyz.shape[0], 1), device="cuda")self.max_radii2D = torch.zeros((self.get_xyz.shape[0]), device="cuda")


  (6) 将新的参数张量添加到优化器的参数组中 

def cat_tensors_to_optimizer(self, tensors_dict):"""将新的参数张量添加到优化器的参数组中"""optimizable_tensors = {}for group in self.optimizer.param_groups:extension_tensor = tensors_dict[group["name"]]stored_state = self.optimizer.state.get(group['params'][0], None)if stored_state is not None:stored_state["exp_avg"] = torch.cat((stored_state["exp_avg"], torch.zeros_like(extension_tensor)), dim=0)stored_state["exp_avg_sq"] = torch.cat((stored_state["exp_avg_sq"], torch.zeros_like(extension_tensor)), dim=0)del self.optimizer.state[group['params'][0]]group["params"][0] = nn.Parameter(torch.cat((group["params"][0], extension_tensor), dim=0).requires_grad_(True))self.optimizer.state[group['params'][0]] = stored_stateoptimizable_tensors[group["name"]] = group["params"][0]else:group["params"][0] = nn.Parameter(torch.cat((group["params"][0], extension_tensor), dim=0).requires_grad_(True))optimizable_tensors[group["name"]] = group["params"][0]return optimizable_tensors

(7)根据旋转四元数构建旋转矩阵。 

def build_rotation(r):"""根据旋转四元数构建旋转矩阵。"""norm = torch.sqrt(r[:,0]*r[:,0] + r[:,1]*r[:,1] + r[:,2]*r[:,2] + r[:,3]*r[:,3])q = r / norm[:, None]R = torch.zeros((q.size(0), 3, 3), device='cuda')# 计算旋转矩阵的各元素...return R

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

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

相关文章

无人机协同控制技术详解!

一、算法概述 无人机协同控制技术算法是指通过综合运用通信、控制、优化等多学科知识,实现对多个无人机的协同控制和任务规划。这些算法通常基于各种数学模型和控制理论,如线性代数、微分方程、最优控制等,旨在确保无人机能够相互协作&#…

【热门主题】000013 C++游戏开发全攻略

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【热…

QT中的item views与Item widgets控件的用法总结

0、前言 在一般进行数据表格展示的时候,大多时候要用到表格、列表或者树形结构。 Qt中常见的控件显示有两大类: Item View (list View、Tree View、Table View、Column View和Undo View)Item widget(List Widget、Tree Widget和…

ssm+vue645基于web的电影购票系统设计与实现

博主介绍:专注于Java(springboot ssm 等开发框架) vue .net php phython node.js uniapp 微信小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设,从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不…

Spark RDD

概念 RDD是一种抽象,是Spark对于分布式数据集的抽象,它用于囊括所有内存中和磁盘中的分布式数据实体 RDD 与 数组对比 对比项数组RDD概念类型数据结构实体数据模型抽象数据跨度单机进程内跨进程、跨计算节点数据构成数组元素数据分片(Partitions)数据…

java-数据结构

一.链表 单向链表 /单向链表 public class SinglyLinkedList implements Iterable<Integer> {//头节点private Node head null;//头指针//节点类private static class Node{int value;//值Node next;//下一个节点的指针public Node(int value, Node next) {this.val…

pycharm与anaconda下的pyside6的安装记录

一、打开anaconda虚拟环境的命令行窗口&#xff0c;pip install&#xff0c;加入清华源&#xff1a; pip install PySide6 -i https://pypi.tuna.tsinghua.edu.cn/simple 二、打开pycharm&#xff0c;在文件--设置--工具--外部工具中配置一下三项&#xff1a; 1、 QtDesigner…

成本累计曲线:项目预算的秘密武器

在项目管理的过程中&#xff0c;成本控制是影响项目成败的关键因素之一&#xff0c;而其中“成本累计曲线”就像是一位财务导航员&#xff0c;为项目的成本控制和进度监控提供了极大的帮助。那么&#xff0c;什么是成本累计曲线&#xff1f;它包含哪些步骤&#xff1f;如何应用…

[0152].第3节:IDEA中工程与模块

我的后端学习大纲 IDEA大纲 1、Project和Module的概念&#xff1a; 2、Module操作&#xff1a; 2.1.创建Module: 2.2.删除Module&#xff1a; 2.3.导入Module&#xff1a; 1.导入外来模块的代码&#xff1a; 查看Project Structure&#xff0c;选择import module&#xff1a…

【Linux网络】UdpSocket

目录 套接字 socket编程 源IP地址和目的IP地址 端口号 网络字节序 socket常用API socket结构 UDP UDP协议&#xff08;用户数据报协议&#xff09; 创建套接字 绑定 通信 udp_echo_server:简单的回显服务器和客户端代码 dict_server:简单的英译汉的网络字典 chat_…

双11猫咪好物盛典开启,线上抢购不停 购物清单新鲜出炉

双十一购物狂欢节终于到了&#xff01;铲屎官们想好要给猫咪添置什么好东西了吗&#xff1f;还不知道怎么选的看过来啦~这里整理了一份双十一购物清单&#xff0c;快看看有没有你需要的吧&#xff01; 双十一养猫必购1&#xff1a;CEWEY自动猫砂盆 CEWEY自动猫砂盆真的是我最爱…

magic-api简单使用二:自定义返回结果

背景 在上一章 中我们学习了搭建项目和导入文件&#xff0c; 这二天稍微有点时间&#xff0c;研究下这个magic-api的写法。 后续如果需要维护或者更改&#xff0c;也能在项目中尽快上手。 今天我们主要学习自定义返回结果&#xff0c;当然也可以使用官方的。不需要任何更改。…

二百七十、Kettle——ClickHouse中增量导入清洗数据错误表

一、目的 比如原始数据100条&#xff0c;清洗后&#xff0c;90条正确数据在DWD层清洗表&#xff0c;10条错误数据在DWD层清洗数据错误表&#xff0c;所以清洗数据错误表任务一定要放在清洗表任务之后。 更关键的是&#xff0c;Hive中原本的SQL语句&#xff0c;放在ClickHouse…

【Nas】X-Doc:jellyfin“该客户端与媒体不兼容,服务器未发送兼容的媒体格式”问题解决方案

【Nas】X-Doc&#xff1a;jellyfin“该客户端与媒体不兼容&#xff0c;服务器未发送兼容的媒体格式”问题解决方案 当使用Jellyfin播放视频时出现“该客户端与媒体不兼容&#xff0c;服务器未发送兼容的媒体格式”&#xff0c;这是与硬件解码和ffmpeg设置有关系&#xff0c;具体…

linux应急响应-1

声明&#xff1a;部分内容来源于网络&#xff0c;只是新手练习 靶场环境来自于知攻善防实验室 概述&#xff1a; 一、整体过程 初始环境设置 将Linux centOS 7配置为图形化界面&#xff0c;通过yum groupinstall “X Window System” -y和yum groupinstall “GNOME Desktop”&a…

视频去水印软件推荐:6款去水印工具值得一试

在视频创作和分享的过程中&#xff0c;水印往往会成为影响美观和平台推流。幸运的是&#xff0c;市面上有许多视频去水印软件能够帮助我们轻松解决这一问题。本文将为大家推荐几款实用的视频去水印软件&#xff0c;并详细介绍它们的功能和去除水印的方法。 1.影忆 功能介绍&…

MaxKB: 一款基于大语言模型的知识库问答系统

嗨, 大家好, 我是徐小夕. 之前一直在社区分享零代码&低代码的技术实践&#xff0c;最近也在研究多模态文档引擎相关的产品, 在社区发现一款非常有意思的知识库问答系统——MaxKB, 它支持通过大语言模型和RAG技术来为知识库赋能,今天就和大家分享一下这款项目. PS: 它提供了…

Java NIO2 异步IO支持

NIO2 从 Java 7 在之前的NIO基础上&#xff0c;它提供了异步 IO 操作、文件系统访问增强等诸多功能 路径&#xff08;Path&#xff09;接口 Path 接口代表了文件系统的路径。它可以用来定位一个文件或目录。 提供了多种方法来解析、转换和查询路径信息。Paths 类提供了一些静…

上市公司数字经济与实体经济融合发展程度测算数据(2008-2022年)-最新出炉_附下载链接

上市公司数字经济与实体经济融合发展程度测算数据&#xff08;2008-2022年&#xff09; 下载链接-点它&#x1f449;&#x1f449;&#x1f449;&#xff1a;上市公司数字经济与实体经济融合发展程度测算数据&#xff08;2008-2022年&#xff09;-最新出炉.zip 一、引言 随着…

Prompt Engineering (Prompt工程)

2 prompt工程2大原则 2.1 给出清晰&#xff0c;详细的指令 策略1&#xff1a;使用分割符清晰的指示输出的不同部分&#xff0c;比如"",<>,<\tag>等分隔符 策略2&#xff1a;指定一个结构化的输出&#xff0c;比如json,html等格式 策略3&#xff1a;要…