Production-ready pipeline for sparse SfM, dense initialization, and depth-based densification
Production-ready pipeline for 3D reconstruction and point cloud densification (90% test coverage, all critical functionality validated):
- Graphical User Interface: Easy-to-use GUI with real-time visualization
- Sparse SfM: COLMAP with SuperPoint+LightGlue
- Hybrid Densification: GIM stereo matching + MoGe depth estimation (RECOMMENDED)
- Dense Initialization: GIM-based dense point cloud generation (RoMa, DKM, LoFTR, LightGlue)
- Depth Densification: MoGe monocular depth estimation (standalone or hybrid)
- Semantic Filtering: YOLO11 dynamic object filtering
- Object-Centric Mode: Reconstruct scenes or single objects
- Interactive GUI: Modern desktop interface with tab-based workflow selection
- Real-time Visualization: Built-in 3D point cloud viewer with camera frustums
- Console Monitoring: Live progress tracking and debug output
- Configuration Management: Save/load YAML configs, preset management
- Smart Defaults: Auto-fill paths and intelligent parameter suggestions
- Sparse SfM: COLMAP integration with SuperPoint+LightGlue
- Dynamic Object Filtering: YOLO11-based semantic segmentation (filters people, cars, etc.)
- Object-Centric Mode: Reconstruct single objects with custom masks
- Multiple Pairing Strategies: Exhaustive, sequential, retrieval, pose-based, covisibility
- Two-Stage Pipeline: GIM stereo matching → Coverage analysis → MoGe depth for gaps
- 40-60% Faster: Only processes depth where GIM coverage is insufficient
- Better Quality: Combines stereo accuracy with monocular coverage
- Unified Filtering: Multi-view consistency check on ALL points together
- Smart Coverage Analysis: Identifies regions needing additional densification
- GIM-Based Dense Init: Four matchers (RoMa, DKM, LoFTR, LightGlue)
- EDGS Sampling: Efficient Dense Geometric Sampling with configurable confidence/coverage
- GPU-CPU Pipelining: 2x faster processing with concurrent GPU matching and CPU triangulation
- Advanced Geometric Filtering: Sampson error, parallax checks, reprojection validation
- MoGe Integration: Microsoft's MoGe v2 for metric-scale depth estimation
- GPU-Accelerated Refinement: PCHIP interpolation for depth alignment with sparse points
- Multi-View Consistency: Affine depth formula-based floater removal
- Point Sampling: Edge-aware intelligent sampling for high-detail regions
- Cross-Platform: Windows, Linux, macOS with UV package manager
- OpenCV-based: All image I/O uses OpenCV (no Pillow dependency)
- Auto Model Downloads: YOLO11, MoGe download automatically
- Simple CLI: Flat argument structure with
--scene-namepattern for ease of use - Tested & Validated: 90% test coverage, all critical functionality production-ready
# 1. Clone and setup
git clone --recursive this repo
uv sync
# 2. Download models
# GIM models: Download from Google Drive
# https://drive.google.com/drive/folders/13LXYmdMaDcSnT7aZVWLwlbc5YzTCIxEc?usp=sharing
# MoGe models: Run download script
uv run download_models.py
# 3. Launch GUI (easiest way to get started)
uv run python -m gui
# OR use CLI for basic reconstruction
mkdir -p inputs/my_scene/images
# ... add your images ...
uv run scripts/reconstruction/reconstruction.py --input-path inputs/my_scene# Install UV package manager
# Clone and setup
git clone --recursive this repo
uv syncLinux/macOS
# Install COLMAP first (see official guide), then:
uv add /path/to/colmapor if you don't want to use colmap gpu features
uv add pycolmapWindows
# VCPKG and COLMAP must be installed
uv add ./external/colmap `
--config-settings="cmake.define.CMAKE_TOOLCHAIN_FILE=./external/vcpkg/scripts/buildsystems/vcpkg.cmake" `
--config-settings="cmake.define.VCPKG_TARGET_TRIPLET=x64-windows"or if you don't want to use colmap gpu features
uv add pycolmapSome gim-model weights can be found in this google drive.
- MoGe: Downloads automatically or run
uv run download_models.py - YOLO11: Downloads on first use from ultralytics
Launch the interactive GUI for an easy-to-use visual interface:
uv run python -m guiFeatures:
- Tab-based Function Selection: Switch between reconstruction, densification, and filtering workflows
- Visual Configuration: Form-based parameter input with tooltips and validation
- Real-time Console Output: Monitor progress and debug information
- Point Cloud Viewer: Built-in 3D visualization of reconstruction results
- Configuration Presets: Fast/Balanced/Quality presets for quick setup
- Save/Load Configs: Store and reuse YAML configuration files
- Path Auto-fill: Automatically suggests output paths based on input
- View Buttons: Quick access to visualize input and output reconstructions
Workflow:
- Select function tab (Reconstruction, Hybrid Densification, etc.)
- Configure parameters using the form fields
- Click "Run" to start processing (auto-switches to Console Output)
- Click "View" buttons to visualize results (auto-switches to Point Cloud Viewer)
CLI Interface: All scripts use a consistent, flat argument structure with --input-path:
--input-pathspecifies the root directory containingimages/andsparse/0/subdirectories- Subdirectories can be customized with
--images-subdir,--sparse-subdir, etc. - Outputs are auto-generated within the input directory (e.g.,
inputs/bicycle/sparse/0_filtered/)
# Prepare input
mkdir -p inputs/bicycle/images
# ... place images in images/ folder ...
# Basic (with YOLO11 filtering)
uv run scripts/reconstruction/reconstruction.py --input-path inputs/bicycle
# Fast (skip segmentation)
uv run scripts/reconstruction/reconstruction.py --input-path inputs/bicycle --skip-segmentation
# Different segmentation models (s=fastest, m=balanced, l=accurate)
uv run scripts/reconstruction/reconstruction.py --input-path inputs/bicycle --segmentation-model yolo11s-seg
# Different pairing strategies
uv run scripts/reconstruction/reconstruction.py --input-path inputs/bicycle --pairing-method sequential
uv run scripts/reconstruction/reconstruction.py --input-path inputs/bicycle --pairing-method retrieval --descriptors descriptors.h5Output: inputs/bicycle/sparse/0/ (COLMAP model)
Reconstruct single objects with custom masks (255=keep, 0=filter):
# Prepare masks: inputs/statue/object_masks/image.ext.png
uv run scripts/reconstruction/reconstruction.py --input-path inputs/statue \
--object-masks-subdir object_masks| Mode | Keeps | Use Case | Mask Source |
|---|---|---|---|
| Scene (default) | Static scene | Buildings | Auto (YOLO11) |
| Object-centric | Masked object | Products | Manual (SAM) |
Clean sparse COLMAP reconstructions without generating dense points. Uses MoGe depth consistency to remove floater points.
Use Cases:
- Clean sparse reconstructions before MVS or Gaussian Splatting
- Improve COLMAP quality by removing outliers
- Prepare for downstream tasks requiring high-quality sparse points
# Basic filtering (auto-outputs to {input_path}/sparse/0_filtered/)
uv run scripts/depth_densification/filter_sparse_colmap.py \
--input-path inputs/bicycle
# With pre-computed MoGe data (much faster: ~2-5 min vs 10-15 min)
uv run scripts/depth_densification/filter_sparse_colmap.py \
--input-path inputs/bicycle \
--depth-subdir "moge_output/depth" \
--normal-subdir "moge_output/normal"
# Strict filtering (removes more floaters)
uv run scripts/depth_densification/filter_sparse_colmap.py \
--input-path inputs/bicycle \
--filtering-level strict
# Custom output path
uv run scripts/depth_densification/filter_sparse_colmap.py \
--input-path inputs/bicycle \
--output-path "outputs/my_filtered_model"
# Custom filtering parameters
uv run scripts/depth_densification/filter_sparse_colmap.py \
--input-path inputs/bicycle \
--vote-threshold 3 \
--depth-threshold 0.95 \
--depth-offset 0.05Output: Filtered COLMAP reconstruction in inputs/bicycle/sparse/0_filtered/
- Preserves cameras and images unchanged
- Only filters bad points (floaters, outliers, noise)
- Typically removes 10-30% of sparse points
Benefits:
- Fast with pre-computed: Skip MoGe inference if depth/normal already available
- Independent: Doesn't require full densification pipeline
- Quality presets: Easy strict/normal/lenient switching
- Subdirectory overrides: Customize any path with
--*-subdirparameters
Combines GIM stereo matching with MoGe depth estimation for best results:
# Recommended: GIM-LoFTR + MoGe (best speed/quality balance)
uv run scripts/densification/run_hybrid_densification.py \
--input-path inputs/bicycle \
--gim-matcher gim_loftr
# Highest quality: GIM-RoMa + MoGe
uv run scripts/densification/run_hybrid_densification.py \
--input-path inputs/bicycle \
--gim-matcher gim_roma
# Custom coverage threshold (only fill regions with <20% GIM coverage)
uv run scripts/densification/run_hybrid_densification.py \
--input-path inputs/bicycle \
--gim-matcher gim_loftr \
--coverage-threshold 0.2
# Skip depth stage (GIM only with unified filtering)
uv run scripts/densification/run_hybrid_densification.py \
--input-path inputs/bicycle \
--skip-depth
# Use pre-computed MoGe depth/normal maps (faster iteration)
uv run scripts/densification/run_hybrid_densification.py \
--input-path inputs/bicycle \
--depth-subdir "moge_output/depth" \
--normal-subdir "moge_output/normal"Pre-computing MoGe Data (Recommended for Iteration):
# Step 1: Pre-compute depth/normal once (5-10 min, one-time cost)
uv run scripts/depth_densification/run_moge_inference.py \
--input-dir "inputs/bicycle/images" \
--output-dir "inputs/bicycle/moge_output" \
--separate-dirs
# Step 2: Run hybrid densification using pre-computed data (~50% faster)
uv run scripts/densification/run_hybrid_densification.py \
--input-path inputs/bicycle \
--depth-subdir "moge_output/depth" \
--normal-subdir "moge_output/normal"
# Benefits: Skip expensive MoGe inference, experiment with GIM/filtering parameters quicklyOutput: inputs/bicycle/sparse/0_hybrid_densified/ (COLMAP model with ~3.75M points)
Key Parameters:
--gim-matcher: Matcher choice (gim_loftr recommended, gim_roma for quality)--coverage-threshold: Fill regions with <N GIM coverage (0.0-1.0, default: 0.2)--filtering-level: Preset (strict/normal/lenient, default: normal)--vote-threshold: Custom floater filtering (default: 5)--skip-depth: Skip MoGe stage (GIM only)--skip-gim: Skip GIM stage (depth only)
Benefits:
- 40-60% faster than running GIM + depth separately
- Better quality: Stereo accuracy + monocular coverage
- Clean output: Unified filtering eliminates duplicates
Alternative: GIM-Only Dense Initialization
For stereo matching only (no depth estimation):
# High-quality dense initialization
uv run -m gim_densifier --input-path inputs/bicycle --matcher gim_roma
# Fast mode (fewer references and neighbors)
uv run -m gim_densifier \
--input-path inputs/bicycle \
--matcher gim_dkm \
--num-refs 0.3 \
--neighbors-per-ref 2 \
--matches-per-ref 5000
# Custom parameters
uv run -m gim_densifier \
--input-path inputs/bicycle \
--matcher gim_roma \
--num-refs 0.5 \
--neighbors-per-ref 4 \
--matches-per-ref 12000 \
--use-advanced-filtering
# Object-centric densification with masks
uv run -m gim_densifier \
--input-path inputs/statue \
--matcher gim_roma \
--object-masks-subdir object_masksOutput: inputs/bicycle/sparse/0_gim_densified/ (COLMAP model)
Configuration:
--num-refs: Reference image ratio (0.3-1.0, default: 0.75)--neighbors-per-ref: Matching neighbors (2-6, default: 4)--matches-per-ref: Points per reference (5000-15000, default: 12000)--multinomial-ratio: Confidence/coverage balance (0.0-1.0, default: 0.7)--use-advanced-filtering: Enhanced geometric validation (default: True)--object-masks-subdir: Subdirectory with object masks (naming:image.ext.png)
Object Masking:
- Same mask convention as reconstruction: 255 (white) = keep, 0 (black) = filter
- Focus densification on specific objects (statues, products, etc.)
- Mask file naming:
DSC_0001.JPG→DSC_0001.JPG.png
Alternative: MoGe-Only Depth Densification
For monocular depth only (no GIM matching):
# Basic mode (auto-outputs to {input_path}/sparse/0_depth_densified/)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle
# Custom output path
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--output-path "outputs/my_densified_model"
# MoGe inference only (depth/normal/mask without COLMAP)
uv run scripts/depth_densification/run_moge_inference.py \
--input-dir "inputs/bicycle/images" \
--output-dir "inputs/bicycle/moge_output" \
--separate-dirsOutput: COLMAP model with densified points in inputs/bicycle/sparse/0_depth_densified/
2-Step Workflow for faster experimentation:
# Step 1: Pre-compute depth/normal maps once (5-10 min, one-time)
uv run scripts/depth_densification/run_moge_inference.py \
--input-dir "inputs/bicycle/images" \
--output-dir "inputs/bicycle/moge_output" \
--separate-dirs
# Creates: depth/{stem.npy}, normal/{stem.npy}, masks/{stem.png}
# Step 2: Run densification with pre-computed data (1-2 min, fast iteration)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--depth-subdir "moge_output/depth" \
--normal-subdir "moge_output/normal" \
--masks-subdir "moge_output/masks"Benefits:
- Skip expensive MoGe inference (saves 5-10 min per run)
- Experiment with filtering parameters quickly
- Inspect/modify depth maps before densification
- File naming:
DSC_0001.JPG→DSC_0001.npy(stem only, no extension)
Filtering Presets:
# Strict filtering (removes more floaters, highest quality)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--filtering-level strict
# Lenient filtering (keeps more points, fewer removals)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--filtering-level lenient| Preset | Vote Threshold | Depth Threshold | Offset | Use Case |
|---|---|---|---|---|
| strict | 4 | 0.9 | 0.1m | Maximum quality, removes most floaters |
| normal | 5 | 0.85 | 0.1m | Balanced (default) |
| lenient | 5 | 0.85 | 0.15m | Keep more points |
COLMAP Quality Filtering:
Pre-filter sparse points before depth refinement:
# Default: reprojection error < 1.0px, track length ≥ 3
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--filter-colmap-quality \
--max-reprojection-error 1.0 \
--min-track-length 3
# High-quality COLMAP (strict thresholds)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--max-reprojection-error 0.8 \
--min-track-length 4Correspondence Range Filtering:
Controls extrapolation beyond COLMAP correspondence range:
# Indoor/conservative (tight extrapolation bounds)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/indoor \
--correspondence-extrapolation-lower 0.05 \
--correspondence-extrapolation-upper 0.1
# Outdoor/permissive (allow more extrapolation for distant objects)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/outdoor \
--correspondence-extrapolation-lower 0.2 \
--correspondence-extrapolation-upper 0.5
# Disable (trust refinement completely, rely on multi-view filtering)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--no-filter-correspondenceSparse Depth Bounds Filtering:
Filters points outside sparse COLMAP depth range (camera space):
# Enabled by default with 30% margin
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--filter-sparse-depth-bounds \
--sparse-depth-margin 0.3
# Disable for incomplete sparse coverage (outdoor scenes, untextured areas)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/outdoor \
--no-filter-sparse-depth-boundsScene-Specific Configurations:
# Indoor/object-centric: Conservative, tight bounds
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/indoor \
--filtering-level strict \
--correspondence-extrapolation-lower 0.05 \
--correspondence-extrapolation-upper 0.1 \
--sparse-depth-margin 0.05
# Outdoor/multi-scale: Correspondence filter only
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/outdoor \
--no-filter-sparse-depth-bounds \
--correspondence-extrapolation-upper 0.5Disable Sparse Point Filtering:
By default, sparse COLMAP points are also filtered. To only filter dense points:
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--no-filter-sparse-pointsChoose different MoGe models for speed/quality trade-offs:
# Default: ViT-Large with normals (recommended, 331M params)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--moge-checkpoint "weights/moge/moge-2-vitl-normal/model.pt"
# Faster: ViT-Base with normals (110M params)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--moge-checkpoint "weights/moge/moge-2-vitb-normal/model.pt"
# Fastest: ViT-Small with normals (30M params)
uv run scripts/depth_densification/run_pipeline.py \
--input-path inputs/bicycle \
--moge-checkpoint "weights/moge/moge-2-vits-normal/model.pt"| Model | Size | Speed | Quality | Use Case |
|---|---|---|---|---|
moge-2-vitl-normal |
331M | Slow | Best | Production |
moge-2-vitb-normal |
110M | Medium | Good | Balanced |
moge-2-vits-normal |
30M | Fast | Fair | Testing/rapid iteration |
Download models: uv run download_models.py (see Installation section)
Process multiple scenes in one command:
# Batch process all scenes in inputs/ directory
uv run scripts/depth_densification/run_batch.py \
--data-dir "inputs" \
--results-dir "outputs"
# Expected structure:
# inputs/
# ├── scene1/
# │ ├── sparse/0/
# │ └── images/
# ├── scene2/
# │ ├── sparse/0/
# │ └── images/
# ...Benefits: Automated processing of entire datasets
Recommended Workflow:
Images → Sparse SfM → Hybrid Densification → Final Cloud
(COLMAP) (GIM + MoGe) (~3.75M points)
├─ Stage 1: GIM dense matching
├─ Coverage analysis
├─ Stage 2: MoGe depth for gaps
└─ Unified filtering
Alternative Workflows:
# GIM-Only (stereo matching)
Images → Sparse SfM → GIM Dense Init → Final Cloud
(COLMAP) (RoMa/DKM/LoFTR)
# MoGe-Only (monocular depth)
Images → Sparse SfM → MoGe Depth → Final Cloud
(COLMAP) (ViT-L)
gim/
├── scripts/
│ ├── reconstruction/ # Sparse SfM pipeline
│ │ └── reconstruction.py # Main reconstruction script
│ ├── densification/ # Hybrid densification (RECOMMENDED)
│ │ └── run_hybrid_densification.py # GIM + MoGe unified pipeline
│ ├── depth_densification/ # MoGe-only depth densification
│ │ ├── run_pipeline.py # Single scene
│ │ ├── run_batch.py # Batch processing
│ │ └── run_moge_inference.py # MoGe inference only
│ ├── benchmarks/ # Performance benchmarking
│ └── demos/
│ └── match.py # Image matching demo
├── gim_densifier/ # GIM-only dense initialization
│ ├── dense_init.py # Main CLI
│ ├── dense_matcher.py # Unified matcher interface
│ └── utils/
│ ├── sampling.py # EDGS sampling
│ └── geometry.py # Geometric filtering
├── depth_densifier/ # Depth densification core (shared)
│ ├── depth_refiner.py # GPU-accelerated refinement
│ ├── point_sampler.py # Edge-aware sampling
│ ├── floater_filter.py # Multi-view filtering
│ └── utils.py # Depth densification utilities
├── hloc/ # COLMAP integration
│ ├── extract_features.py # Feature extraction + masking
│ ├── match_features.py # Feature matching
│ ├── segmentation.py # YOLO11 segmentation
│ └── reconstruction.py # COLMAP interface
├── networks/ # Network implementations
│ ├── roma/ # GIM-RoMa
│ ├── dkm/ # GIM-DKM
│ ├── loftr/ # GIM-LoFTR
│ ├── lightglue/ # LightGlue
│ └── moge/ # MoGe (inference-only)
└── weights/ # Pre-trained weights
| Matcher | Points | Time | Speed Rank | Quality Rank | Best For |
|---|---|---|---|---|---|
| GIM-LoFTR | 3.72M | 266s | 🥈 2nd | 3rd | Best balance |
| GIM-LightGlue | 3.62M | 233s | 🥇 1st (fastest) | 4th | Speed-critical |
| GIM-RoMa | 3.76M | 414s | 3rd | 🥇 1st (highest) | Maximum quality |
| GIM-DKM | 3.75M | 460s | 4th (slowest) | 2nd | Baseline |
- Recommended: GIM-LoFTR for best speed/quality balance (266s, 3.72M points)
- Filtering: Normal preset (vote=5, depth=0.85, offset=0.1) is optimal
- Point variation: Only 3.8% difference between best and worst matchers
- Speed variation: 97% difference (233s to 460s) - matcher choice matters!
| Stage | Time | Notes |
|---|---|---|
| Sparse SfM | ~8 min | SuperPoint + LightGlue + COLMAP |
| GIM-only Dense Init | ~31s | GPU-CPU pipelined, 19 refs |
| MoGe-only Depth | ~4 min | Standalone depth densification |
See BENCHMARK_RESULTS.md for detailed analysis.
The multinomial_ratio parameter balances confidence-based vs spatial coverage sampling:
# Pure spatial coverage (uniform)
--multinomial-ratio 0.0
# Balanced (default)
--multinomial-ratio 0.7
# Pure confidence-based (traditional)
--multinomial-ratio 1.0# Exhaustive (small datasets, <500 images)
--pairing-method exhaustive
# Sequential (video sequences, ordered)
--pairing-method sequential --num-matched 10
# Retrieval (large unordered, >1000 images)
--pairing-method retrieval --descriptors descriptors.h5 --num-matched 50
# Covisibility (refine existing reconstruction)
--pairing-method covisibility --reconstruction-path sparse/0 --num-matched 20from hloc.segmentation import SegmentationModel
# Filter only people and cars (not animals)
custom_classes = [0, 2] # COCO: person, car
model = SegmentationModel(
model_name='yolo11s-seg',
dynamic_classes=custom_classes
)All densification methods use multi-view consistency filtering to remove floater points. Understanding these parameters helps tune for different scene types:
| Parameter | Default | Range | Description |
|---|---|---|---|
vote_threshold |
5 | 3-7 | Min views where point must be inconsistent to be removed |
depth_threshold |
0.85 | 0.8-0.95 | Depth consistency ratio (lower = stricter) |
depth_offset |
0.1m | 0.05-0.2m | Absolute depth tolerance |
How it works:
- For each 3D point, check consistency across all viewing cameras
- Inconsistent view:
projected_depth < threshold × refined_depth - offset - If ≥
vote_thresholdviews are inconsistent → mark as floater and remove
Tuning Guidelines:
# Maximum quality (strict) - Removes most floaters
--vote-threshold 4 \
--depth-threshold 0.9 \
--depth-offset 0.1
# Balanced (normal) - Default preset
--vote-threshold 5 \
--depth-threshold 0.85 \
--depth-offset 0.1
# Keep more points (lenient) - Fewer removals
--vote-threshold 5 \
--depth-threshold 0.85 \
--depth-offset 0.15Scene-Specific Recommendations:
| Scene Type | Preset | Notes |
|---|---|---|
| Indoor | strict | Bounded space, high consistency expected |
| Outdoor | normal | Mix of near/far content, balanced approach |
| Object-centric | strict | Clean object reconstruction, remove all noise |
| Large-scale | lenient | Distant points may have lower consistency |
Two-stage filtering prevents wild extrapolation during MoGe depth refinement:
What it filters: Pixels where MoGe depth falls outside COLMAP correspondence range
Example: If COLMAP sparse points exist at MoGe depths [2.5m, 8.0m]:
- With
lower=0.1, upper=0.3(defaults):- Min valid: 2.5 × (1 - 0.1) = 2.25m
- Max valid: 8.0 × (1 + 0.3) = 10.4m
- Pixels outside [2.25m, 10.4m] are filtered
When to adjust:
| Scenario | lower |
upper |
Reason |
|---|---|---|---|
| Uncertain reconstruction | 0.05 | 0.1 | Conservative, trust correspondences |
| Distant objects | 0.2 | 0.5-1.0 | Allow far-field extrapolation |
| Consistent MoGe scale | - | - | Disable filter entirely |
| Indoor/bounded | 0.05 | 0.1 | Limited depth range |
Disable when: MoGe scale is highly consistent with COLMAP, or you want to rely solely on multi-view filtering
What it filters: 3D points with camera-space depth outside sparse COLMAP depth range
How it works:
- Compute min/max depth of sparse points in each camera view
- Add margin (default 30% of depth range)
- Filter dense points outside [min - margin, max + margin]
When to enable/disable:
✅ Enable for:
- Indoor scenes with complete sparse coverage
- Object-centric captures (all depth within bounds)
- Preventing far-field noise
❌ Disable for:
- Outdoor scenes with incomplete sparse coverage
- Untextured walls/regions missing sparse points
- Large depth range variations (close + very distant)
Margin tuning:
0.0= Strict (only within sparse range)0.1= Conservative (10% beyond)0.3= Default (30% beyond, recommended)1.0+= Very permissive
Decision flowchart:
Goal: Dense point cloud?
│
├─ Best overall quality + speed → Hybrid Densification
│ - GIM stereo for textured regions
│ - MoGe depth for coverage gaps
│ - 40-60% faster than separate runs
│
├─ Stereo accuracy only → GIM Dense Init
│ - High-texture scenes
│ - No monocular depth needed
│ - Choose matcher: LoFTR (fast) or RoMa (quality)
│
├─ Monocular depth only → MoGe Depth Densifier
│ - Low-texture scenes
│ - Wide coverage needed
│ - Pre-compute for fast iteration
│
└─ Just clean sparse points → Sparse Filtering
- No dense points needed
- Prepare for MVS/Gaussian Splatting
- Fast with pre-computed MoGe
Matcher Selection (GIM/Hybrid):
| Matcher | Speed Rank | Quality Rank | Best For |
|---|---|---|---|
| GIM-LoFTR | 🥈 2nd | 3rd | Recommended: Best balance |
| GIM-LightGlue | 🥇 1st | 4th | Speed-critical applications |
| GIM-RoMa | 3rd | 🥇 1st | Maximum quality |
| GIM-DKM | 4th | 2nd | Baseline/comparison |
Scene Type Recommendations:
| Scene Type | Method | Config |
|---|---|---|
| Urban | Hybrid (LoFTR) | normal filtering |
| Indoor | Hybrid (RoMa) | strict filtering, tight bounds |
| Object | GIM (RoMa) + masks | strict filtering |
| Outdoor | Hybrid (LoFTR) | normal filtering, disable sparse bounds |
| Large-scale | Hybrid (LightGlue) | lenient filtering |
Built with:
- GIM - Image matching (MIT License)
- MoGe - Monocular depth (MIT/Apache 2.0)
- COLMAP - Structure-from-Motion (BSD 3-Clause)
- LightGlue - Feature matching (Apache 2.0)
- Ultralytics - YOLO11 (AGPL v3)
- MIT-SemSeg - Semantic segmentation (BSD 3-Clause)
GPL v3 License. See LICENSE for details.
This project is licensed under the GNU General Public License v3 (GPL v3) to ensure compatibility with incorporated concepts from LichtFeld Studio (GPL v3). All third-party components retain their respective licenses. See licenses/ directory for full license texts and attributions.
