Paper: Tang J, Ren J, Zhou H, et al. Dreamgaussian: Generative gaussian splatting for efficient 3d content creation[J]. arXiv preprint arXiv:2309.16653, 2023.
Introduction: https://dreamgaussian.github.io/
Code: https://github.com/dreamgaussian/dreamgaussian
DreamGaussian 是 ICLR 2024 Oral 论文,能够在短短 2 分钟内完成 Image-to-3D 和 Text-to-3D 任务,根据文本或 2D 图像重建出高质量的纹理 3D 网格。
DreamGaussian 基于 3D Gaussian Splatting,使用 2D diffusion 作先验优化三维场景。为了得到更清晰的渲染效果,还设计算法从 3D-GS 中提取 mesh 以细化纹理。DreamGaussian 不仅能细致还原物体的几何形状,还能捕捉其表面的细微纹理和色彩,展现了惊人的细节和还原度。
本文参考 【三维重建】DreamGaussian:高斯splatting的单视图3D内容生成(原理+代码),更多参考资料如下:
文中提出了一种新的 3D 内容生成模型,通过将 Gaussian Splatting 应用到生成任务中,显著减少了 2D lifting 方法的生成时间。以往的 NeRF 表示法难以优化空白空间,而生成式 Gaussian Splatting 可以简化优化空间,从而达到较高的生成效率。
生成式 NeRF:NeRF 采用体积渲染,可以在只有二维监督下实现三维优化,已广泛用于三维重建和生成。但 NeRF 的优化过程需要耗费大量时间,尽管有 InstantNGP 等加速工作,但这只能缩减重建的时间,并不能降低渲染的时间消耗。
生成式 Gaussian Splatting:3D Gaussian Splatting 作为 NeRF 的替代三维场景表示方法,其快速可微光栅化实现了高效和高质量的渲染效果。因此 Dreamgaussian 将 3D Gaussian Splatting 引入 3D 内容生成任务,以实现高效的渲染。
由于 SDS 监督和致密化操作的模糊性,直接使用 3D-GS 生成的内容会比较模糊。想要清晰渲染就需要明确地细化纹理,就需要从 3D-GS 中提取精细的纹理多边形网格。因此 Dreamgaussian 设计了相应算法,通过局部密度查询从 3D-GS 中提取网格 (mesh)。
致密化 (densification) :3D-GS 的优化过程中,需要周期性地进行自适应控制,即对 under-reconstruction 和 over-reconstruction 的 Gaussians 进行复制或拆分的操作。对于高斯模型没有完全覆盖的几何体,复制高斯模型并将其沿位置梯度方向移动以覆盖几何体;对于高斯模型覆盖范围超出的几何体,拆分高斯模型至只覆盖几何体。
为了进一步增强纹理细节,增加了一个生成 UV 空间的细化阶段。鉴于直接应用隐空间 SDS Loss 会导致 UV 映射时过度饱和的块状伪影,参考 Sdedit 1,并进行图像空间监督。
UV 空间:一种二维纹理坐标系,用于定义纹理贴图在三维模型表面上的位置。在 UV 空间中,每个点都可以用一个 ( u , v ) (u, v) (u,v) 坐标来表示,其中 u u u 代表水平方向, v v v 代表垂直方向。这种映射关系可以通过纹理映射技术实现,将二维图像投影到三维模型的表面上。2
Sdedit:Stochastic Differential Editing,一种基于扩散模型的图像生成和编辑方法,使用随机微分方程 (stochastic differential equation) 迭代去噪来生成逼真的图像。Sdedit 不需要特定任务的训练或反演,可以自然地在真实感和可信度之间平衡,在完成图像合成和编辑的任务中性能明显优于 GAN。
如图所示,Dreamgaussian 先使用 3D Gaussian Splatting 建模 text / image 指示的内容,使用 SDS Loss 进行优化;然后从 Gaussians 中提取纹理网格;最后通过多轮计算 MSE Loss 细化网格上图像的纹理。
在三维空间中,通过随机采样初始化 Gaussians,随后使用 SDS 进行优化,并且周期性地对 Gaussians 进行致密化。在 2D diffusion 中,利用不同的 diffusion 先验 ϕ \phi ϕ 引导 SDS 去噪,并反向传播到三维 Gaussians 中。
记 3D GS 场景中的 Gaussian Θ i = { x i , s i , q i , α i , c i } \Theta_i=\{x_i, s_i, q_i, \alpha_i, c_i\} Θi={xi,si,qi,αi,ci},分别表示该 Gaussian 的三维位置、缩放矩阵、旋转矩阵、透明度和球谐系数(记颜色特征);训练过程中相机机位 p p p 渲染得到的 RGB 图像为 I R G B p I_{RGB}^{p} IRGBp,透明度为 I A p I_{A}^{p} IAp。
Image-to-3D 的输入是一张图像 I ~ R G B r \tilde I_{RGB}^{r} I~RGBr 和 mask I ~ A r \tilde I_{A}^{r} I~Ar。采用 Zero-1-to-3 3 作为二维 diffusion 先验,其 SDS Loss 如下:
∇ Θ L S D S = E t , p , ϵ [ ( ϵ ϕ ( I R G B p ; t , I ~ R G B r , Δ p ) − ϵ ) ∂ I R G B p ∂ Θ ] \nabla_{\Theta} \mathcal{L}_{\mathrm{SDS}}=\mathbb{E}_{t, p, \epsilon}\left[\left(\epsilon_\phi\left(I_{\mathrm{RGB}}^p ; t, \tilde{I}_{\mathrm{RGB}}^r, \Delta p\right)-\epsilon\right) \frac{\partial I_{\mathrm{RGB}}^p}{\partial \Theta}\right] ∇ΘLSDS=Et,p,ϵ[(ϵϕ(IRGBp;t,I~RGBr,Δp)−ϵ)∂Θ∂IRGBp]
I R G B p I_{RGB}^{p} IRGBp 和 I A p I_{A}^{p} IAp 的损失如下:
L R e f = λ R G B ∥ I R G B r − I ~ R G B r ∥ 2 2 + λ A ∥ I A r − I ~ A r ∥ 2 2 \mathcal{L}_{\mathrm{Ref}}=\lambda_{\mathrm{RGB}}\left\|I_{\mathrm{RGB}}^r-\tilde{I}_{\mathrm{RGB}}^r\right\|_2^2+\lambda_{\mathrm{A}}\left\|I_{\mathrm{A}}^r-\tilde{I}_{\mathrm{A}}^r\right\|_2^2 LRef=λRGB IRGBr−I~RGBr 22+λA IAr−I~Ar 22
Text-to-3D 的输入是一句文本 prompt。采用 Stable diffusion 作为先验,其 SDS Loss 如下:
∇ Θ L S D S = E t , p , ϵ [ ( ϵ ϕ ( I R G B p ; t , e ) − ϵ ) ∂ I R G B p ∂ Θ ] \nabla_{\Theta} \mathcal{L}_{\mathrm{SDS}}=\mathbb{E}_{t, p, \epsilon}\left[\left(\epsilon_\phi\left(I_{\mathrm{RGB}}^p ; t, e\right)-\epsilon\right) \frac{\partial I_{\mathrm{RGB}}^p}{\partial \Theta}\right] ∇ΘLSDS=Et,p,ϵ[(ϵϕ(IRGBp;t,e)−ϵ)∂Θ∂IRGBp]
作者观察到,即使使用较长的 SDS 训练迭代,生成的 GS 场景看起来还是较为模糊,缺少细节。这是因为 SDS Loss 的模糊性,在每个优化步骤提供了不连续的三维引导。因此作者在生成式 GS 的基础上设计了网格提取和纹理细化。
Dreamgaussian 将生成的 GS 场景转换成多边形网格 (mesh),从而才能进一步细化纹理。Dreamgaussian 的网格提取基于 block-wise 的局部密度查询 (local density query),并且对颜色进行逆映射 (color back-projection)。
为了提取网格的几何形状,需要一个密集的密度网格来应用 Marching Cubes 算法。GS 一个重要特征是在优化过程中,过大的 Gaussian 会被复制或分割,Dreamgaussian 利用这个特性来执行基于 block-wise 的密度查询。
先将 (−1,1)3 的三维空间划分为 163 个块,然后剔除中心位于每个局部块外的 Gaussians;在每个块内查询一个 83 个密集的网格,从而得到最终的 1283 个密集网格。对于网格位置 x x x 处的每个查询,将 Gaussians 的加权不透明度相加得到局部密度:
d ( x ) = ∑ i α i exp ( − 1 2 ( x − x i ) T Σ i − 1 ( x − x i ) ) d(\mathbf{x})=\sum_i \alpha_i \exp \left(-\frac{1}{2}\left(\mathbf{x}-\mathbf{x}_{\mathbf{i}}\right)^T \Sigma_i^{-1}\left(\mathbf{x}-\mathbf{x}_{\mathbf{i}}\right)\right) d(x)=i∑αiexp(−21(x−xi)TΣi−1(x−xi))
使用一个经验阈值 (empirical threshold) 通过 Marching Cubes 算法提取网格表面。采用 Decimation 和 Remeshing 对提取的网格进行后处理,使其光滑。
Marching Cubes 算法:一种计算机图形学中的算法,用于将三维数据转换为 mesh 模型。其主要原理是将三维数据分割为小的立方体,然后根据每个立方体内部的数据值确定其表面的形状。算法的具体步骤如下:
- 网格划分:将三维数据划分为边长为 h h h 的网格,每个网格包含 8 个顶点和 12 条棱,分别对应三维空间中的点和线段;
- 计算网格内部的标量值:对于每个网格,需要计算其内部 8 个顶点的标量值。对于坐标顶点 ( x , y , z ) (x,y,z) (x,y,z),可以表示其标量值为 f ( x , y , z ) f(x,y,z) f(x,y,z);
- 确定网格内部的等值面:根据网格内部的标量值,需要确定其内部的等值面,即标量值等于某个特定值的表面。在 Marching Cubes 算法中,通常将等值面的标量值设为 0;
- 计算等值面上的顶点:对于每个等值面,需要计算其上的顶点。这些顶点通常位于等值面的边界处,也就是位于两个不同标量值的网格之间的位置;
- 确定等值面的拓扑结构:根据等值面上的顶点,需要确定其拓扑结构。拓扑结构是指等值面上顶点之间的连接关系,通常使用三角形来表示;
- 生成三角形网格:根据等值面的拓扑结构,需要生成三角形网格。在 Marching Cubes 算法中,使用了一个预定义的查找表来确定每个等值面所对应的三角形网格;
在获得了网格几何形状后,将渲染的 RGB 图像反向投影到网格表面,并将其作为纹理。具体的做法是:先展开 mesh 的 UV 坐标,并初始化一个空的纹理图像;然后统一选择 8 个方位角和 3 个高度,加上顶部和底部视图来渲染相应的 RGB 图像。
这些 RGB 图像中的每个像素都可以根据 UV 坐标反向投影到纹理图像上,并且排除具有小相机空间 z 方向法线的像素,以避免网格边界上的不稳定投影。这个反向投影的纹理图像作为下一网格纹理微调阶段的初始化。
由于 SDS 的模糊性,从 Gaussian 中提取的 mesh 通常具有模糊的纹理。因此,Dreamgaussian 提出了第二阶段来细化纹理图像。然而,直接使用 SDS 损失直接微调 UV 空间往往会导致伪影,在 SDS 的模糊引导下,传播到每个 mipmap 级别的梯度会导致过饱和的颜色块:
Dreamgaussian 在模糊纹理的基础上,从任意相机机位 p p p 渲染模糊图像 I c o a r s e p I_{coarse}^{p} Icoarsep,然后使用随机噪声对图像进行扰动,并使用二维 diffusion 先验执行多步去噪过程 f ϕ ( ⋅ ) f_{\phi}(·) fϕ(⋅) 获得细化的图像:
I fine p = f ϕ ( I coarse p + ϵ ( t start ) ; t start , c ) I_{\text {fine}}^p=f_\phi\left(I_{\text {coarse}}^p+\epsilon\left(t_{\text {start}}\right) ; t_{\text {start}}, c\right) Ifinep=fϕ(Icoarsep+ϵ(tstart);tstart,c)
初始时间步长 t start t_{\text {start}} tstart 是特定用来限制噪声强度的,因此细化后的图像 I fine p I_{\text {fine}}^p Ifinep 可以在不破坏原始内容的情况下增强细节。然后再使用增强后的图像通过像素级的 MSE 损失来优化纹理:
L M S E = ∥ I fine p − I coarse p ∥ 2 2 \mathcal{L}_{\mathrm{MSE}}=\left\|I_{\text {fine }}^p-I_{\text {coarse }}^p\right\|_2^2 LMSE=∥Ifine p−Icoarse p∥22
DreamGaussian 可以在 2 分钟内根据文本或 2D 图像生成逼真的具有显式网格和纹理细节的 3D 物体,其效率是现有技术的十倍之多。更难能可贵的是,尽管处理速度极快,但它在输出模型的质量上却毫不妥协,下图是老算法和新算法的渲染效率比较 4:
Dreamgaussian 开源了 训练代码,也在 Colab 和 huggingface 上提供了 Demo,Colab 中分别展示 Image-to-3D 和 Text-to-3D 的效果,可以在线运行。下文克隆了源代码仓库进行复现:
实验过程:
根据 README 克隆仓库并安装依赖项;
图像预处理时,去除 test.png
背景并重新居中,然后保存为 256×256 像素的 RGBA 图像;
训练阶段,因为服务器上无图形界面的环境,因此使用 GUI 模式会报错:
试图安装图形界面并使用虚拟显示,未成功:
# 安装 Mesa 工具
sudo apt-get update
sudo apt-get install mesa-utils
# 设置虚拟显示
sudo apt-get install xvfb
xvfb-run python main.py --config configs/image.yaml input=data/test_rgba.png save_path=test
用无 GUI 模式进行训练,遇到 RuntimeError: Error building extension 'nvdiffrast_plugin_gl'
报错:
将 configs/text.yaml
和 configs/text_mv.yaml
中 force_cuda_rast
设置为 True 即可 5;
解决完上个报错,又出现新的 RuntimeError: Error building extension 'nvdiffrast_plugin_gl'
报错:
将 main.py
和 mesh_renderer.py
中 self.glctx = dr.RasterizeGLContext()
改为 self.glctx = dr.RasterizeCudaContext()
即可 6 7。至此,Dreamgaussian Image-to-3D 可以训练 gaussian 和 mesh 了;
可视化训练结果时,又出现新的 RuntimeError: Error building extension 'nvdiffrast_plugin_gl'
报错:
只需要在命令结尾加上可选项 --force_cuda_rast
8 即可。至此,Dreamgaussian Image-to-3D 可以可视化了;
完整训练指令如下:
### preprocess
python process.py data/test.png
### training gaussian stage
python main.py --config configs/image.yaml input=data/test_rgba.png save_path=test
### training mesh stage
python main2.py --config configs/image.yaml input=data/test_rgba.png save_path=test mesh=logs/test_mesh.obj
### visualization
kire logs/test_mesh.obj --save_video outputs/test_mesh.mp4 --wogui --force_cuda_rast # gaussian
kire logs/test.obj --save_video outputs/test.mp4 --wogui --force_cuda_rast # mesh
### evaluation of CLIP-similarity
python -m kiui.cli.clip_sim data/test_rgba.png logs/test_mesh.obj --force_cuda_rast # gaussian
python -m kiui.cli.clip_sim data/test_rgba.png logs/test.obj --force_cuda_rast # mesh
实验结果:
gaussian 初始建模效果如下:
mesh 精细建模效果如下:
实验过程:
完整训练指令如下:
### training gaussian stage
python main.py --config configs/text.yaml prompt="a photo of an icecream" save_path=icecream
### training mesh stage
python main2.py --config configs/text.yaml prompt="a photo of an icecream" save_path=icecream
### visualization
kire logs/icecream_mesh.obj --save_video outputs/icecream_mesh.mp4 --wogui --force_cuda_rast # gaussian
kire logs/icecream.obj --save_video outputs/icecream.mp4 --wogui --force_cuda_rast # mesh
实验结果:
gaussian 初始建模效果如下:
mesh 精细建模效果如下:
Chenlin Meng, Yutong He, Yang Song, Jiaming Song, Jiajun Wu, Jun-Yan Zhu, and Stefano Ermon. Sdedit: Guided image synthesis and editing with stochastic differential equations. arXiv preprint arXiv:2108.01073, 2021. ↩︎
计算机图形学七:纹理映射(Texture Mapping)及Mipmap技术 ↩︎
Liu R, Wu R, Van Hoorick B, et al. Zero-1-to-3: Zero-shot one image to 3d object[C]//Proceedings of the IEEE/CVF International Conference on Computer Vision. 2023: 9298-9309. ↩︎
春江水暖鸭先知:洞悉AIGC技术趋势,把握内容产业变革的先机 ↩︎
dr.RasterizeGLContext() failed #78 ↩︎
Cannot build nvdiffrast_plugin_gl.so#76 ↩︎
I have problem about nvdiffrast_plugin_gl.so #92 ↩︎
ninja: build stopped: subcommand failed. #24 ↩︎