3DGS原理&运行


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椭球集的创建

初始化点云即为3DGSDataset

如何利用SfM初始化点云? (colmap原理)

从多个图像(视频截取多个帧)提取特征点;不同图像的特征点进行匹配;建立两两图像的对应关系;利用像素坐标、相机参数计算三维点坐标;推断相机位姿(移动轨迹);恢复三维结构。

接下来将点云扩展为3D Gaussian并设置参数。

$$ G(x)=e^{-\frac{1}{2}(x-\sigma)^T\sum^{-1}(x-\sigma)} $$ 其中,位置信息为σ(坐标),形状信息为(协方差矩阵)。3D Gaussian具有良好的几何性质,中心点不透明度最大,边缘随着中心点偏离,不透明度降低,且线性变换后仍为高斯函数,方便几何变换建模。

而协方差矩阵可拆解为: ∑ = RSSTRT 其中,R为旋转矩阵(正交矩阵),S为缩放矩阵(对角矩阵)。对角矩阵和对角矩阵的转置的乘积即为对角线元的平方和,控制大小缩放。旋转矩阵为正交矩阵,从xyz三个分量控制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 $$ 其中fxfy为焦距,cxcy为主点,即经历了一次缩放变换和一次平移变换。

  • 模型变换:将物体从局部坐标系内旋转、缩放、平移到我们定义的世界坐标系内
  • 视图变换:从世界坐标系转到相机坐标系
  • 投影变换:从相机坐标系变换到归一化坐标系(图像坐标系)
  • 视口变换:归一化坐标系计算像素坐标

拥有了这些前置知识,我们可以推导出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,根据TileIDdepth生成索引。

  • 先按Tile ID,再按depth升序排序。后面涉及不透明度的计算,由先splat的椭球进行叠加,而且远端先splat特征容易丢失。

  • 二维协方差矩阵Conv2D2D椭圆中心像素坐标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=811),接着对每个窗口计算以下值。

  1. 均值(亮度)$$ \mu_x = \frac{1}{N^2} \sum_{i=1}^N \sum_{j=1}^N x(i,j) $$
  2. 方差(对比度)$$ \sigma_x^2 = \frac{1}{N^2 - 1} \sum_{i=1}^N \sum_{j=1}^N (x(i,j) - \mu_x)^2 $$
  3. 协方差(结构)$$ \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-rasterizationfused-ssim报错,大概率是编译环境配置错误,按这个顺序检查:

  • cuda版本是否为11.8
  • Visual 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.dbimage即为要训练的图片/data/input

接着,在Processing中依次点击Feature extractionFeature 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中查看渲染效果。


文章作者: Sa1ntCHEN
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Sa1ntCHEN !
  目录