VGGT + Factor Graph Refinement

May 6, 2026 · View on GitHub

License: MIT Python 3.10+

Video → 3D in one command. No COLMAP. Outputs COLMAP/nerfstudio format directly.

VGGT gives you instant poses but OOMs past 50 frames. VGGT-SLAM 2.0 fixes that but requires 4 repos, conda, a missing checkpoint, manual ffmpeg, and a 24GB GPU — and outputs nothing you can actually use downstream.

This project is the practical middle ground:

python run.py --video my_phone_video.mp4 --output scene/ --export all
scene/
├── sparse/0/          # COLMAP format → feed into ANY 3DGS pipeline
├── transforms.json    # nerfstudio format → splatfacto/nerfacto
├── scene.ply          # Colored point cloud
├── scene.splat        # Web viewer (.splat format)
├── poses_c2w.npy      # Raw poses
└── summary.json       # Timing + metrics

Why not VGGT-SLAM 2.0?

VGGT-SLAM 2.0 (MIT SPARK)This project
Installconda + 4 git clones + hunt for SALAD checkpointpip install gtsam + clone this repo
InputPre-extracted frames (manual ffmpeg)Direct video file
GPU24GB minimum (crashes on 12GB)8GB+ (auto chunk sizing)
OutputViser visualization onlyCOLMAP, nerfstudio, PLY, .splat
Metric scaleNoOptional (MoGe-2 alignment)
COLMAP exportNo (issue #10 — unanswered)Yes
Point cloud saveNo (issue #24)Yes
Gaussian splattingNoBuilt-in gsplat training
Mesh exportNoTSDF fusion
StabilitySL(4) singularity crashes (issue #5)SE(3) + robust kernels (no crashes)

This is not a research SLAM system. It's a tool for getting usable 3D output from video.

Demo

3D visualization

Results

Pose Accuracy (TUM-RGBD, 80 frames, chunk_size=8)

SequenceNaive Stitch ATEFactor Graph ATEImprovement
fr1/desk0.187 m0.031 m83.5%
fr1/xyz0.176 m0.060 m66.1%
fr1/room0.134 m0.085 m36.4%
fr2/desk0.127 m0.021 m83.6%
fr3/office0.105 m0.049 m53.7%

Replica Dataset (80 frames, chunk_size=8)

SequenceNaive Stitch ATEFactor Graph ATEImprovement
office00.410 m0.104 m74.6%
office10.208 m0.068 m67.3%
room00.511 m0.082 m84.0%
room10.463 m0.078 m83.1%

Average improvement: 70.3% across 9 sequences on 2 datasets.

Scaling

FramesVGGT Single-ShotNaive StitchFactor Graph (ours)
100.002 m0.004 m0.003 m
300.004 m0.016 m0.004 m
500.005 m0.033 m0.005 m
80OOM0.042 m0.015 m
200OOM0.132 m0.043 m
300OOM0.190 m0.056 m

Scaling

Gaussian Splatting Render Quality

MetricNaive PosesFactor Graph PosesImprovement
Mean PSNR8.16 dB13.28 dB+5.12 dB
Training loss~0.50 (stuck)~0.16 (converged)3x lower

render comparison

Quick Start

# Install
pip install gtsam torch torchvision scipy opencv-python-headless tqdm
git clone https://github.com/facebookresearch/vggt && cd vggt && pip install -e . && cd ..
git clone https://github.com/jashshah999/vggt-factor-refinement && cd vggt-factor-refinement

# Run on your video (outputs COLMAP + nerfstudio + PLY + .splat)
python run.py --video my_video.mp4 --output scene/ --export all

# Run on image directory
python run.py --images path/to/frames/ --output scene/

# Also train Gaussian Splatting
python run.py --video my_video.mp4 --output scene/ --train-gaussians --train-iters 3000

# Benchmark on TUM-RGBD
python benchmark_chunked.py --seq fr1/desk --chunk-size 8 --overlap 2

Export Formats

FormatFlagUse case
COLMAP sparse--export colmapFeed into gaussian-splatting, nerfstudio, 3DGS
nerfstudio--export nerfstudioDirect use with splatfacto/nerfacto
PLY--export plyView in MeshLab, CloudCompare, Blender
.splat--export splatWeb-based 3DGS viewers (antimatter15/splat)
All--export allEverything above

How It Works

Video / Image directory
    |
    v
[Frame extraction + keyframe selection]
    |
    v
[VGGT per chunk (auto-sized for your GPU)]
    |
    v
[Sim(3) overlap stitching (confidence-weighted)]
    |
    v
[iSAM2 factor graph]
  - Within-chunk odometry (confidence-weighted noise)
  - Cross-chunk overlap constraints (Cauchy robust kernel)
  - DINOv2 appearance loop closure + ORB geometric verification
  - Covisibility graph loop closure (3D voxel overlap)
    |
    v
[Optional: Sparse point BA (200 landmark joint optimization)]
    |
    v
[Export to COLMAP / nerfstudio / PLY / .splat]
    |
    v
[Optional: Train Gaussian Splatting with gsplat]

Architecture

src/
├── chunked_pipeline.py       # Main orchestrator
├── factor_graph.py           # Batch LM optimization
├── isam2_backend.py          # iSAM2 incremental solver
├── covisibility.py           # 3D covisibility graph
├── point_ba.py               # Joint point + pose BA
├── multi_backend.py          # VGGT + MASt3R ensemble
├── keyframe_selection.py     # Smart frame selection
├── depth_fusion.py           # Multi-view depth consistency
├── trajectory_smoothing.py   # SE(3) temporal smoothing
├── uncertainty.py            # Calibrated pose uncertainty
├── loop_closure.py           # DINOv2 appearance matching
├── cross_chunk_align.py      # 3D point RANSAC alignment
├── sl4_graph.py              # SL(4) for uncalibrated cameras
├── vggt_wrapper.py           # VGGT model interface
├── metrics.py                # ATE, RPE evaluation
├── data_loaders.py           # TUM, Replica loaders
├── gaussian_render.py        # gsplat training
└── exporters/
    ├── colmap_export.py      # COLMAP sparse model (text + binary)
    ├── nerfstudio_export.py  # transforms.json
    ├── ply_export.py         # Colored point cloud
    └── splat_export.py       # .splat format for web viewers

Key Features

FeatureDescription
One-command pipelineVideo → 3D in a single command
COLMAP replacementDirect COLMAP-format output for any 3DGS pipeline
8GB GPU supportAuto-detects VRAM and reduces chunk size
iSAM2 BackendO(log n) incremental optimization
Covisibility GraphFinds loop closures via shared 3D geometry
Point BAJoint pose + landmark optimization
Multi-backendEnsemble VGGT + MASt3R for better coverage
Robust KernelsCauchy/Huber M-estimators for outlier rejection
Depth FusionMulti-view consistency filtering
Trajectory SmoothingSpline/Savitzky-Golay/bilateral on SE(3)
Uncertainty EstimationCalibrated 6-DOF pose uncertainty

Limitations

  • Not real-time (batch offline processing)
  • Accuracy below dedicated SLAM systems (ORB-SLAM3, DROID-SLAM) on well-supported sequences
  • Loop closure relative poses derived from stitched trajectory (circular when drift is large)
  • DINOv2 may match repetitive textures incorrectly (ORB verification catches most)

Requirements

  • CUDA GPU (8GB+ with auto chunk reduction, 24GB for default settings)
  • Python 3.10+
  • PyTorch, GTSAM, VGGT

License

MIT