Single-image to 200-view splat-training dataset, with a per-asset aesthetic dialer.
Drop a photo of an object into a folder. Get back a 200-view orbit-rendered COLMAP + Nerfstudio dataset, ready to train into a 3D Gaussian splat in PostShot, LichtFeld, gsplat, or any other 3DGS trainer.
Built on Microsoft TRELLIS.2 (via TencentARC's Pixal3D productized fork). Adds:
- A 5-tier sampler system with empirically-validated configurations for different asset types (organic/stone/weathered → hard-surface/mechanical → max sculpt detail)
- A probe mode that runs all 5 tiers on a single asset at view 129, lets you visually compare and dial in the right aesthetic before committing to a full 200-view render
- A seed-quantifier for the probe so you can also see seed-to-seed variation per tier
- An AutoCrop preprocessor that tight-crops inputs to a 40px-bordered subject bbox — eliminates wasted negative space so the subject occupies more of Pixal3D's 1024-pixel image conditioning
- An AuraSR-based generative upscaler for preprocessing soft / low-res / compressed source images before they go through the splat pipeline
- A hot-folder daemon that watches a folder for incoming images and processes them with one or many tier configurations
- Drop-in Windows BAT files for daemon + autocrop + upscaler, so the whole workflow is double-click-from-desktop
Most image-to-3D tools (TRELLIS.2 demo, LiTo, AnySplat, Rodin Gen-2.5) give you one output per image — a single SLat-decoder-baked aesthetic. Image2Splat treats Pixal3D's sampler params as creative knobs rather than fixed defaults, surfacing them as named tiers that map to genuine per-asset-type aesthetics.
The 5 tiers were locked in through ~15 hours of sweeps on Gargoyle / Knight / Column / and other reference assets:
| Tier | Steps | Shape guidance | Tex guidance | Best for |
|---|---|---|---|---|
| 1 — Default | 12 | 7.5 | 1.1 | Safe production baseline |
| 2 — Subtle | 13 | 7.6 | 1.2 | Mild bump, conservative |
| 3 — Balanced | 14 | 7.7 | 1.25 | Mathematical midpoint |
| 4 — Refined | 15 | 7.6 | 1.2 | Hard-surface + organic carved-detail |
| 5 — Sculpted | 15 | 8.0 | 1.5 | Max push, hard-surface, mechanical |
Pixal3D's published defaults are 12/7.5/1.0 (sparse_structure / shape_slat / tex_slat). Empirically the tiny tex bump in Tier 1 produces visibly cleaner texture for our use cases.
Per image dropped in inbox/:
datasets/<image_slug>/USER_Alt2_200v_3000px/
images/ ← 200 PNG renders @ 3000×3000, orbital camera trajectory
000.png ... 199.png
transforms.json ← Nerfstudio-format camera intrinsics + extrinsics
cameras.txt ← COLMAP-format extrinsics (binary fmt also written)
images.txt
points3D.txt
This is NOT a finished splat — it's the training dataset. You then feed it to your splat trainer of choice:
- PostShot (paid, Windows, fast, includes COLMAP-bypass)
- LichtFeld (paid, Windows/Mac, similar)
- gsplat / nerfstudio / 3DGS (free, CLI, more setup)
A note on PostShot v1.1+: it requires a track-count alignment that the daemon's output doesn't auto-satisfy. Run scripts/fix_colmap_postshot11.py on your output dataset before importing.
- OS: WSL2 on Windows 10/11, or Linux. (BAT files assume WSL on Windows.)
- GPU: NVIDIA RTX with ≥24 GB VRAM. Validated on RTX 5090 (sm_120 Blackwell). Should work on 3090 / 4090 / A6000 / H100. Compute time scales inversely with GPU speed.
- CUDA: 12.4+ (for sm_120 you need 12.8). Auto-managed by the conda env.
- Disk: ~50 GB for env + models + ~10 GB per processed asset (200 PNG renders × 3000×3000)
- Time per asset: ~5-7 min mesh+render on 5090, ~10-15 min total once you include polish/colmap export.
# In WSL — clone anywhere; the installer adapts to the location.
git clone https://github.com/sdimaging/Image2Splat ~/projects/Image2Splat
cd ~/projects/Image2Splat
./setup.shsetup.sh does the whole thing (re-run safe):
- Clones TRELLIS.2 + Pixal3D and builds the
trellis2+anysplatconda envs. - Asks where you want your hot-folder and saves
IMAGE2SPLAT_HOTFOLDER. - Creates the hot-folder tree and installs the launcher BATs into it, with this repo's path baked in — no manual copying, no hardcoded paths.
The hot-folder ends up laid out like:
<your hot-folder>\
inbox\ ← drop source images here
processing\ ← daemon work-in-flight
completed\ ← successfully processed sources
failed\ ← errors + .error.log (3-strike quarantine lands here)
datasets\ ← COLMAP/Nerfstudio output datasets
UPSCALE\ ← AuraSR preprocessor (Input\ / Output\ / Start Upscale.bat)
Start Splat Daemon.bat
Start Dashboard.bat
Autocrop.bat
On WSL, pick a Windows path for the hot-folder (e.g. a Desktop folder) so the
.batlaunchers are double-clickable from Windows.
See INSTALL.md for prerequisites and the full step-by-step.
The installer sets this for you; you only touch it to move the hot-folder:
# In your ~/.bashrc or ~/.zshrc
export IMAGE2SPLAT_HOTFOLDER='/mnt/c/Users/<you>/Desktop/image2splat'The daemon auto-creates inbox/, processing/, completed/, failed/, and
datasets/ inside this directory on first run, so a fresh path just works. The
launcher BATs also self-locate — whatever folder a BAT sits in becomes the
hot-folder it operates on, keeping the daemon and dashboard in agreement.
Either:
- Double-click
Start Splat Daemon.bat(Windows) — opens a terminal and prompts for the run type. - Or:
bash scripts/run_hotfolder_watchdog.sh --askin WSL directly.
You'll get a single prompt:
Run type:
1) Default steps=12 shape=7.5 tex=1.1
2) Subtle steps=13 shape=7.6 tex=1.2
3) Balanced steps=14 shape=7.7 tex=1.25
4) Refined steps=15 shape=7.6 tex=1.2
5) Sculpted steps=15 shape=8.0 tex=1.5
6) Probe all 5 tiers at view 129 (multi-tier comparison)
B) Batch run pre-staged T#_seed#/ folders in inbox
Select [1-6 / B, default 1]:
Then drop images into inbox/. The daemon picks them up, processes, moves the source to
completed/, and writes the dataset to datasets/.
The run self-heals — this is the watchdog wrapper (run_hotfolder_watchdog.sh):
- Auto-restart on OOM kills and GPU driver resets, resuming via skip-existing (finished datasets are never redone).
- 3-strike quarantine — if one image crashes the daemon 3 times (e.g. a pathological asset
that explodes the mesh and trips the GPU), it's moved to
failed/and the run continues on the rest, instead of stopping the whole batch. - Reboot-proof resume — the chosen run config + strike counts are saved to
.watchdog_state; if the PC reboots or the window closes, just re-launch and it offers to resume the exact run (or pressnto start fresh).
(The plain one-shot launcher scripts/run_hotfolder.sh is still available if you want the
daemon without the watchdog.)
Don't know which tier/seed suits an asset? Drop it in, pick 6 — Probe:
Probe seeds: enter a COUNT for random (e.g. 3), or an explicit
comma-list to PIN exact seeds (e.g. 222,74964,91766).
Seeds [default 3]:
- A count
N→ 222 anchor + N-1 random seeds (logged inprobe_meta.jsonfor reproducibility). - A comma-list → those exact seeds, identical for every asset. Pin a seed set that works well for your content and reuse it across runs.
The daemon renders view 129 only at 5 tiers × (seeds) comparison frames at
datasets/<slug>/probe/, plus probe_meta.json.
Open the folder in Photoshop / Bridge as layers, flip between tiers + seeds, pick the winner.
Then re-drop the same image at that specific tier for the full 200v render — or stage a
T#_seed#/ batch and run option B.
If your inputs have white or black backgrounds with negative space around the subject (typical for product photography, museum catalog images, AI-generated stock), AutoCrop eliminates wasted pixels so the subject occupies more of Pixal3D's 1024-pixel image conditioning.
- Drop images into the daemon's
inbox/folder - Double-click
Autocrop.bat - Originals are auto-backed up to
inbox/.original_backups/and replaced with tight-cropped versions (40px margin around subject) - Then run the daemon as normal
How it detects the subject: pixel-statistic bbox detection — any pixel that's NOT near-white (RGB > 240), NOT near-black (RGB < 15), and NOT transparent (alpha < 10) counts as subject. Expands the bbox by 40px on all sides for clean margins.
Subject pixel density gain: a 2000×2000 input where the subject is the center 800×800 becomes a ~880×880 crop where the subject fills nearly the entire frame. Pixal3D's downsample-to-1024 then sees ~1000 pixels of subject instead of ~400. ~5-6× effective density boost with zero hallucination.
For soft / low-res / compressed source images, the AuraSR upscaler adds plausible micro-detail that SURVIVES Pixal3D's internal 1024-pixel image conditioning downsample:
- Drop source images in
Desktop\UPSCALE\Input\ - Double-click
Start Upscale.bat - Get 4× upscaled PNGs in
Desktop\UPSCALE\Output\ - Use those as the new inputs to the splat daemon
GAN-based generative upscale — adds detail it thinks should be there. Best for inputs that look soft. Skip for already-crisp 2K+ images.
Stack with AutoCrop for max benefit: AutoCrop first (eliminate negative space), then AuraSR (4× detail on the cropped subject), then daemon. Each stage multiplies effective subject density at Pixal3D's conditioning stage.
drop image → pick tier 1-5 → 200v at that tier → train splat
drop image → tier 6 probe → 5 comparison frames per seed
→ pick best (tier, seed) from probe → re-drop at that tier → 200v
→ train splat
drop image → pick tier 1 → 200v at tier 1 → move source back to inbox
→ drop again, pick tier 4 → 200v at tier 4 → ...
→ cherry-pick views across tier outputs in Photoshop before splat training
→ get a custom "best of N tiers" splat that no single sampler config could produce
drop catalog-style images in inbox → Autocrop.bat → tight-cropped versions in place
→ (move to UPSCALE\Input) → Start Upscale.bat → 4× AuraSR'd versions in UPSCALE\Output
→ (move back to inbox) → Start Splat Daemon.bat → pick tier → 200v at chosen tier
→ train splat
Each preprocessing stage multiplies effective subject pixel density at the conditioning stage:
- AutoCrop: ~5-6× density gain by eliminating negative space
- AuraSR: 4× supersample (artifacts get filtered out by Pixal3D's 1024 downsample)
- Pixal3D: subject fills ~95%+ of the 1024×1024 conditioning frame instead of ~20-40%
soft / compressed source → AuraSR upscale → SR'd version into splat daemon
→ probe mode for tier selection → 200v at chosen tier → splat
your image
│
▼
[ optional: AutoCrop → eliminate negative space ]
│
▼
[ optional: AuraSR upscale → 4× generative detail ]
│
▼
hotfolder_daemon.py
│ • image preprocess (BiRefNet bg removal if no alpha)
│ • MoGe camera estimation
│ • Pixal3D run (sparse → shape → texture SLat sampling)
│ • mesh extraction (~6-21 M faces, QEM-decimated to ≤16.78M)
│ • multiview rendering (200v Fibonacci orbit, 3000px, HDRI lighting)
│ • polish pass (sharpen + film grain)
│ • COLMAP + Nerfstudio dataset export
▼
datasets/<slug>/USER_Alt2_200v_3000px/
│
▼
[ your splat trainer: PostShot / LichtFeld / gsplat ]
│
▼
final 3D Gaussian splat
src/ ← Python source for the splat pipeline
backbone.py Pixal3D / TRELLIS.2 backbone wrapper
cameras.py Fibonacci-sphere camera trajectory + intrinsics
render.py Multi-view PBR rendering via nvdiffrast
polish.py Per-view sharpen + grain post-process
hdri_io.py EXR HDRI envmap loader
mesh_export.py PLY + GLB export
export_colmap.py COLMAP dataset writer
export_nerfstudio.py Nerfstudio transforms.json writer
scripts/
hotfolder_daemon.py The main daemon
run_hotfolder_watchdog.sh Resilient launcher: auto-restart, 3-strike
quarantine, reboot-proof resume (recommended)
run_hotfolder.sh Plain one-shot launcher (no watchdog)
rank_seeds.py Score/rank probe cells by plateau-faceting metric
probepull.py Stage probe selects -> inbox T#_seed#/ batch folders
quick_splat.py TripoSplat feed-forward preview splat per asset
setup_env.sh Install Pixal3D + TRELLIS.2 + conda env
autocrop.py Pixel-stat bbox autocropper for tight-cropping
run_autocrop.sh WSL wrapper for autocrop
probe_tier_validation.py Reproducer for the tier-locking sweep
fix_colmap_postshot11.py PostShot v1.1+ COLMAP track-count patcher
upscale/
upres.py AuraSR folder-to-folder upscaler
run_upscale.sh WSL wrapper
bat/ Windows BAT files (copy to Desktop)
Start Splat Daemon.bat
Autocrop.bat
Start Upscale.bat
docs/ Design notes + eval sessions
| Param | Default | Notes |
|---|---|---|
| seed | 222 | Production-locked. Different seeds = different outputs at same tier. |
| HDRI | USER_Alt2.exr | Studio HDRI used for shading. Swap for different lighting. |
| HDRI exposure | 2.5× | Linear multiplier on radiance. |
| Pipeline | 1536_cascade | 1536 = HR shape SLat at 1536³ voxel grid. 2048 is OOD and may fail. |
| Max tokens | 131,072 | 128k token budget for sparse-voxel structure. |
| Max faces | 16,000,000 | Cap before QEM decimation. nvdiffrast hard cap = 2^24 = 16.78M. |
| Resolution | 3000 px | Per-view render resolution. PostShot prefers 2-4K. |
| Num views | 200 | Fibonacci-sphere orbit. 200 is the validated count for object splats. |
| FOV | 40° | Camera horizontal field of view. |
| Polish sharpen | 40% | Subtle unsharp. Disabled via 0. |
| Polish grain | σ=3.0 | Gaussian noise post-render. Disabled via 0. |
- ❌ Train the splat — output is the dataset, you bring your own trainer (PostShot, LichtFeld, gsplat, etc.)
- ❌ Multi-image input — single image to single asset. Use TRELLIS.2 directly for multi-image conditioning.
- ❌ Text-to-3D — image-to-3D only.
- ❌ Editing existing splats — generation only, no remixing.
- GPU-locked — needs CUDA. Apple Silicon / CPU paths are untested.
- Single-asset orientation — assumes the input image's principal axis maps to the asset's vertical. Auto-aligned via MoGe; for unusual poses you may need to pre-rotate the input.
- Tier 6 probe currently single-view (129) — could extend to multi-view probe later for trickier assets.
- Microsoft TRELLIS.2 — foundational image-to-3D model architecture
- TencentARC Pixal3D — productized TRELLIS.2 fork with pixel-aligned back-projection
- valeoai/MoGe — monocular geometry estimation
- BiRefNet — background removal
- nvdiffrast — differentiable rendering
- fal/AuraSR — generative super-resolution
- CuMesh — GPU mesh ops + QEM decimation
MIT — see LICENSE.