diff --git a/scene/gaussian_model.py b/scene/gaussian_model.py index b92e539..367ddc6 100644 --- a/scene/gaussian_model.py +++ b/scene/gaussian_model.py @@ -25,53 +25,56 @@ class GaussianModel: def setup_functions(self): """ - 定义和初始化处理高斯体模型参数的 激活函数 + 定义和初始化处理高斯体模型参数的 激活函数 """ - # 定义 从尺度、旋转构建3D高斯的 协方差矩阵 的函数 def build_covariance_from_scaling_rotation(scaling, scaling_modifier, rotation): - L = build_scaling_rotation(scaling_modifier * scaling, rotation) # 从尺度、尺度的缩放、旋转得到L矩阵 - actual_covariance = L @ L.transpose(1, 2) # 计算实际的协方差矩阵 - symm = strip_symmetric(actual_covariance) # 提取对称部分 + """ + 从 缩放因子、旋转四元数 构建 各3D高斯体的 协方差矩阵 + """ + L = build_scaling_rotation(scaling_modifier * scaling, rotation) # 从缩放因子、旋转四元数得到高斯体的变化,N 3 3 + actual_covariance = L @ L.transpose(1, 2) # 计算实际的 协方差矩阵 + symm = strip_symmetric(actual_covariance) # 提取上半对角元素 return symm # 初始化一些激活函数 - self.scaling_activation = torch.exp # 用exp函数,确保尺度参数非负 - self.scaling_inverse_activation = torch.log # 尺度的逆激活函数,用于梯度回传 + self.scaling_activation = torch.exp # 缩放因子的激活函数,exp函数,确保缩放因子非负 + self.scaling_inverse_activation = torch.log # 缩放因子的逆激活函数,用于梯度回传,log函数 - self.covariance_activation = build_covariance_from_scaling_rotation # 协方差矩阵的激活函数 + self.covariance_activation = build_covariance_from_scaling_rotation # 协方差矩阵的激活函数(实际未使用激活函数,直接构建) - self.opacity_activation = torch.sigmoid # 用sigmoid函数,确保不透明度在0到1之间 + self.opacity_activation = torch.sigmoid # 不透明的激活函数,sigmoid函数,确保不透明度在0到1之间 self.inverse_opacity_activation = inverse_sigmoid # 不透明度的逆激活函数 - self.rotation_activation = torch.nn.functional.normalize # 用于标准化旋转参数的函数 + self.rotation_activation = torch.nn.functional.normalize # 旋转四元数的激活函数,归一化函数(取模) def __init__(self, sh_degree : int): """ - 初始化3D高斯模型的参数 + 3D高斯模型的各参数 初始化为0或空 sh_degree: 设定的 球谐函数的最大阶数,默认为3,用于控制颜色表示的复杂度 """ - self.active_sh_degree = 0 # 当前激活的球谐阶数,初始为0 + self.active_sh_degree = 0 # 当前球谐函数的阶数,初始为0 self.max_sh_degree = sh_degree # 允许的最大球谐阶数j - # 初始化3D高斯模型的各项参数 - self._xyz = torch.empty(0) # 3D高斯的 中心位置(均值) - self._features_dc = torch.empty(0) # 第一个球谐系数,用于表示基础颜色 - self._features_rest = torch.empty(0) # 其余球谐系数,用于表示颜色的细节和变化 - self._scaling = torch.empty(0) # 3D高斯的尺度,控制高斯的形状 - self._rotation = torch.empty(0) # 3D高斯的旋转(一系列四元数) - self._opacity = torch.empty(0) # 3D高斯的不透明度(sigmoid前的),控制可见性 - self.max_radii2D = torch.empty(0) # 在2D投影中,每个高斯的最大半径 + self._xyz = torch.empty(0) # 各3D高斯的 中心位置 - self.xyz_gradient_accum = torch.empty(0) # 累积3D高斯中心位置的梯度,当它太大的时候要对Gaussian进行分裂,小时代表under要复制 - self.denom = torch.empty(0) # 与累积梯度配合使用,表示统计了多少次累积梯度,算平均梯度时除掉这个(denom = denominator,分母) + self._features_dc = torch.empty(0) # 球谐函数的直流分量,第一个元素,用于表示基础颜色 + self._features_rest = torch.empty(0) # 球谐函数的高阶分量,用于表示颜色的细节和变化 + + self._scaling = torch.empty(0) # 各3D高斯的 缩放因子,控制高斯的形状 + self._rotation = torch.empty(0) # 各3D高斯的 旋转四元数 + self._opacity = torch.empty(0) # 各3D高斯的不透明度(sigmoid前的),控制可见性 + self.max_radii2D = torch.empty(0) # 各3D高斯投影到2D平面上的 最大半径 + + self.xyz_gradient_accum = torch.empty(0) # 3D高斯中心位置 梯度的累及值,当它太大的时候要对Gaussian进行分裂,小时代表under要复制 + self.denom = torch.empty(0) # 与累积梯度配合使用,表示统计了多少次累积梯度,用于计算每个高斯体的平均梯度时需除以它(denom = denominator,分母) self.optimizer = None # 优化器,用于调整上述参数以改进模型(论文中采用Adam,见附录B Algorithm 1的伪代码) - self.percent_dense = 0 # 控制Gaussian密集程度的超参数 - self.spatial_lr_scale = 0 # 位置坐标的学习率要乘上这个,抵消在不同尺度下应用同一个学习率带来的问题 + self.percent_dense = 0 # 百分比密度,控制3D高斯的密度 + self.spatial_lr_scale = 0 # 各3D高斯的位置学习率的变化因子,位置的学习率 乘以它,以抵消在不同尺度下应用同一个学习率带来的问题 - # 调用 setup_functions,初始化处理高斯体模型参数的 激活函数 + # 初始化高斯体模型各参数的 激活函数 self.setup_functions() def capture(self): @@ -109,11 +112,11 @@ class GaussianModel: self.optimizer.load_state_dict(opt_dict) @property - def get_scaling(self): + def get_scaling(self): # 获取的是激活后的 缩放因子 return self.scaling_activation(self._scaling) @property - def get_rotation(self): + def get_rotation(self): # 获取的是激活后的 旋转四元数 return self.rotation_activation(self._rotation) @property @@ -127,13 +130,14 @@ class GaussianModel: return torch.cat((features_dc, features_rest), dim=1) @property - def get_opacity(self): + def get_opacity(self): # 获取的是激活后的 不透明度 return self.opacity_activation(self._opacity) def get_covariance(self, scaling_modifier = 1): return self.covariance_activation(self.get_scaling, scaling_modifier, self._rotation) def oneupSHdegree(self): + # 当前球谐函数的阶数 < 规定的最大阶数,则 阶数+1 if self.active_sh_degree < self.max_sh_degree: self.active_sh_degree += 1 @@ -141,17 +145,17 @@ class GaussianModel: """ 从稀疏点云数据pcd 初始化模型参数 pcd: 稀疏点云,包含点的位置和颜色 - spatial_lr_scale: 空间学习率缩放因子,影响 位置坐标参数的学习率 + spatial_lr_scale: 位置学习率的 变化因子 """ - # 根据scene.Scene.__init__ 以及 scene.dataset_readers.SceneInfo.nerf_normalization,即scene.dataset_readers.getNerfppNorm的代码, # 这个值似乎是训练相机中离它们的坐标平均值(即中心)最远距离的1.1倍,根据命名推断应该与学习率有关,防止固定的学习率适配不同尺度的场景时出现问题。 self.spatial_lr_scale = spatial_lr_scale - # 将点云的 位置 和 颜色 数据从numpy数组转换为PyTorch张量,并传送到CUDA设备上 - fused_point_cloud = torch.tensor(np.asarray(pcd.points)).float().cuda() # 稀疏点云的3D坐标,大小为(P, 3) - fused_color = RGB2SH(torch.tensor(np.asarray(pcd.colors)).float().cuda()) # 球谐的直流分量,大小为(P, 3), - # RGB2SH(x) = (x - 0.5) / 0.28209479177387814看样子pcd.colors的原始范围应该是0到1。0.28209479177387814是1 / (2*sqrt(pi)),是直流分量Y(l=0,m=0)的值 + # 点云的3D位置从array转换为tensor,并放到cuda上,(N, 3) + fused_point_cloud = torch.tensor(np.asarray(pcd.points)).float().cuda() + # 点云的颜色从RGB array转换为tensor,放到cuda上,再转为球谐函数直流分量系数,(N, 3) + fused_color = RGB2SH(torch.tensor(np.asarray(pcd.colors)).float().cuda()) + # 初始化存储 球谐系数 的张量,RGB三通道球谐的所有系数,每个通道有(max_sh_degree + 1) ** 2个球谐系数 features = torch.zeros((fused_color.shape[0], 3, (self.max_sh_degree + 1) ** 2)).float().cuda() # (P, 3, 16) diff --git a/utils/general_utils.py b/utils/general_utils.py index 87ad557..76896da 100644 --- a/utils/general_utils.py +++ b/utils/general_utils.py @@ -78,13 +78,13 @@ def get_expon_lr_func( def strip_lowerdiag(L): """ - 从协方差矩阵中提取六个独立参数 - :param L: 协方差矩阵 - :return: 六个独立参数组成的张量 + 从协方差矩阵中提取6个上半对角元素,节省内存 + [ _ _ _ ] + [ _ _ ] + [ _ ] """ - uncertainty = torch.zeros((L.shape[0], 6), dtype=torch.float, device="cuda") + uncertainty = torch.zeros((L.shape[0], 6), dtype=torch.float, device="cuda") # N 6 - # 提取协方差矩阵的独立元素 uncertainty[:, 0] = L[:, 0, 0] uncertainty[:, 1] = L[:, 0, 1] uncertainty[:, 2] = L[:, 0, 2] @@ -95,15 +95,15 @@ def strip_lowerdiag(L): def strip_symmetric(sym): """ - 提取协方差矩阵的对称部分 + 提取协方差矩阵的上半对角元素 sym: 协方差矩阵 - return: 对称部分 + return: 上半对角元素 """ return strip_lowerdiag(sym) def build_rotation(r): ''' - 从旋转四元数 -> 单位化 -> 3x3的旋转矩阵 + 旋转四元数 -> 单位化 -> 3x3的旋转矩阵 ''' norm = torch.sqrt(r[:,0]*r[:,0] + r[:,1]*r[:,1] + r[:,2]*r[:,2] + r[:,3]*r[:,3]) @@ -129,20 +129,20 @@ def build_rotation(r): def build_scaling_rotation(s, r): """ - 构建3D高斯模型的尺度-旋转矩阵 - s: 尺度参数 - r: 旋转参数 + 构建3D高斯模型的 缩放-旋转矩阵 + s: 缩放因子, N 3 + r: 旋转四元素, N 4 return: 尺度-旋转矩阵 """ - L = torch.zeros((s.shape[0], 3, 3), dtype=torch.float, device="cuda") # 初始化尺度矩阵 - R = build_rotation(r) # 四元数 -> 旋转矩阵 + L = torch.zeros((s.shape[0], 3, 3), dtype=torch.float, device="cuda") # 初始化缩放矩阵为0,N 3 3 + R = build_rotation(r) # 旋转四元数 -> 旋转矩阵,N 3 3 - # 设置尺度矩阵的对角线元素 + # 构建缩放矩阵,其对角线元素对应为缩放因子的s1, s2, s3 L[:,0,0] = s[:,0] L[:,1,1] = s[:,1] L[:,2,2] = s[:,2] - L = R @ L # 应用旋转 + L = R @ L # 高斯体的变化:旋转 矩阵乘 缩放 return L def safe_state(silent): diff --git a/utils/sh_utils.py b/utils/sh_utils.py index ee17f8e..efc3f60 100644 --- a/utils/sh_utils.py +++ b/utils/sh_utils.py @@ -23,7 +23,7 @@ import torch -C0 = 0.28209479177387814 +C0 = 0.28209479177387814 # 球谐函数直流分量的值,sqrt(1 / (4*pi)),是0阶的球谐函数,即直流分量Y(l=0,m=0)的值 C1 = 0.4886025119029199 C2 = [ 1.0925484305920792, @@ -61,14 +61,14 @@ def eval_sh(deg, sh, dirs): Works with torch/np/jnp. ... Can be 0 or more batch dimensions. Args: - deg: int SH deg. Currently, 0-3 supported - sh: jnp.ndarray SH coeffs [..., C, (deg + 1) ** 2] - dirs: jnp.ndarray unit directions [..., 3] + deg: 球谐函数的 阶数,这里可能为 0-3 + sh: 球谐函数的 系数 [..., C, (deg + 1) ** 2] + dirs: 方向值 jnp.ndarray unit directions [..., 3] Returns: [..., C] """ assert deg <= 4 and deg >= 0 - coeff = (deg + 1) ** 2 + coeff = (deg + 1) ** 2 # 球谐函数当前阶数要求的系数 个数 assert sh.shape[-1] >= coeff result = C0 * sh[..., 0] @@ -113,9 +113,9 @@ def eval_sh(deg, sh, dirs): def RGB2SH(rgb): """ - 将RGB颜色值转换为球谐系数C0项的系数 - :param rgb: RGB颜色值 - :return: 转换后的球谐系数C0项的系数 + 将RGB颜色值 转换为 球谐系数直流分量的系数 + rgb: RGB颜色值 + C0:球谐函数直流分量的值,sqrt(1 / (4*pi)),是0阶的球谐函数,即直流分量Y(l=0,m=0)的值 """ return (rgb - 0.5) / C0