# clone repository
git clone https://github.com/yzslab/gaussian-splatting-lightning.git
cd gaussian-splatting-lightning
# create virtual environment
conda create -yn gspl python=3.9 pip
conda activate gspl
Tested on PyTorch==2.0.1
You must install the one match to the version of your nvcc (nvcc --version)
For CUDA 11.8
pip install -r requirements/pyt201_cu118.txt
pip install -r requirements.txt
ffmpeg is required if you want to render video: sudo apt install -y ffmpeg
If you want to use nerfstudio-project/gsplat
NOTE: Only my modified v1 is supported
pip uninstall -y gsplat
pip install -r requirements/gsplat.txt
If you need SegAnyGaussian
gsplat (see command above)
SAM
pip install -r requirements/sam.txt
For torch==2.0.1 and cuda 11.8:
pip install -r requirements/pytorch3d-pre.txt
pip install --no-index --no-cache-dir -r requirements/pytorch3d-py39_cu118_pyt201.txt
Download ViT-H SAM model, place it to the root dir of this repo.: wget -O sam_vit_h_4b8939.pth https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth
python main.py fit \
--data.path DATASET_PATH \
-n EXPERIMENT_NAME
It can detect some dataset type automatically. You can also specify type with option --data.parser. Possible values are: Colmap, Blender, NSVF, Nerfies, MatrixCity, PhotoTourism, SegAnyColmap, Feature3DGSColmap.
[NOTE] By default, only checkpoint files will be produced on training end. If you need ply file in vanilla 3DGS's format (can be loaded by SIBR_viewer or some WebGL/GPU based viewer):
python utils/ckpt2ply.py TRAINING_OUTPUT_PATH, e.g.:
python utils/ckpt2ply.py outputs/legopython utils/ckpt2ply.py outputs/lego/checkpoints/epoch=300-step=30000.ckpt--model.save_ply truepython main.py fit \
--viewer \
...
configs/blender.yaml when training on blender dataset.python main.py fit \
--config configs/blender.yaml \
...
# the requirements of mask
# * must be single channel
# * zero(black) represent the masked pixel (won't be used to supervise learning)
# * the filename of the mask file must be image filename + '.png',
# e.g.: the mask of '001.jpg' is '001.jpg.png'
... fit \
--data.parser Colmap \
--data.parser.mask_dir MASK_DIR_PATH \
...
You can use utils/image_downsample.py to downsample your images, e.g. 4x downsample: python utils/image_downsample.py PATH_TO_DIRECTORY_THAT_STORE_IMAGES --factor 4
# it will load images from `images_4` directory
... fit \
--data.parser Colmap \
--data.parser.down_sample_factor 4 \
...
Rounding mode is specified by --data.parser.down_sample_rounding_mode. Available values are floor, round, round_half_up, ceil. Default is round.
Load large dataset without OOM
... fit \
--data.image_uint8 true
... fit \
--data.train_max_num_images_to_cache 512 \
--data.async_caching true \
...
... fit \
--data.train_max_num_images_to_cache 1024 \
...
Speedup training
Store all images in GPU memory
... fit \
--data.image_on_cpu false \
...
Combining this with --data.image_uint8 true to reduce GPU memory consumption is also feasible.
Avoid performing a validation after every training epoch
Simply set check_val_every_n_epoch to a very large value. Please note that the metrics starting with val/, such as val/psnr, on the progress bar will not be updated during the training.
... fit \
--trainer.check_val_every_n_epoch 99999 \
...
Take a look at Taming 3DGS (2.21.) for further acceleration
python main.py fit \
--config configs/gsplat.yaml \
...
[NOTE] Try New Multiple GPU training strategy, which can be enabled during densification.
[NOTE] Multi-GPU training with DDP strategy can only be enabled after densification. You can start a single GPU training at the beginning, and save a checkpoint after densification finishing. Then resume from this checkpoint and enable multi-GPU training.
You will get improved PSNR and SSIM with more GPUs:
# Single GPU at the beginning
python main.py fit \
--config ... \
--data.path DATASET_PATH \
--model.density.densify_until_iter 15000 \
--max_steps 15000
# Then resume, and enable multi-GPU
python main.py fit \
--config ... \
--trainer configs/ddp.yaml \
--data.path DATASET_PATH \
--max_steps 30000 \
--ckpt_path last # find latest checkpoint automatically, or provide a path to checkpoint file
python main.py fit \
--config configs/deformable_blender.yaml \
--data.path ...
Training:
python main.py fit \
--config configs/mip_splatting_gsplat_v2.yaml \
--data.path ...
Fuse the 3D smoothing filter to the Gaussian parameters:
python utils/fuse_mip_filter.py \
TRAINED_MODEL_DIR
Prune & finetune only currently
Train & densify & prune
... fit \
--config configs/light_gaussian/train_densify_prune-gsplat.yaml \
--data.path ...
Prune & finetune (make sure to use the same hparams as the input model used)
... fit \
--config configs/light_gaussian/prune_finetune-gsplat.yaml \
--data.path ... \
... \
--ckpt_path YOUR_CHECKPOINT_PATH
... fit \
--config configs/gsplat-absgrad.yaml \
--data.path ...
Install diff-surfel-rasterization first
pip install -r requirements/2DGS.txt
Then start training
... fit \
--config configs/vanilla_2dgs.yaml \
--data.path ...
Mesh extraction
Bounded
python utils/gs2d_mesh_extraction.py MODEL_OUTPUT_PATH
Unbounded
python utils/gs2d_mesh_extraction.py MODEL_OUTPUT_PATH --unbounded true
First, train a 3DGS scene using gsplat
python main.py fit \
--config configs/gsplat.yaml \
--data.path data/Truck \
-n Truck -v gsplat # trained model will save to `outputs/Truck/gsplat`
Then generate SAM masks and their scales
Masks
python utils/get_sam_masks.py data/Truck/images
You can specify the path to SAM checkpoint via argument -c PATH_TO_SAM_CKPT
Scales
python utils/get_sam_mask_scales.py outputs/Truck/gsplat
Both the masks and scales will be saved in data/Truck/semantics, the structure of data/Truck will like this:
├── images # The images of your dataset
├── 000001.jpg
├── 000002.jpg
...
├── semantic # Generated by `get_sam_masks.py` and `get_sam_mask_scales.py`
├── masks
├── 000001.jpg.pt
├── 000002.jpg.pt
...
└── scales
├── 000001.jpg.pt
├── 000002.jpg.pt
...
├── sparse # colmap sparse database
...
Train SegAnyGS
python seganygs.py fit \
--config configs/segany_splatting.yaml \
--data.path data/Truck \
--model.initialize_from outputs/Truck/gsplat \
-n Truck -v seganygs # save to `outputs/Truck/seganygs`
The value of --model.initialize_from is the path to the trained 3DGS model
Start the web viewer to perform segmentation or cluster
python viewer.py outputs/Truck/seganygs
With appearance model, the reconstruction quality can be improved when your images have various appearance, such as different exposure, white balance, contrast and even day and night.
This model assign an extra feature vector $\boldsymbol{\ell}^{(g)}$ to each 3D Gaussian and an appearance embedding vector $\boldsymbol{\ell}^{(a)}$ to each appearance group. Both of them will be used as the input of a lightweight MLP to calculate the color.
$$ \mathbf{C} = f \left ( \boldsymbol{\ell}^{(g)}, \boldsymbol{\ell}^{(a)} \right ) $$
Please refer to internal/renderers/gsplat_appearance_embedding_renderer.py for more details.
| Baseline | New Model |
|---|---|
First generate appearance groups (Colmap or PhotoTourism dataset only)
python utils/generate_image_apperance_groups.py PATH_TO_DATASET_DIR \
--image \
--name appearance_image_dedicated # the name will be used later
The images in a group will share a common appearance embedding. The command above will assign each image a group, which means that will not share any appearance embedding between images.
Then start training
python main.py fit \
--config configs/appearance_embedding_renderer/view_dependent.yaml \
--data.path PATH_TO_DATASET_DIR \
--data.parser Colmap \
--data.parser.appearance_groups appearance_image_dedicated # value here should be the same as the one provided to `--name` above
If you are using PhotoTourism dataset, please replace --data.parser Colmap with --data.parser PhotoTourism.
view_independent.yaml: turn off view dependent effectssh_view_dependent.yaml: represent view dependent effects using spherical harmonics*-distributed.yaml: multiple GPUs*-estimated_depth_reg.yaml / *-estimated_depth_reg-hard_depth.yaml: with depth regularizationRemove the dependence on MLP when rendering
It is recommended to use view_independent-* or sh_view_dependent-* configs if you want to do so.
By running python utils/fuse_appearance_embeddings_into_shs_dc.py TRAINED_MODEL_DIR, you can get a fixed appearance checkpoint without requiring a MLP.
... fit \
--config configs/gsplat-mcmc.yaml \
--model.density.cap_max MAX_NUM_GAUSSIANS \
...
MAX_NUM_GAUSSIANS is the maximum number of Gaussians that will be used.
Refer to ubc-vision/3dgs-mcmc, internal/density_controllers/mcmc_density_controller.py and internal/metrics/mcmc_metrics.py for more details.
This comes from Feature 3DGS. But two stage optimization is adapted here, rather than jointly.
First, train a model using gsplat (see command above)
Then extract feature map from your dataset
Theoretically, any feature is distillable. You need to implement your own feature map extractor. Here are instructions about extracting SAM and LSeg features.
SAM
python utils/get_sam_embeddings.py data/Truck/images
With this command, feature maps will be saved to data/Truck/semantic/sam_features, and preview to data/Truck/semantic/sam_feature_preview, respectively.
LSeg: please use ShijieZhou-UCLA/feature-3dgs and follow its instruction to extra LSeg features (do not use this repo's virtual environment for it).
Then start distillation
SAM
python main.py fit \
--config configs/feature_3dgs/sam-speedup.yaml \
--data.path data/Truck \
--data.parser.down_sample_factor 2 \
--model.initialize_from outputs/Truck/gsplat \
-n Truck -v feature_3dgs-sam
LSeg
[NOTE] In order to distill LSeg's high-dimensional features, you may need a GPU equipped with a large memory capacity
python main.py fit \
--config configs/feature_3dgs/lseg-speedup.yaml \
...
--model.initialize_from is the path to your trained model.
Since rasterizing high dimension features is slow, --data.parser.down_sample_factor is used here to smaller the rendered feature map to speedup distillation.
After distillation finishing, you can use viewer to visualize the feature map rendered from 3D Gaussians
python viewer.py outputs/Truck/feature_3dgs
CLIP is required if you are using LSeg feature: pip install git+https://github.com/openai/CLIP.git
LSeg feature is used in this video.
Based on the Appearance Model (2.12.) above, this model can produce a visibility map for every training view indicating whether a pixel belongs to transient objects or not.
The idea of the visibility map is a bit like Ha-NeRF, but rather than uses positional encoding for pixel coordinates, 2D dense grid encoding is used here in order to accelerate training.
Please refer to Ha-NeRF, internal/renderers/gsplat_appearance_embedding_visibility_map_renderer.py and internal/metrics/visibility_map_metrics.py for more details.
[NOTE] Though it shows the capability to distinguish the pixels of transient objects, may not be able to remove some artifats/floaters belong to transients. And may also treat under-reconstructed regions as transients.
pip install -r requirements/tcnn.txt
Download PhotoTourism dataset from here and split file from the "Additional links" here. The split file should be placed at the same path as the dense directory of the PhotoTourism dataset, e.g.:
├──brandenburg_gate
├── dense # colmap database
├── images
├── ...
├── sparse
...
├── brandenburg.tsv # split file
[Optional] 2x downsize the images: python utils/image_downsample.py data/brandenburg_gate/dense/images --factor 2
python main.py fit \
--config configs/appearance_embedding_visibility_map_renderer/view_independent-2x_ds.yaml \
--data.path data/brandenburg_gate \
-n brandenburg_gate
If you have not downsized images, remember to add a --data.parser.down_sample_factor 1 to the command above.
python main.py validate \
--config outputs/brandenburg_gate/lightning_logs/version_0/config.yaml \
--save_val \
--val_train
Then you can find the rendered masks and images in outputs/brandenburg_gate/val.
This is a bit like a simplified version of Scaling Up 3DGS.
In the implementation here, Gaussians are stored, projected and their colors are calculated in a distributed manner, and each GPU rasterizes a whole image for a different camera. No Pixel-wise Distribution currently.
This strategy works with densification enabled.
[NOTE]
PSNR
SSIM
LPIPS
python main.py fit \
--config configs/distributed.yaml \
...
By default, all processes will hold a (redundant) replica of the dataset in memory, which may cause CPU OOM. You can avoid this by adding the option --data.distributed true, so that each process loads a different subset of the dataset.
python utils/merge_distributed_ckpts.py outputs/TRAINED_MODEL_DIR
python viewer.py outputs/TRAINED_MODEL_DIR/checkpoints/MERGED_CHECKPOINT_FILE
[NOTE] No utilization-based pruning (4.2.3 of the paper) and appearance modeling (4.2.4 of the paper)
Install requirements
pip install -r requirements/SpotLessSplats.txt
Extract Stable Diffusion features
python utils/sd_feature_extraction.py YOUR_IMAGE_DIR
Training
python main.py fit \
--config configs/spot_less_splats/gsplat-cluster.yaml \
--data.parser.split_mode "reconstruction" \
--data.path YOUR_DATASET_PATH \
-n EXPERIMENT_NAME
python main.py fit \
--config configs/spot_less_splats/gsplat-mlp.yaml \
--data.parser.split_mode "reconstruction" \
--data.path YOUR_DATASET_PATH \
-n EXPERIMENT_NAME
Change the value of --data.parser.split_mode to keyword if you are using the RobustNeRF dataset.
Render SLS predicted masks
python utils/render_sls_masks.py outputs/EXPERIMENT_NAME
This is implemented with reference to Hierarchical 3DGS.
| Baseline | DepthReg | DepthReg + AppearanceModel |
|---|---|---|
Setup Depth Anything V2
# clone the repo.
git clone https://github.com/DepthAnything/Depth-Anything-V2 utils/Depth-Anything-V2
# NOTE: do not run `pip install -r utils/Depth-Anything-V2/requirements.txt`
# download the pretrained model `Depth-Anything-V2-Large`
mkdir utils/Depth-Anything-V2/checkpoints
wget -O utils/Depth-Anything-V2/checkpoints/depth_anything_v2_vitl.pth "https://huggingface.co/depth-anything/Depth-Anything-V2-Large/resolve/main/depth_anything_v2_vitl.pth?download=true"
Dataset pre-processing
python utils/estimate_dataset_depths.py data/Family
Make sure that both the sparse and images folders exist in data/Family.
With the operation above, the structure of data/Family should be like this:
├── data/Family
├── estimated_depths # generated by `utils/run_depth_anything_v2.py`
├── 00001.jpg.npy
├── ...
├── images
├── 00001.jpg
├── ...
├── sparse # colmap sparse model
├── ...
├── estimated_depth_scales.json # generated by `utils/get_depth_scales.py`
...
Training
python main.py fit \
--config configs/depth_regularization/estimated_inverse_depth-l1.yaml \
--data.path data/Family \
-n EXPERIMENT_NAME
Other available configs:
In my experiments, simply L1 is slightly better than L2 or the one with SSIM.
Install the StopThePop-Rasterization first:
pip install -r requirements/StopThePop.txt
Training:
python main.py fit \
--config configs/stp/baseline.yaml \
--data.path ... \
...
The scales of Gaussians will grow to some unreasonable values after densification. For example, some linear shape Gaussians are almost longer than your scene, and appear as artifacts at many viewpoints. This regularization, containing max scale and scale ratio losses, can avoid it. Take a look internal/metrics/scale_regularization_metrics.py for more details.
Usage:
python main.py fit \
--config configs/scale_reg.yaml \
--model.metric.max_scale 1. \
...
The --model.metric.max_scale is a scene-specific hyperparameter. The regularization will be applied to the Gaussians with scales exceeding it. It should be greater than percent_dense * camera_extent. The percent_dense is 0.01 by default. The camera_extent will be printed as spatial_lr_scale=... at the beginning of the training. Set it to a very large value, e.g. 2048, to disable the max scale loss if you are not sure what value should be used.
There are two implementations: one is the gsplat v1 based, and the other is the vanilla one. The gsplat v1 based implementation currently does not have "Backpropagation with Per-Splat Parallelization."
(a) Install libraries first
fused-ssim
pip install --no-build-isolation -r requirements/fused-ssim.txt
my modified gsplat v1 if you want the gsplat v1 based one (refer to 1.5. for the setup guide)
another rasterizer if you want the vanilla one
pip install -r requirements/diff-accel-rasterization.txt
(b) Available config files
| Type | gsplat v1 | vanilla |
|---|---|---|
| Competitive quality | configs/gsplat_v1-accel.yaml | configs/taming_3dgs/rasterizer-fused_ssim-aa.yaml |
| More acceleration, slightly lower quality (SparseAdam) | configs/gsplat_v1-accel_more.yaml | configs/taming_3dgs/rasterizer-fused_ssim-sparse_adam-aa.yaml |
| Steerable Densification | configs/gsplat_v1-accel-steerable.yaml | - |
You need to adjust the --model.density.budget if you want to use the steerable one.
The negative impacts of appearance variations can be largely mitigated using this method.
configs/bilagrid.yamlpip install -r requirements/fused-bilagrid.txtconfigs/bilagrid_fused.yamlBetter quality can be achieved with fewer primitives.
My modified gsplat v1 is required.
python main.py fit \
--config configs/gsplat_v1.yaml \
--config configs/gns.yaml \
--model.density.budget YOUR_EXPECTED_BUDGET_GOES_HERE \
...
Per-image metrics will be saved to TRAINING_OUTPUT/metrics as a csv file.
python main.py validate \
--config outputs/lego/config.yaml
python main.py test \
--config outputs/lego/config.yaml
python main.py validate \
--config outputs/lego/config.yaml \
--val_train
python main.py <validate or test> \
--config outputs/lego/config.yaml \
--save_val
Then you can find the images in outputs/lego/<val or test>.
| Transform | Camera Path | Edit |
|---|---|---|
The web viewer is powered by viser.
python viewer.py TRAINING_OUTPUT_PATH
# e.g.:
# python viewer.py outputs/lego/
# python viewer.py outputs/lego/checkpoints/epoch=300-step=30000.ckpt
# python viewer.py outputs/lego/baseline/point_cloud/iteration_30000/point_cloud.ply # only works with VanillaRenderer
python viewer.py \
outputs/garden \
outputs/lego \
outputs/Synthetic_NSVF/Palace/point_cloud/iteration_30000/point_cloud.ply \
--enable_transform
[NOTE] The commands in this section only design for third-party outputs
python viewer.py \
Deformable-3D-Gaussians/outputs/lego \
--vanilla_deformable \
--reorient disable # change to enable when loading real world scene
python viewer.py \
4DGaussians/outputs/lego \
--vanilla_gs4d
# Install `diff-surfel-rasterization` first
pip install -r requirements/diff-surfel-rasterization.txt
# Then start viewer
python viewer.py \
2d-gaussian-splatting/outputs/Truck \
--vanilla_gs2d
python viewer.py \
SegAnyGAussians/outputs/Truck \
--vanilla_seganygs
python viewer.py \
mip-splatting/outputs/bicycle \
--vanilla_mip
Q: The viewer shows my scene in unexpected orientation, how to rotate the camera, like the U and O key in the SIBR_viewer?
A: Check the Orientation Control on the right panel, rotate the camera frustum in the scene to the orientation you want, then click Apply Up Direction.
Besides: You can also click the 'Reset up direction' button. Then the viewer will use your current orientation as the reference.
Q: The web viewer is slow (or low fps, far from real-time).
A: This is expected because of the overhead of the image transfer over network. You can get around 10fps in 1080P resolution, which is enough for you to view the reconstruction quality.
Jupyter Notebook
93.4%
Python
6.6%
# clone repository
git clone https://github.com/yzslab/gaussian-splatting-lightning.git
cd gaussian-splatting-lightning
# create virtual environment
conda create -yn gspl python=3.9 pip
conda activate gspl
Tested on PyTorch==2.0.1
You must install the one match to the version of your nvcc (nvcc --version)
For CUDA 11.8
pip install -r requirements/pyt201_cu118.txt
pip install -r requirements.txt
ffmpeg is required if you want to render video: sudo apt install -y ffmpeg
If you want to use nerfstudio-project/gsplat
NOTE: Only my modified v1 is supported
pip uninstall -y gsplat
pip install -r requirements/gsplat.txt
If you need SegAnyGaussian
gsplat (see command above)
SAM
pip install -r requirements/sam.txt
For torch==2.0.1 and cuda 11.8:
pip install -r requirements/pytorch3d-pre.txt
pip install --no-index --no-cache-dir -r requirements/pytorch3d-py39_cu118_pyt201.txt
Download ViT-H SAM model, place it to the root dir of this repo.: wget -O sam_vit_h_4b8939.pth https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth
python main.py fit \
--data.path DATASET_PATH \
-n EXPERIMENT_NAME
It can detect some dataset type automatically. You can also specify type with option --data.parser. Possible values are: Colmap, Blender, NSVF, Nerfies, MatrixCity, PhotoTourism, SegAnyColmap, Feature3DGSColmap.
[NOTE] By default, only checkpoint files will be produced on training end. If you need ply file in vanilla 3DGS's format (can be loaded by SIBR_viewer or some WebGL/GPU based viewer):
python utils/ckpt2ply.py TRAINING_OUTPUT_PATH, e.g.:
python utils/ckpt2ply.py outputs/legopython utils/ckpt2ply.py outputs/lego/checkpoints/epoch=300-step=30000.ckpt--model.save_ply truepython main.py fit \
--viewer \
...
configs/blender.yaml when training on blender dataset.python main.py fit \
--config configs/blender.yaml \
...
# the requirements of mask
# * must be single channel
# * zero(black) represent the masked pixel (won't be used to supervise learning)
# * the filename of the mask file must be image filename + '.png',
# e.g.: the mask of '001.jpg' is '001.jpg.png'
... fit \
--data.parser Colmap \
--data.parser.mask_dir MASK_DIR_PATH \
...
You can use utils/image_downsample.py to downsample your images, e.g. 4x downsample: python utils/image_downsample.py PATH_TO_DIRECTORY_THAT_STORE_IMAGES --factor 4
# it will load images from `images_4` directory
... fit \
--data.parser Colmap \
--data.parser.down_sample_factor 4 \
...
Rounding mode is specified by --data.parser.down_sample_rounding_mode. Available values are floor, round, round_half_up, ceil. Default is round.
Load large dataset without OOM
... fit \
--data.image_uint8 true
... fit \
--data.train_max_num_images_to_cache 512 \
--data.async_caching true \
...
... fit \
--data.train_max_num_images_to_cache 1024 \
...
Speedup training
Store all images in GPU memory
... fit \
--data.image_on_cpu false \
...
Combining this with --data.image_uint8 true to reduce GPU memory consumption is also feasible.
Avoid performing a validation after every training epoch
Simply set check_val_every_n_epoch to a very large value. Please note that the metrics starting with val/, such as val/psnr, on the progress bar will not be updated during the training.
... fit \
--trainer.check_val_every_n_epoch 99999 \
...
Take a look at Taming 3DGS (2.21.) for further acceleration
python main.py fit \
--config configs/gsplat.yaml \
...
[NOTE] Try New Multiple GPU training strategy, which can be enabled during densification.
[NOTE] Multi-GPU training with DDP strategy can only be enabled after densification. You can start a single GPU training at the beginning, and save a checkpoint after densification finishing. Then resume from this checkpoint and enable multi-GPU training.
You will get improved PSNR and SSIM with more GPUs:
# Single GPU at the beginning
python main.py fit \
--config ... \
--data.path DATASET_PATH \
--model.density.densify_until_iter 15000 \
--max_steps 15000
# Then resume, and enable multi-GPU
python main.py fit \
--config ... \
--trainer configs/ddp.yaml \
--data.path DATASET_PATH \
--max_steps 30000 \
--ckpt_path last # find latest checkpoint automatically, or provide a path to checkpoint file
python main.py fit \
--config configs/deformable_blender.yaml \
--data.path ...
Training:
python main.py fit \
--config configs/mip_splatting_gsplat_v2.yaml \
--data.path ...
Fuse the 3D smoothing filter to the Gaussian parameters:
python utils/fuse_mip_filter.py \
TRAINED_MODEL_DIR
Prune & finetune only currently
Train & densify & prune
... fit \
--config configs/light_gaussian/train_densify_prune-gsplat.yaml \
--data.path ...
Prune & finetune (make sure to use the same hparams as the input model used)
... fit \
--config configs/light_gaussian/prune_finetune-gsplat.yaml \
--data.path ... \
... \
--ckpt_path YOUR_CHECKPOINT_PATH
... fit \
--config configs/gsplat-absgrad.yaml \
--data.path ...
Install diff-surfel-rasterization first
pip install -r requirements/2DGS.txt
Then start training
... fit \
--config configs/vanilla_2dgs.yaml \
--data.path ...
Mesh extraction
Bounded
python utils/gs2d_mesh_extraction.py MODEL_OUTPUT_PATH
Unbounded
python utils/gs2d_mesh_extraction.py MODEL_OUTPUT_PATH --unbounded true
First, train a 3DGS scene using gsplat
python main.py fit \
--config configs/gsplat.yaml \
--data.path data/Truck \
-n Truck -v gsplat # trained model will save to `outputs/Truck/gsplat`
Then generate SAM masks and their scales
Masks
python utils/get_sam_masks.py data/Truck/images
You can specify the path to SAM checkpoint via argument -c PATH_TO_SAM_CKPT
Scales
python utils/get_sam_mask_scales.py outputs/Truck/gsplat
Both the masks and scales will be saved in data/Truck/semantics, the structure of data/Truck will like this:
├── images # The images of your dataset
├── 000001.jpg
├── 000002.jpg
...
├── semantic # Generated by `get_sam_masks.py` and `get_sam_mask_scales.py`
├── masks
├── 000001.jpg.pt
├── 000002.jpg.pt
...
└── scales
├── 000001.jpg.pt
├── 000002.jpg.pt
...
├── sparse # colmap sparse database
...
Train SegAnyGS
python seganygs.py fit \
--config configs/segany_splatting.yaml \
--data.path data/Truck \
--model.initialize_from outputs/Truck/gsplat \
-n Truck -v seganygs # save to `outputs/Truck/seganygs`
The value of --model.initialize_from is the path to the trained 3DGS model
Start the web viewer to perform segmentation or cluster
python viewer.py outputs/Truck/seganygs
With appearance model, the reconstruction quality can be improved when your images have various appearance, such as different exposure, white balance, contrast and even day and night.
This model assign an extra feature vector $\boldsymbol{\ell}^{(g)}$ to each 3D Gaussian and an appearance embedding vector $\boldsymbol{\ell}^{(a)}$ to each appearance group. Both of them will be used as the input of a lightweight MLP to calculate the color.
$$ \mathbf{C} = f \left ( \boldsymbol{\ell}^{(g)}, \boldsymbol{\ell}^{(a)} \right ) $$
Please refer to internal/renderers/gsplat_appearance_embedding_renderer.py for more details.
| Baseline | New Model |
|---|---|
First generate appearance groups (Colmap or PhotoTourism dataset only)
python utils/generate_image_apperance_groups.py PATH_TO_DATASET_DIR \
--image \
--name appearance_image_dedicated # the name will be used later
The images in a group will share a common appearance embedding. The command above will assign each image a group, which means that will not share any appearance embedding between images.
Then start training
python main.py fit \
--config configs/appearance_embedding_renderer/view_dependent.yaml \
--data.path PATH_TO_DATASET_DIR \
--data.parser Colmap \
--data.parser.appearance_groups appearance_image_dedicated # value here should be the same as the one provided to `--name` above
If you are using PhotoTourism dataset, please replace --data.parser Colmap with --data.parser PhotoTourism.
view_independent.yaml: turn off view dependent effectssh_view_dependent.yaml: represent view dependent effects using spherical harmonics*-distributed.yaml: multiple GPUs*-estimated_depth_reg.yaml / *-estimated_depth_reg-hard_depth.yaml: with depth regularizationRemove the dependence on MLP when rendering
It is recommended to use view_independent-* or sh_view_dependent-* configs if you want to do so.
By running python utils/fuse_appearance_embeddings_into_shs_dc.py TRAINED_MODEL_DIR, you can get a fixed appearance checkpoint without requiring a MLP.
... fit \
--config configs/gsplat-mcmc.yaml \
--model.density.cap_max MAX_NUM_GAUSSIANS \
...
MAX_NUM_GAUSSIANS is the maximum number of Gaussians that will be used.
Refer to ubc-vision/3dgs-mcmc, internal/density_controllers/mcmc_density_controller.py and internal/metrics/mcmc_metrics.py for more details.
This comes from Feature 3DGS. But two stage optimization is adapted here, rather than jointly.
First, train a model using gsplat (see command above)
Then extract feature map from your dataset
Theoretically, any feature is distillable. You need to implement your own feature map extractor. Here are instructions about extracting SAM and LSeg features.
SAM
python utils/get_sam_embeddings.py data/Truck/images
With this command, feature maps will be saved to data/Truck/semantic/sam_features, and preview to data/Truck/semantic/sam_feature_preview, respectively.
LSeg: please use ShijieZhou-UCLA/feature-3dgs and follow its instruction to extra LSeg features (do not use this repo's virtual environment for it).
Then start distillation
SAM
python main.py fit \
--config configs/feature_3dgs/sam-speedup.yaml \
--data.path data/Truck \
--data.parser.down_sample_factor 2 \
--model.initialize_from outputs/Truck/gsplat \
-n Truck -v feature_3dgs-sam
LSeg
[NOTE] In order to distill LSeg's high-dimensional features, you may need a GPU equipped with a large memory capacity
python main.py fit \
--config configs/feature_3dgs/lseg-speedup.yaml \
...
--model.initialize_from is the path to your trained model.
Since rasterizing high dimension features is slow, --data.parser.down_sample_factor is used here to smaller the rendered feature map to speedup distillation.
After distillation finishing, you can use viewer to visualize the feature map rendered from 3D Gaussians
python viewer.py outputs/Truck/feature_3dgs
CLIP is required if you are using LSeg feature: pip install git+https://github.com/openai/CLIP.git
LSeg feature is used in this video.
Based on the Appearance Model (2.12.) above, this model can produce a visibility map for every training view indicating whether a pixel belongs to transient objects or not.
The idea of the visibility map is a bit like Ha-NeRF, but rather than uses positional encoding for pixel coordinates, 2D dense grid encoding is used here in order to accelerate training.
Please refer to Ha-NeRF, internal/renderers/gsplat_appearance_embedding_visibility_map_renderer.py and internal/metrics/visibility_map_metrics.py for more details.
[NOTE] Though it shows the capability to distinguish the pixels of transient objects, may not be able to remove some artifats/floaters belong to transients. And may also treat under-reconstructed regions as transients.
pip install -r requirements/tcnn.txt
Download PhotoTourism dataset from here and split file from the "Additional links" here. The split file should be placed at the same path as the dense directory of the PhotoTourism dataset, e.g.:
├──brandenburg_gate
├── dense # colmap database
├── images
├── ...
├── sparse
...
├── brandenburg.tsv # split file
[Optional] 2x downsize the images: python utils/image_downsample.py data/brandenburg_gate/dense/images --factor 2
python main.py fit \
--config configs/appearance_embedding_visibility_map_renderer/view_independent-2x_ds.yaml \
--data.path data/brandenburg_gate \
-n brandenburg_gate
If you have not downsized images, remember to add a --data.parser.down_sample_factor 1 to the command above.
python main.py validate \
--config outputs/brandenburg_gate/lightning_logs/version_0/config.yaml \
--save_val \
--val_train
Then you can find the rendered masks and images in outputs/brandenburg_gate/val.
This is a bit like a simplified version of Scaling Up 3DGS.
In the implementation here, Gaussians are stored, projected and their colors are calculated in a distributed manner, and each GPU rasterizes a whole image for a different camera. No Pixel-wise Distribution currently.
This strategy works with densification enabled.
[NOTE]
PSNR
SSIM
LPIPS
python main.py fit \
--config configs/distributed.yaml \
...
By default, all processes will hold a (redundant) replica of the dataset in memory, which may cause CPU OOM. You can avoid this by adding the option --data.distributed true, so that each process loads a different subset of the dataset.
python utils/merge_distributed_ckpts.py outputs/TRAINED_MODEL_DIR
python viewer.py outputs/TRAINED_MODEL_DIR/checkpoints/MERGED_CHECKPOINT_FILE
[NOTE] No utilization-based pruning (4.2.3 of the paper) and appearance modeling (4.2.4 of the paper)
Install requirements
pip install -r requirements/SpotLessSplats.txt
Extract Stable Diffusion features
python utils/sd_feature_extraction.py YOUR_IMAGE_DIR
Training
python main.py fit \
--config configs/spot_less_splats/gsplat-cluster.yaml \
--data.parser.split_mode "reconstruction" \
--data.path YOUR_DATASET_PATH \
-n EXPERIMENT_NAME
python main.py fit \
--config configs/spot_less_splats/gsplat-mlp.yaml \
--data.parser.split_mode "reconstruction" \
--data.path YOUR_DATASET_PATH \
-n EXPERIMENT_NAME
Change the value of --data.parser.split_mode to keyword if you are using the RobustNeRF dataset.
Render SLS predicted masks
python utils/render_sls_masks.py outputs/EXPERIMENT_NAME
This is implemented with reference to Hierarchical 3DGS.
| Baseline | DepthReg | DepthReg + AppearanceModel |
|---|---|---|
Setup Depth Anything V2
# clone the repo.
git clone https://github.com/DepthAnything/Depth-Anything-V2 utils/Depth-Anything-V2
# NOTE: do not run `pip install -r utils/Depth-Anything-V2/requirements.txt`
# download the pretrained model `Depth-Anything-V2-Large`
mkdir utils/Depth-Anything-V2/checkpoints
wget -O utils/Depth-Anything-V2/checkpoints/depth_anything_v2_vitl.pth "https://huggingface.co/depth-anything/Depth-Anything-V2-Large/resolve/main/depth_anything_v2_vitl.pth?download=true"
Dataset pre-processing
python utils/estimate_dataset_depths.py data/Family
Make sure that both the sparse and images folders exist in data/Family.
With the operation above, the structure of data/Family should be like this:
├── data/Family
├── estimated_depths # generated by `utils/run_depth_anything_v2.py`
├── 00001.jpg.npy
├── ...
├── images
├── 00001.jpg
├── ...
├── sparse # colmap sparse model
├── ...
├── estimated_depth_scales.json # generated by `utils/get_depth_scales.py`
...
Training
python main.py fit \
--config configs/depth_regularization/estimated_inverse_depth-l1.yaml \
--data.path data/Family \
-n EXPERIMENT_NAME
Other available configs:
In my experiments, simply L1 is slightly better than L2 or the one with SSIM.
Install the StopThePop-Rasterization first:
pip install -r requirements/StopThePop.txt
Training:
python main.py fit \
--config configs/stp/baseline.yaml \
--data.path ... \
...
The scales of Gaussians will grow to some unreasonable values after densification. For example, some linear shape Gaussians are almost longer than your scene, and appear as artifacts at many viewpoints. This regularization, containing max scale and scale ratio losses, can avoid it. Take a look internal/metrics/scale_regularization_metrics.py for more details.
Usage:
python main.py fit \
--config configs/scale_reg.yaml \
--model.metric.max_scale 1. \
...
The --model.metric.max_scale is a scene-specific hyperparameter. The regularization will be applied to the Gaussians with scales exceeding it. It should be greater than percent_dense * camera_extent. The percent_dense is 0.01 by default. The camera_extent will be printed as spatial_lr_scale=... at the beginning of the training. Set it to a very large value, e.g. 2048, to disable the max scale loss if you are not sure what value should be used.
There are two implementations: one is the gsplat v1 based, and the other is the vanilla one. The gsplat v1 based implementation currently does not have "Backpropagation with Per-Splat Parallelization."
(a) Install libraries first
fused-ssim
pip install --no-build-isolation -r requirements/fused-ssim.txt
my modified gsplat v1 if you want the gsplat v1 based one (refer to 1.5. for the setup guide)
another rasterizer if you want the vanilla one
pip install -r requirements/diff-accel-rasterization.txt
(b) Available config files
| Type | gsplat v1 | vanilla |
|---|---|---|
| Competitive quality | configs/gsplat_v1-accel.yaml | configs/taming_3dgs/rasterizer-fused_ssim-aa.yaml |
| More acceleration, slightly lower quality (SparseAdam) | configs/gsplat_v1-accel_more.yaml | configs/taming_3dgs/rasterizer-fused_ssim-sparse_adam-aa.yaml |
| Steerable Densification | configs/gsplat_v1-accel-steerable.yaml | - |
You need to adjust the --model.density.budget if you want to use the steerable one.
The negative impacts of appearance variations can be largely mitigated using this method.
configs/bilagrid.yamlpip install -r requirements/fused-bilagrid.txtconfigs/bilagrid_fused.yamlBetter quality can be achieved with fewer primitives.
My modified gsplat v1 is required.
python main.py fit \
--config configs/gsplat_v1.yaml \
--config configs/gns.yaml \
--model.density.budget YOUR_EXPECTED_BUDGET_GOES_HERE \
...
Per-image metrics will be saved to TRAINING_OUTPUT/metrics as a csv file.
python main.py validate \
--config outputs/lego/config.yaml
python main.py test \
--config outputs/lego/config.yaml
python main.py validate \
--config outputs/lego/config.yaml \
--val_train
python main.py <validate or test> \
--config outputs/lego/config.yaml \
--save_val
Then you can find the images in outputs/lego/<val or test>.
| Transform | Camera Path | Edit |
|---|---|---|
The web viewer is powered by viser.
python viewer.py TRAINING_OUTPUT_PATH
# e.g.:
# python viewer.py outputs/lego/
# python viewer.py outputs/lego/checkpoints/epoch=300-step=30000.ckpt
# python viewer.py outputs/lego/baseline/point_cloud/iteration_30000/point_cloud.ply # only works with VanillaRenderer
python viewer.py \
outputs/garden \
outputs/lego \
outputs/Synthetic_NSVF/Palace/point_cloud/iteration_30000/point_cloud.ply \
--enable_transform
[NOTE] The commands in this section only design for third-party outputs
python viewer.py \
Deformable-3D-Gaussians/outputs/lego \
--vanilla_deformable \
--reorient disable # change to enable when loading real world scene
python viewer.py \
4DGaussians/outputs/lego \
--vanilla_gs4d
# Install `diff-surfel-rasterization` first
pip install -r requirements/diff-surfel-rasterization.txt
# Then start viewer
python viewer.py \
2d-gaussian-splatting/outputs/Truck \
--vanilla_gs2d
python viewer.py \
SegAnyGAussians/outputs/Truck \
--vanilla_seganygs
python viewer.py \
mip-splatting/outputs/bicycle \
--vanilla_mip
Q: The viewer shows my scene in unexpected orientation, how to rotate the camera, like the U and O key in the SIBR_viewer?
A: Check the Orientation Control on the right panel, rotate the camera frustum in the scene to the orientation you want, then click Apply Up Direction.
Besides: You can also click the 'Reset up direction' button. Then the viewer will use your current orientation as the reference.
Q: The web viewer is slow (or low fps, far from real-time).
A: This is expected because of the overhead of the image transfer over network. You can get around 10fps in 1080P resolution, which is enough for you to view the reconstruction quality.
Jupyter Notebook
93.4%
Python
6.6%