Skip to content

OpsiClear/densifier

Repository files navigation

3D Reconstruction & Point Cloud Densification Library

Production-ready pipeline for sparse SfM, dense initialization, and depth-based densification

GIM GUI Preview

Overview

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

Key Features

Graphical User Interface

  • 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

Complete 3D Reconstruction Pipeline

  • 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

Hybrid Densification (RECOMMENDED)

  • 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

Dense Point Cloud Generation (GIM-Only)

  • 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

Depth-Based Densification (MoGe-Only or Standalone)

  • 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

Production Features

  • 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-name pattern for ease of use
  • Tested & Validated: 90% test coverage, all critical functionality production-ready

Quick Start

# 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

Installation

Quick Setup with UV (Recommended)

# Install UV package manager


# Clone and setup
git clone --recursive this repo
uv sync

Installing pycolmap (Required for 3D Reconstruction)

Linux/macOS
# Install COLMAP first (see official guide), then:
uv add /path/to/colmap

or if you don't want to use colmap gpu features

uv add pycolmap
Windows
# 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 pycolmap

Model Weights

Required: GIM Weights

Some gim-model weights can be found in this google drive.

Auto-Downloaded:

  • MoGe: Downloads automatically or run uv run download_models.py
  • YOLO11: Downloads on first use from ultralytics

Usage

Graphical User Interface (GUI)

Launch the interactive GUI for an easy-to-use visual interface:

uv run python -m gui

Features:

  • 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:

  1. Select function tab (Reconstruction, Hybrid Densification, etc.)
  2. Configure parameters using the form fields
  3. Click "Run" to start processing (auto-switches to Console Output)
  4. Click "View" buttons to visualize results (auto-switches to Point Cloud Viewer)

Command-Line Interface (CLI)

CLI Interface: All scripts use a consistent, flat argument structure with --input-path:

  • --input-path specifies the root directory containing images/ and sparse/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/)

1. Sparse 3D Reconstruction

# 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.h5

Output: inputs/bicycle/sparse/0/ (COLMAP model)

2. Object-Centric Reconstruction

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)

3. Sparse Point Cloud Filtering

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.05

Output: 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 --*-subdir parameters

4. Hybrid Densification (RECOMMENDED)

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 quickly

Output: 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_masks

Output: 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.JPGDSC_0001.JPG.png
Alternative: MoGe-Only Depth Densification

For monocular depth only (no GIM matching):

Basic Usage

# 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-dirs

Output: COLMAP model with densified points in inputs/bicycle/sparse/0_depth_densified/


Pre-computing MoGe Data (Recommended for Iteration)

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.JPGDSC_0001.npy (stem only, no extension)

Advanced Filtering Options

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 4

Correspondence 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-correspondence

Sparse 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-bounds

Scene-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.5

Disable 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-points

Model Selection

Choose 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)


Batch Processing

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

Pipeline

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)

Module Architecture

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

Performance (RTX 4090, bicycle dataset with 194 images)

Hybrid Densification (RECOMMENDED)

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!

Legacy Workflows (Single-Stage)

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.

Advanced Topics

EDGS Sampling Control

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

Pairing Strategies

# 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 20

Custom Segmentation Classes

from 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
)

Advanced Configuration

Filtering Parameters Explained

All densification methods use multi-view consistency filtering to remove floater points. Understanding these parameters helps tune for different scene types:

Core Filtering Parameters

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_threshold views 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.15

Scene-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

Depth Refinement Filters

Two-stage filtering prevents wild extrapolation during MoGe depth refinement:

1. Correspondence Range Filter

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

2. Sparse Depth Bounds Filter

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

Method Selection Guide

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

Acknowledgments

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)

License

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.

About

3dgs densifier using gim + moge

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors