3D Gaussian Splatting代码中的Gaussian_Module和Cameras两个类的代码解读

Gaussian_model

讨论Gaussian_model这个类,是因为里面包含了三维高斯分布的基本信息,里面定义了各种参量的构建方式、用于优化学习的激活函数、学习率设置方法和高斯点优化过程中的增加与删除方式及对应优化器的处理方法。这个类定义在scene文件夹中的gaussian_module.py文件里。

scene/gaussian_model中进行函数构建

在这里插入图片描述

协方差矩阵和各种参数的激活函数

首先这个方法构建了协方差矩阵,而其中旋转、缩放矩阵在以下文件中:

utils/general_utils的build_rotation中构建旋转矩阵

'''
用来计算四元数表示的旋转矩阵(Rotation Matrix)的。。

首先,通过计算每个四元数的模长,来标准化它们。这是为了确保旋转向量(四元数)的单位长度,以便于正确地进行旋转计算。

接着,将标准化后的四元数应用到旋转矩阵上。这里,代码创建了一个大小为 (batch_size, 3, 3) 的零张量 R,然后,通过四元数的各个分量进行矩阵赋值,根据四元数到旋转矩阵的转换公式来填充这个张量。

最后,返回填充完的旋转矩阵 R。

需要注意的是,这段代码是针对批处理的,因此输入 r 是一个张量,其中每一行代表一个四元数。
'''
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')

    r = q[:, 0]
    x = q[:, 1]
    y = q[:, 2]
    z = q[:, 3]

    R[:, 0, 0] = 1 - 2 * (y*y + z*z)
    R[:, 0, 1] = 2 * (x*y - r*z)
    R[:, 0, 2] = 2 * (x*z + r*y)
    R[:, 1, 0] = 2 * (x*y + r*z)
    R[:, 1, 1] = 1 - 2 * (x*x + z*z)
    R[:, 1, 2] = 2 * (y*z - r*x)
    R[:, 2, 0] = 2 * (x*z - r*y)
    R[:, 2, 1] = 2 * (y*z + r*x)
    R[:, 2, 2] = 1 - 2 * (x*x + y*y)
    return R

utils/general_utils的build_scaling_rotation中构建缩放矩阵并将旋转矩阵和缩放矩阵合并

def build_scaling_rotation(s, r):
    L = torch.zeros((s.shape[0], 3, 3), dtype=torch.float, device="cuda")
    R = build_rotation(r)

    L[:,0,0] = s[:,0]
    L[:,1,1] = s[:,1]
    L[:,2,2] = s[:,2]

    L = R @ L
    return L

scene/gaussian_model的setup_functions中用build_covariance_from_scaling_rotation中将旋转矩阵和缩放矩阵合并并处理成协方差矩阵。并在setup_functions中设定激活函数。

def setup_functions(self):
        def build_covariance_from_scaling_rotation(scaling, scaling_modifier, rotation):
            L = build_scaling_rotation(scaling_modifier * scaling, rotation)
            actual_covariance = L @ L.transpose(1, 2)
            symm = strip_symmetric(actual_covariance)
            return symm
        
        self.scaling_activation = torch.exp
        self.scaling_inverse_activation = torch.log

        self.covariance_activation = build_covariance_from_scaling_rotation

        self.opacity_activation = torch.sigmoid
        self.inverse_opacity_activation = inverse_sigmoid

        self.rotation_activation = torch.nn.functional.normalize
'''
self.scaling_activation = torch.exp:这行代码将指数函数 torch.exp 赋值给了 self.scaling_activation。这意味着在网络中,会使用指数函数作为缩放操作的激活函数。

self.scaling_inverse_activation = torch.log:这行代码将对数函数 torch.log 赋值给了 self.scaling_inverse_activation。这表示在网络中,会使用对数函数作为缩放的逆操作的激活函数。

self.covariance_activation = build_covariance_from_scaling_rotation:这行代码将一个函数 build_covariance_from_scaling_rotation 赋值给了 self.covariance_activation。这可能是一个自定义的函数,用于构建协方差矩阵,该函数可能会使用了缩放和旋转操作。

self.opacity_activation = torch.sigmoid:这行代码将 sigmoid 函数 torch.sigmoid 赋值给了 self.opacity_activation。这表示在网络中,会使用 sigmoid 函数作为不透明度的激活函数。

self.inverse_opacity_activation = inverse_sigmoid:这行代码将一个函数 inverse_sigmoid 赋值给了 self.inverse_opacity_activation。这可能是一个自定义的函数,用于计算 sigmoid 函数的逆操作。

self.rotation_activation = torch.nn.functional.normalize:这行代码将归一化函数 torch.nn.functional.normalize 赋值给了 self.rotation_activation。这表示在网络中,会使用归一化函数作为旋转操作的激活函数。
'''

点云数据的处理

初始化参数的含义:

def __init__(self, sh_degree: int):
    # 初始化球谐函数相关的度数
    # 初始化当前活动的球谐函数度数为 0,并将最大球谐函数度数设置为传入的 sh_degree 参数。
    self.active_sh_degree = 0
    self.max_sh_degree = sh_degree

    # 初始化存储点、球谐函数系数、缩放、旋转、不透明度等的张量为空张量
    self._xyz = torch.empty(0)
    self._features_dc = torch.empty(0)
    self._features_rest = torch.empty(0)
    self._scaling = torch.empty(0)
    self._rotation = torch.empty(0)
    self._opacity = torch.empty(0)
    
    # 初始化高斯分布投影后的最大二维半径、梯度累积器(用于辨别是否需要新增和删除高斯)和分母张量(表示统计了多少次累计梯度,最后要把这个分母张量除掉)为空张量
    self.max_radii2D = torch.empty(0)
    self.xyz_gradient_accum = torch.empty(0)
    self.denom = torch.empty(0)

    # 初始化优化器optimizer为 None
    self.optimizer = None
    
    # 初始化密度百分比和空间学习率缩放因子(用于处理不同参数对学习率的要求)
    self.percent_dense = 0
    self.spatial_lr_scale = 0

    # 调用设置函数的方法进行必要的初始化
    self.setup_functions()

scene/gaussian_model的create_from_pcd

def create_from_pcd(self, pcd : BasicPointCloud, spatial_lr_scale : float):
    self.spatial_lr_scale = spatial_lr_scale
    
    # 将点云数据中的点坐标转换为 PyTorch 张量,并放置在 GPU 上进行加速处理
    fused_point_cloud = torch.tensor(np.asarray(pcd.points)).float().cuda()
    
    '''
    球谐函数这一堆写在另一个文件里。
    '''
    
    print("Number of points at initialisation : ", fused_point_cloud.shape[0])
    
    # 计算点云中每个点与原点的欧氏距离的平方,并将其限制在一个最小值以上,以避免出现除以零的情况
    '''
    这行代码使用了函数 distCUDA2 来计算点云中每个点之间的距离,并将结果存储在 dist2 变量中。
	torch.from_numpy(np.asarray(pcd.points)).float().cuda() 将点云数据转换为 PyTorch 张量,并将其移到 GPU 上。
	torch.clamp_min 函数用于将 dist2 中的所有元素的最小值限制为 0.0000001,以确保不会出现零距离。	
    '''
    dist2 = torch.clamp_min(distCUDA2(torch.from_numpy(np.asarray(pcd.points)).float().cuda()), 0.0000001)
    
    '''
    这行代码首先计算了 dist2 中每个元素的平方根,然后取其自然对数。
[..., None] 用于在张量的最后一个维度上添加一个新的维度。
repeat(1, 3) 表示沿着第一个维度将张量复制三次,以便将其扩展为与 fused_point_cloud 相同的形状,其中 fused_point_cloud 是点云的坐标。
最终,scales 是一个与 fused_point_cloud 具有相同形状的张量,用于存储每个点的缩放因子。
    '''
    scales = torch.log(torch.sqrt(dist2))[...,None].repeat(1, 3)
    
    '''
    这行代码创建了一个形状为 (点数, 4) 的全零张量 rots,用于存储点云中每个点的旋转信息。
每个点的旋转信息是一个四维向量,其中第一个元素为1,其余元素为0,表示点云中的每个点都没有旋转。
    '''
    rots = torch.zeros((fused_point_cloud.shape[0], 4), device="cuda")
    
    '''
    这行代码将 rots 张量的第一列(即第一个元素)设置为1,以表示每个点的旋转信息中的第一个元素为1,其余元素为0,即单位四元数。
    '''
    rots[:, 0] = 1
    
    # 计算每个点的不透明度,这里使用了一个 sigmoid 函数的逆函数
    opacities = inverse_sigmoid(0.1 * torch.ones((fused_point_cloud.shape[0], 1), dtype=torch.float, device="cuda"))
    
    # 将点云的坐标、特征、尺度、旋转和不透明度分别存储为对象的参数,并设置为可训练
    self._xyz = nn.Parameter(fused_point_cloud.requires_grad_(True))
    self._features_dc = nn.Parameter(features[:,:,0:1].transpose(1, 2).contiguous().requires_grad_(True))
    self._features_rest = nn.Parameter(features[:,:,1:].transpose(1, 2).contiguous().requires_grad_(True))
    self._scaling = nn.Parameter(scales.requires_grad_(True))
    self._rotation = nn.Parameter(rots.requires_grad_(True))
    self._opacity = nn.Parameter(opacities.requires_grad_(True))
    
    # 初始化一个用于存储二维最大半径的张量,其形状与点云的数量相同
    self.max_radii2D = torch
当室外温度数据的时间间隔室内温度数据的时间间隔不一致时,要使室外温度数据变得更密集,你可以采取以下几种策略: 1. **重新采样(Resampling)**: - 使用数据插值(如线性插值或基于实际差值的插值)填补两个连续记录之间的时间点,生成新的室外温度数据。 - C++库如Poco、Boost或其他科学计算库可能提供这样的功能。 ```cpp // 假设你有一个包含时间戳室外温度的数据结构 struct OutdoorTempData { std::chrono::system_clock::time_point timestamp; double temperature; }; // 使用插值函数 double interpolate(double start_temp, double end_temp, double time_diff, double target_time) { // 插值逻辑 } std::vector<OutdoorTempData> densify_data(const std::vector<OutdoorTempData>& original_data) { std::vector<OutdoorTempData> densified; for (const auto& data : original_data) { if (!densified.empty() && densified.back().timestamp < data.timestamp + std::chrono::seconds(新间隔)) { densified.back().temperature = interpolate(densified.back().temperature, data.temperature, densified.back().timestamp.time_since_epoch(), data.timestamp.time_since_epoch()); } else { densified.push_back(data); } } return densified; } ``` 2. **数据融合(Data Aggregation)**: - 如果原始数据是每N分钟收集一次,而你想改为每5分钟,你可以合并相邻的N分钟内的数据平均值。 ```cpp double aggregate_temperature(const std::vector<OutdoorTempData>& chunk) { double sum = 0; for (const auto& temp : chunk) { sum += temp.temperature; } return sum / chunk.size(); } std::vector<OutdoorTempData> densify_data_by_aggregation(const std::vector<OutdoorTempData>& original_data, int new_interval_minutes) { std::vector<OutdoorTempData> densified; for (size_t i = 0; i < original_data.size(); i += new_interval_minutes) { auto chunk = original_data.substr(i, new_interval_minutes); // 获取连续的新间隔长度数据 densified.push_back({chunk[0].timestamp, aggregate_temperature(chunk)}); } return densified; } ``` 3. **实时同步(Real- 如果有可能,可以尝试调整采集设备或通信系统的设置,使其按新的时间间隔进行数据传输。 无论哪种方法,你需要考虑数据质量误差引入的风险,并根据具体的应用场景选择最合适的处理方式。如果原始数据量非常大,可能还需要考虑性能优化,比如使用并行化来加速数据处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值