3D Gaussian Splatting
3DGS原理
框架图

- SfM
Points:基于
RGB图像,用SfM(Structure from Motion)算法生成初始化点云(实际应用中使用colmap)。 - Initialization:基于初始化点云进行
3D Gaussian椭球集的创建。 - Projection:基于相机位姿,将椭球投影到
2D图像空间中。 - Differentiable Tile
Rasterizer:基于图形块
Tile进行光栅化图像渲染。 - Gradient
Flow:生成的图像和真实图像比较计算
loss,反向传播更新参数。 - Adaptive Density
Control:自适应密度控制将
3D高斯基元进行参数优化。
3DGS椭球集的创建
初始化点云即为3DGS的Dataset。
如何利用
SfM初始化点云? (colmap原理)
从多个图像(视频截取多个帧)提取特征点;不同图像的特征点进行匹配;建立两两图像的对应关系;利用像素坐标、相机参数计算三维点坐标;推断相机位姿(移动轨迹);恢复三维结构。
接下来将点云扩展为3D Gaussian并设置参数。
$$
G(x)=e^{-\frac{1}{2}(x-\sigma)^T\sum^{-1}(x-\sigma)}
$$ 其中,位置信息为σ(坐标),形状信息为∑(协方差矩阵)。3D Gaussian具有良好的几何性质,中心点不透明度最大,边缘随着中心点偏离,不透明度降低,且线性变换后仍为高斯函数,方便几何变换建模。

而协方差矩阵可拆解为: ∑ = RSSTRT
其中,R为旋转矩阵(正交矩阵),S为缩放矩阵(对角矩阵)。对角矩阵和对角矩阵的转置的乘积即为对角线元的平方和,控制大小缩放。旋转矩阵为正交矩阵,从x,y,z三个分量控制3D椭球的旋转。
$$
R_x(\theta)=\begin{bmatrix}
1 & 0 & 0\\
0 & \cos\theta & -\sin\theta\\
0 & \sin\theta & \cos\theta
\end{bmatrix}\\
RR^T=E(大小不变,根据\theta在坐标轴中旋转)
$$ 最终,3D Gaussians包含的参数有:

如何通过球谐函数确认颜色信息?
SH的基函数可以表示为:

SH基函数模拟光强分布,其具有正交性互不干扰,维数越高和原先的图形越接近,根据系数加权和得到最终结果,而方位角对应RGB像素值,由此来模拟光照和色彩。

缩放矩阵S如何确定缩放的程度?
利用simple-knn算法,找到k个最近欧氏距离最近邻点。 $$
\sum =
\frac{1}{k-1}\sum_{j=1}^{k}(x_j-\sigma)(x_j-\sigma)^T,\sigma为坐标平均值
$$
我们通过奇异值分解SVD∑ = USUT,可得到缩放程度为$\sqrt{s}$,旋转矩阵为U,进而初始化为3D高斯椭球。
3DGS椭球投影
先学习坐标系变换。

- 世界坐标系[(xw, yw, zw)](真实世界中物体的坐标,原点的选取取决于具体情况)
- 相机坐标系[(xc, yc, zc)](在相机上建立)
- 图像坐标系[(x, y)](描述相机到图像的投影投射)
- 像素坐标系[(u, v)](确定像点坐标)
世界 to 相机 $$ \begin{bmatrix} x_c\\y_c\\z_c \end{bmatrix}=R\begin{bmatrix} x_w\\y_w\\z_w \end{bmatrix}+t $$ 其中,R为旋转矩阵,t为平移矩阵。
相机 to 图像 $$ \begin{bmatrix} x_c\\y_c\\z_c \end{bmatrix}=z_c\begin{bmatrix} x\\y\\1 \end{bmatrix} $$ zc为物体在相机坐标系中的深度,利用相似三角形的性质进行一次缩放变换。
图像 to 像素 $$ 相机内参k = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix}\\ \begin{bmatrix} u\\v\\1 \end{bmatrix}=k\begin{bmatrix} x\\y\\1 \end{bmatrix}\\ u = xf_x+c_x,v=yf_y+c_y $$ 其中fx,fy为焦距,cx,cy为主点,即经历了一次缩放变换和一次平移变换。
- 模型变换:将物体从局部坐标系内旋转、缩放、平移到我们定义的世界坐标系内
- 视图变换:从世界坐标系转到相机坐标系
- 投影变换:从相机坐标系变换到归一化坐标系(图像坐标系)
- 视口变换:归一化坐标系计算像素坐标


拥有了这些前置知识,我们可以推导出3DGS的投影过程:

3D Gaussian椭圆中心点可通过上述计算得到2D Gaussian的椭圆中心点。
其中,2D Gaussian的协方差矩阵可以这样计算: $$
\sum{'}=JW\sum W^T J^T \\ J=\frac{∂(u,v)}{∂(x,y,z)}
$$ 其中,W为视图变换矩阵(世界坐标系到相机坐标系,旋转),J为仿射近似的雅可比矩阵,(u, v)为投影坐标,(x, y, z)为3D位置P,隐含了仿射变换中的线性部分。
Tile_based光栅化图像渲染
先将绘制图像离散化(一张图像分为多个16*16像素块Tile)。

并行遍历计算所有椭球,查看涉及哪些
Tile,每个Tile分配ID,根据TileID和depth生成索引。先按
Tile ID,再按depth升序排序。后面涉及不透明度的计算,由先splat的椭球进行叠加,而且远端先splat特征容易丢失。二维协方差矩阵
Conv2D,2D椭圆中心像素坐标X计算alpha。
$$
\alpha_i^{'}=\alpha*exp(-\frac{1}{2}(x_i^{'}-\sigma_i^{'})^T{\sum}_i^{'-1}(x_i^{'}-\sigma_i^{'}))
$$ *
指数部分是高斯函数的概率密度值,由此可推导公式,其中累乘部分为先前splat图层的连接,模拟不透明度。
$$
c=\sum_{i\in N}c_i\alpha_i^{'}\prod_{j=1}^{i-1}(1-a_j^{'})
$$ 
损失计算
L = (1 − t)L1 + tLSSIM
L1代表M个像素的绝对灰度值误差。 $$
\frac{1}{M}\sum_{i=1}^{M}|I(i)-I^{'}(i)|
$$ SSIM代表图像之间的相似度。 $$
\text{SSIM}(x, y) = \underbrace{[l(x, y)]^\alpha}_{\text{亮度}} \cdot
\underbrace{[c(x, y)]^\beta}_{\text{对比度}} \cdot \underbrace{[s(x,
y)]^\gamma}_{\text{结构}}\\
$$ 其中 (x, y)
为待比较的图像块(通常为局部窗口),(α, β, γ)
为权重参数(默认均为1)。
先将图像划分为N的局部窗口(通常N=8或11),接着对每个窗口计算以下值。
- 均值(亮度): $$ \mu_x = \frac{1}{N^2} \sum_{i=1}^N \sum_{j=1}^N x(i,j) $$
- 方差(对比度): $$ \sigma_x^2 = \frac{1}{N^2 - 1} \sum_{i=1}^N \sum_{j=1}^N (x(i,j) - \mu_x)^2 $$
- 协方差(结构): $$ \sigma_{xy} = \frac{1}{N^2 - 1} \sum_{i=1}^N \sum_{j=1}^N (x(i,j) - \mu_x)(y(i,j) - \mu_y) $$
计算所有窗口的SSIM,并对所有窗口的SSIM取均值,得到全局SSIM:
$$
\text{SSIM}(x, y) = \frac{(2\mu_x\mu_y + C_1)(2\sigma_{xy} +
C_2)}{(\mu_x^2 + \mu_y^2 + C_1)(\sigma_x^2 + \sigma_y^2 + C_2)} \\
text{MSSIM} = \frac{1}{M} \sum_{k=1}^M \text{SSIM}(x_k, y_k)
$$
自适应密度控制

重建不充分的区域在反向传播中梯度更大,一般分为欠重建和过重建。
- 欠重建:
3D高斯基元覆盖不足 - 过重建:不够细化,需要分割
这两种情况需要对3D高斯基元进行参数优化(删除不透明度低于阈值或体积过大的基元)
如何跑通3DGS代码
小白向Windows操作系统,老手
Linux照着README做就好了
一、环境配置
1.下载仓库
https://github.com/graphdeco-inria/gaussian-splatting
2.下载必要的依赖库
在命令行内输入:
cd <Your Location> # 仓库位置
git clone https://github.com/graphdeco-inria/diff-gaussian-rasterization.git submodules/diff-gaussian-rasterization
git clone https://github.com/simon-knuth/simple-knn.git submodules/simple-knn
git clone https://github.com/NVlabs/fused-ssim.git submodules/fused-ssim
如果下载不了,可以手动在github下载。simple-knn库疑似仓库被删除了,建议去其他3DGS相关开源仓库里找。
3.配置编译环境
官网下载cuda 11.8/cudnn;官网下载Visual Studio Installer,启动后下载Visual Studio Community 2019,勾选和C/C++编译相关的;官网下载CMake 3.24。
随后,在环境变量-系统变量-PATH中添加这两条:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64
C:\Program Files\cmake-3.24.0-rc2-windows-x86_64\bin
具体路径根据你的文件地址自行调整。
4.配置conda环境
conda env create --file environment.yml
正常来说,可以一步到位,但是可能会遇到两个问题:
一,在Solving environment处,运行速度极慢,是因为镜像源配置问题,根据清华源文档,我们在.condarc文件里复制这一段:
channels:
- defaults
show_channel_urls: true
default_channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
custom_channels:
conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
二,安装iff-gaussian-rasterization和fused-ssim报错,大概率是编译环境配置错误,按这个顺序检查:
cuda版本是否为11.8Visual Studio是否有其他版本(如2022)的残余
在命令行中执行:
conda activate gaussian_splatting
pip install opencv-python joblib
cd submodules/diff-gaussian-rasterization
pip install .
cd ..\simple-knn
pip install .
cd ..\fused-ssim
pip install .
二、Colmap
在官网下载colmap,并根据文件地址在环境变量-系统变量-PATH添加:
C:\Users\SaintCHEN\Desktop\Repository\gaussian-splatting\external\COLMAP-3.8-windows-cuda
首先在项目目录创建一个/data目录,存放你的数据集,在/data中创建一个/input,放入要训练的图片。
然后,打开COLMAP.bat,打开File-New Project,在data目录下新建一个数据库文件database.db,image即为要训练的图片/data/input。
接着,在Processing中依次点击Feature extraction,Feature matching,得到初始点云。
最后,打开File-Save Model,在/data中创建一个/sparse,保存即可。
三、训练和渲染
先在仓库创建一个output文件夹,可以再新建一个/test,存放我们的训练数据。
打开终端,依次输入:
conda activate gaussian_splatting
python convert.py -s <Your Location> # 填写输入目录,即为~/data,解析colmap数据重建
python train.py -s <Your Location 1> -m <Your Location 2> # 填写输入和输出目录,即为data与output/test,训练高斯基元的参数
python render.py -m <Your Location> # 填写输出目录,即output/test,渲染
最后你可以在output\test\train(test)\ours_30000\renders中查看渲染效果。