diff --git a/open_vocabulary_segmentation/geolangsplat/.gitignore b/open_vocabulary_segmentation/geolangsplat/.gitignore new file mode 100644 index 0000000..f76fb49 --- /dev/null +++ b/open_vocabulary_segmentation/geolangsplat/.gitignore @@ -0,0 +1,56 @@ +# Python +__pycache__/ +*.pyc +*.egg-info/ +build/ +dist/ +.pytest_cache/ +.mypy_cache/ + +# Local query/segmentation outputs and large data artifacts (never commit splats) +*.ply +*.npz +*.csv +*.png +*.zip +*.glscache +outputs/ +runs/ + +# ...but do ship the README example figures +!examples/ +!examples/*.png + +# Local benchmark / evaluation run directories +eval_out/ +fast_bench/ +id_bench/ +robust_out/ +routed_bench/ +frgs_logs/ + +# Local design notes (not shipped) +ARCHITECTURE.md +SLIDES.md +INTEGRATION.md +BENCHMARKS.md + +# Deferred identity field (seed/click grouping) -- lands in a later change +geolangsplat/identity.py +tests/test_identity.py + +# Local benchmark / evaluation code and scripts (not part of this example) +geolangsplat/eval/ +scripts/bench_inference.py +scripts/bench_fast_query.py +scripts/bench_identity.py +scripts/bench_robustness.py +scripts/bench_scenes_aerial_sat.json +scripts/eval_scenes.py +scripts/eval_benchmark.py +scripts/run_lerf_eval.sh +scripts/try_instances.py +scripts/safety_park_demo.sh +tests/test_eval_align.py +tests/test_eval_lerf_ovs.py +tests/test_eval_metrics.py diff --git a/open_vocabulary_segmentation/geolangsplat/README.md b/open_vocabulary_segmentation/geolangsplat/README.md new file mode 100644 index 0000000..470ef16 --- /dev/null +++ b/open_vocabulary_segmentation/geolangsplat/README.md @@ -0,0 +1,310 @@ +# GeoLangSplat + +**Training-free, open-vocabulary 3D segmentation for Gaussian splats.** Give it a text +prompt (`"house"`, `"road"`, `"tree"`, …) and a splat; it returns which Gaussians belong to +that concept — as a segmented `.ply`, a highlight overlay, or a per-Gaussian report. One +engine serves **aerial** (oblique drone), **satellite** (near-nadir), and **object/interior** +(360° inward) captures; the default `auto` recipe reads the scene geometry and synthesizes its +own views, so the common case is `gls segment scene.ply "thing"` with no flags. + +

+ 18 building instances segmented on SafetyPark +

+

+ one building lifted out as its own .ply +   + another building lifted out as its own .ply +

+

gls catalog scene.ply building  -->  every building becomes its own instance, then lifts out as a .ply

+ +--- + +## How it works + +``` +text prompt + | + v +SAM3 segments each view --> alpha-weighted back-projection --> per-Gaussian scores + ^ | +views of the splat competition + cleanup <--+ +(auto-synthesized, or your real photos) | + v + segmented .ply / overlay .ply / per-Gaussian report +``` + +- **Training-free.** No per-scene optimization, no CLIP. We run SAM3 over views of the splat + and lift its per-pixel scores into 3D --> one continuous score per Gaussian. A brand-new + scene is usable in seconds; quality just tracks SAM3 and the reconstruction. +- **Views are the quality knob.** The model can only label what SAM3 sees. The `auto` recipe + reads the scene and picks the views for you --> flat/top-down captures get a nadir + oblique + ladder, rooms and objects get a gravity-up dome. Or point it at the scene's real photos with + `--view-source images --sfm`. +- **One code path, two speeds.** One-shot (default) streams the lift one chunk at a time + (encode --> score --> project --> evict), so peak VRAM stays flat no matter how big the scene + is. Keep an engine warm with `gls serve` and repeat queries come back in ~1-2 s. + +--- + +## Installation + +GeoLangSplat runs inside an existing **fVDB** environment (the fvdb monorepo build, with +`torch` + `fvdb-reality-capture`; not on PyPI). It is light --> it adds only `numpy`, `pillow`, +`tyro`, and the `gls` command. + +1. **Install into your fVDB env:** + + ```bash + source /path/to/fvdb-env/bin/activate + pip install -e . # registers the `gls` command + ``` + +2. **Add SAM3** — the 2D segmenter used by `segment`/`bake`. It is not on PyPI: install it from + source so that `import sam3` works. It loads lazily, so it is *not* needed to import the + package, run the tests (SAM3 is mocked), or run `gls check`. + +3. **Point at a checkpoint and run the preflight:** + + ```bash + export GEOLANGSPLAT_SAM_CKPT=/path/to/sam3.1_multiplex.pt + gls doctor # checks GPU/bf16, fvdb, SAM3, checkpoint + ``` + +For a one-shot provision (e.g. baking a lab image), `setup.sh` downloads the checkpoint +(`GEOLANGSPLAT_SAM_URL=...`), installs the package, and runs `gls doctor` so the environment +ships ready — the notebook/first run then needs no installs. + +--- + +## Python / notebook + +```python +from geolangsplat import segment, GeoLangSplatConfig + +# single prompt -> per-Gaussian selection, written to an overlay .ply +res = segment( + "scene.ply", "building", + config=GeoLangSplatConfig(low_vram=True), # bound VRAM (~6-7 GB) + output="ply_overlay", out_path="building.ply", +) +print(res.num_selected, "/", res.scores.shape[0]) + +# multiple prompts -> multi-class labelling (argmax + confidence/ambiguity gates) +res = segment("scene.ply", ["building", "tree", "grass", "road"], recipe="satellite") +res.to_report("labels.csv") # index,x,y,z,label_id,label,score (+ legend.json) +``` + +`segment(...)` returns a `SegmentResult` with per-Gaussian `scores`, a boolean `selected` +mask, and (multi-prompt) `label_ids`, all in **input `.ply` order**. Pass a `GaussianSplat3d` +or a path; every `GeoLangSplatConfig` field is settable (explicit fields beat a recipe). Reuse +`GeoLangSplatEngine` to build once and query many times. + +### Use as a post-processing step + +GeoLangSplat is a **self-contained post-processing stage** over any reconstruction: in goes a +Gaussian splat (a `.ply` or in-memory `fvdb.GaussianSplat3d`, plus an optional COLMAP scene), +out come per-Gaussian labels in input order. With no per-scene training and no required upstream +state, it drops in after a reconstruction step (e.g. fvdb-reality-capture) — consume +`result.selected` / `result.label_ids` directly or persist `to_ply_*` / `to_report`. + +Display inline in a notebook without an interactive viewer: + +```python +from IPython.display import Image +import subprocess; subprocess.run(["gls", "render", "building.ply", "-o", "building.png"]) +Image("building.png") +``` + +The overlay `.ply` also opens in the `fvdb.viz` viewer (`gls show building.ply`). + +### Segment catalog (notebook object database) + +`build_catalog` runs a whole vocabulary in one pass and turns the result into a small, +browsable database of individual objects: each prompt is segmented, split into spatial +objects (3D connected components), and objects hit by several prompts (e.g. `car` and +`vehicle`) are merged and given a stable id. The catalog is a table you browse and pull +single objects from — handy for picking a specific segment to export downstream. + +```python +from geolangsplat import build_catalog + +cat = build_catalog("scene.ply", ["building", "car", "tree", "road"], recipe="satellite") +cat # rich HTML table inline (id, label, n_gaussians, size, prompts) +cat.browse() # interactive picker: preview + select objects -> export .ply +cat.table # the same data as a pandas DataFrame (filter / sort) +cat.show() # top-down render with each object's id drawn on it +cat.extract(3, "obj3.ply") # pull one object out as its own .ply +cat.export_all("scene_catalog/") # objects/_