cv-3dgs-densification

Computer Visiongsplatrigorous codebase

Description

3D Gaussian Splatting Densification Strategy Design

Objective

Design a densification strategy for 3D Gaussian Splatting (3DGS) that achieves the best novel view synthesis quality on real-world scenes.

Background

3D Gaussian Splatting represents scenes as collections of 3D Gaussians optimized via differentiable rendering. A critical component is the densification strategy, which controls how Gaussians are added, split, and pruned during optimization:

  • Clone: Duplicate small Gaussians in under-reconstructed regions
  • Split: Divide large Gaussians into smaller ones for finer detail
  • Prune: Remove transparent or oversized Gaussians
  • Reset: Periodically reset opacities to encourage pruning of unneeded Gaussians

Recent work has proposed various improvements:

  • AbsGS: Uses absolute gradients instead of average for better detail recovery
  • Mini-Splatting: Blur-aware forced splitting + importance-based pruning
  • MCMC 3DGS: Treats densification as Markov Chain Monte Carlo sampling
  • New Split (Cao et al.): Mathematically consistent Gaussian splitting

Task

Implement a CustomStrategy class in custom_strategy.py. Your strategy controls the full lifecycle of Gaussians during training via two hooks:

Editable Region

@dataclass
class CustomStrategy(Strategy):
    def initialize_state(self, scene_scale: float = 1.0) -> Dict[str, Any]:
        # Initialize running statistics for your strategy
        ...

    def step_pre_backward(self, params, optimizers, state, step, info):
        # Called BEFORE loss.backward(). Use to retain gradients.
        ...

    def step_post_backward(self, params, optimizers, state, step, info, packed=False):
        # Called AFTER loss.backward() and optimizer.step().
        # This is where you implement densification logic.
        ...

Available Operations (from gsplat.strategy.ops)

  • duplicate(params, optimizers, state, mask) — Clone selected Gaussians
  • split(params, optimizers, state, mask) — Split selected Gaussians (sample 2 new positions from covariance)
  • remove(params, optimizers, state, mask) — Remove selected Gaussians
  • reset_opa(params, optimizers, state, value) — Reset all opacities to a value
  • relocate(params, optimizers, state, mask, binoms, min_opacity) — Teleport dead Gaussians to live ones
  • sample_add(params, optimizers, state, n, binoms, min_opacity) — Add new Gaussians sampled from opacity distribution
  • inject_noise_to_position(params, optimizers, state, scaler) — Perturb positions

Available Information

The info dict from rasterization contains:

  • means2d: 2D projected means (with .grad after backward)
  • width, height: Image dimensions
  • n_cameras: Number of cameras in batch
  • radii: Screen-space radii per Gaussian
  • gaussian_ids: Which Gaussians are visible

The params dict contains Gaussian parameters:

  • means: [N, 3] positions
  • scales: [N, 3] log-scales
  • quats: [N, 4] rotation quaternions
  • opacities: [N] logit-opacities (use torch.sigmoid() for actual opacity)
  • sh0, shN: Spherical harmonic coefficients for color

Architecture (Fixed)

  • Renderer: gsplat CUDA rasterizer
  • Optimizer: AdamW with per-parameter learning rates
  • Loss: 0.8 × L1 + 0.2 × SSIM (fixed)
  • Training: 30,000 steps per scene
  • SH degree: 3 (increased gradually)

Evaluation

Novel view synthesis quality on held-out test views:

MetricDirectionDescription
PSNRhigher is betterPeak signal-to-noise ratio (primary metric)
SSIMhigher is betterStructural similarity index
LPIPSlower is betterLearned perceptual similarity (AlexNet)

Evaluated on 4 Mip-NeRF 360 scenes (garden, bicycle, bonsai, stump) with every 8th image held out for testing.

Baselines

NameStrategyDescription
defaultClone/Split/PruneOriginal 3DGS: gradient-threshold densification with periodic opacity reset
mcmcRelocate/Add/NoiseMCMC sampling: teleport dead Gaussians, add new ones, inject position noise
absgradAbsGS variantLike default but uses absolute gradients for better fine detail recovery
tamingCombinedAbsGS + Taming-3DGS max-grad blend + New Split (revised_opacity)

Reference Baseline PSNRs (MipNeRF360)

baselinegardenbicyclebonsaistump
default29.67726.90333.07927.761
mcmc29.13026.02932.92925.609
absgrad29.74527.02633.05127.850
taming30.04427.14133.35327.794

Your goal: beat the best baseline per-scene. taming leads on 3 of 4 scenes (garden / bicycle / bonsai); absgrad still leads stump by a narrow margin.

Code

custom_strategy.py
EditableRead-only
1"""Custom densification strategy for 3D Gaussian Splatting.
2
3This file defines the CustomStrategy class that controls how Gaussians
4are added, split, and pruned during per-scene optimization.
5"""
6
7from dataclasses import dataclass
8from typing import Any, Dict, Tuple, Union
9
10import math
11import torch
12from gsplat.strategy.base import Strategy
13from gsplat.strategy.ops import (
14 duplicate, split, remove, reset_opa,
15 relocate, sample_add, inject_noise_to_position,

Results

ModelTypebest psnr ssim lpips
absgradbaseline---
defaultbaseline---
mcmcbaseline---
tamingbaseline---
claude-opus-4.6vanilla---
deepseek-reasonervanilla---
gemini-3.1-pro-previewvanilla29.9360.8380.082
qwen3.6-plusvanilla26.9070.5360.478
claude-opus-4.6agent---
deepseek-reasoneragent---
gemini-3.1-pro-previewagent---
qwen3.6-plusagent---

Agent Conversations