| --- |
| tags: |
| - ml-intern |
| --- |
| # UniDepth Inference: Image → Metric Depth → Point Cloud |
|
|
| A clean, self-contained Python wrapper around **UniDepth** (CVPR 2024 / V2 2025) for converting a single RGB image into a metric 3D point cloud — with **no camera intrinsics required**. |
|
|
| > **Paper**: [UniDepth: Universal Monocular Metric Depth Estimation](https://arxiv.org/abs/2403.18913) (CVPR 2024) |
| > **V2 Paper**: [UniDepthV2: Universal Monocular Metric Depth Estimation Made Simpler](https://arxiv.org/abs/2502.20110) |
| > **Original Code**: [github.com/lpiccinelli-eth/UniDepth](https://github.com/lpiccinelli-eth/UniDepth) |
| > **Pretrained Weights**: [`lpiccinelli/unidepth-v2-vits14`](https://huggingface.co/lpiccinelli/unidepth-v2-vits14) · [`lpiccinelli/unidepth-v2-vitl14`](https://huggingface.co/lpiccinelli/unidepth-v2-vitl14) |
|
|
| --- |
|
|
| ## Installation |
|
|
| You need the original `unidepth` package (which provides the model definitions) plus this wrapper: |
|
|
| ```bash |
| # 1. Install the official UniDepth package from GitHub |
| pip install git+https://github.com/lpiccinelli-eth/UniDepth.git |
| |
| # 2. Install this wrapper (or just copy the files into your project) |
| pip install . |
| ``` |
|
|
| **Core dependencies**: `torch`, `torchvision`, `PIL`, `numpy`, `huggingface_hub`, `safetensors` |
|
|
| --- |
|
|
| ## Quick Start |
|
|
| ```python |
| from PIL import Image |
| from unidepth.inference import UniDepth |
| |
| # Load image |
| image = Image.open("room.jpg").convert("RGB") |
| |
| # Load model (auto-downloads weights from HuggingFace) |
| model = UniDepth.from_pretrained("lpiccinelli/unidepth-v2-vits14", device="cuda") |
| |
| # Run inference → get depth + point cloud |
| results = model(image) |
| |
| # Metric depth map [H, W] in meters |
| depth = results["depth"] |
| |
| # 3D point cloud [N, 3] in meters (only valid depth pixels) |
| points = results["points"] |
| |
| # Predicted camera intrinsics K [3, 3] |
| intrinsics = results["intrinsics"] |
| |
| # Save as PLY |
| from unidepth.inference import save_pointcloud_ply |
| save_pointcloud_ply("room.ply", points, colors=results["colors"]) |
| ``` |
|
|
| Command-line: |
|
|
| ```bash |
| python examples/image_to_pointcloud.py room.jpg --output room.ply --checkpoint lpiccinelli/unidepth-v2-vits14 |
| ``` |
|
|
| --- |
|
|
| ## How It Works Internally |
|
|
| UniDepth is a **universal monocular metric depth estimator**. Unlike most depth models that only output relative depth or require known camera intrinsics, UniDepth simultaneously predicts: |
|
|
| 1. **Camera intrinsics** (self-promptable camera module) |
| 2. **Metric depth** (in meters) |
| 3. **3D ray directions** for every pixel |
|
|
| ### 1. Pseudo-Spherical Output Representation |
|
|
| The key innovation is the **pseudo-spherical representation** `(θ, φ, z_log)` instead of the standard Cartesian `(x, y, z)`: |
|
|
| - **θ (azimuth)** — horizontal angle of the camera ray |
| - **φ (elevation)** — vertical angle of the camera ray |
| - **z_log** — log-depth (metric) |
| |
| Why? Because `(x, y)` in Cartesian backprojection entangles camera rays with depth: |
| ``` |
| x = (u - cx) / fx * z ← both camera AND depth |
| y = (v - cy) / fy * z ← both camera AND depth |
| ``` |
| |
| By predicting angles `(θ, φ)` separately from `z_log`, the model naturally **disentangles camera calibration from depth estimation**. The two tasks don't interfere during training. |
| |
| ### 2. Self-Promptable Camera Module |
| |
| The camera module bootstraps intrinsics from the image itself: |
| |
| - Takes the ViT class tokens as initialization |
| - Runs 2 self-attention layers → predicts 4 scalars `(Δfx, Δfy, Δcx, Δcy)` |
| - Converts to absolute intrinsics (invariant to image size): |
| ``` |
| fx = Δfx * W / 2 |
| fy = Δfy * H / 2 |
| cx = Δcx * W / 2 |
| cy = Δcy * H / 2 |
| ``` |
| - Backprojects every pixel through `K⁻¹` to get rays on the unit sphere |
| - Extracts azimuth/ elevation from those rays → dense camera representation `C` |
| |
| This means **you don't need to know your camera's focal length** — the model guesses it from visual cues (perspective lines, known object sizes, etc.). |
|
|
| ### 3. Depth Module |
|
|
| - Encoder features from DINOv2 ViT at 4 scales (H/14 × W/14 resolution) |
| - Each scale is **cross-attention conditioned** on the camera embeddings `E = SHE(C)` |
| - `SHE` = Spherical Harmonic Encoding (128 channels from 64 harmonics per angle) |
| - FPN-style decoder with transposed-convolution upsampling |
| - Final output: `Z_log` upsampled to full `(H, W)` + 2 conv layers |
|
|
| ### 4. Converting to Cartesian Point Cloud |
|
|
| The model outputs `O = [θ, φ, Z]` where `Z = exp(Z_log)`. To get standard `(X, Y, Z)`: |
|
|
| ```python |
| X = Z * cos(φ) * cos(θ) |
| Y = Z * cos(φ) * sin(θ) |
| Z = Z * sin(φ) |
| ``` |
|
|
| This is what `generate_pointcloud()` does for you automatically. |
|
|
| ### 5. Handling Known Intrinsics (Optional) |
|
|
| If you already know your camera matrix `K`, you can bypass the predicted camera and use your own: |
|
|
| ```python |
| results = model(image, intrinsics=your_K_matrix) |
| ``` |
|
|
| This gives more accurate 3D reconstruction when intrinsics are reliable. |
|
|
| --- |
|
|
| ## API Reference |
|
|
| ### `UniDepth.from_pretrained(checkpoint, device="cuda")` |
| |
| Load a pretrained model from HuggingFace Hub. |
| |
| | Checkpoint | Size | Speed | Accuracy | |
| |-----------|------|-------|----------| |
| | `lpiccinelli/unidepth-v2-vits14` | 261 MB | Fast | Very Good | |
| | `lpiccinelli/unidepth-v2-vitl14` | 2.6 GB | Slower | Best | |
| |
| ### `model(image, intrinsics=None) → dict` |
| |
| Run inference on a PIL Image or tensor. |
| |
| Returns a dictionary with keys: |
| - `"depth"` — `[H, W]` metric depth (meters) |
| - `"confidence"` — `[H, W]` uncertainty (lower = more confident) |
| - `"points"` — `[N, 3]` Cartesian point cloud (valid pixels only) |
| - `"colors"` — `[N, 3]` RGB colors for each point |
| - `"intrinsics"` — `[3, 3]` predicted camera matrix K |
| - `"camera"` — `[H, W, 2]` predicted azimuth/elevation |
| |
| ### `generate_pointcloud(depth, camera, colors=None, mask=None, intrinsics=None)` |
|
|
| Convert raw model outputs to a filtered point cloud. |
|
|
| ### `save_pointcloud_ply(path, points, colors=None)` |
|
|
| Save points (and optional colors) as an ASCII PLY file. |
|
|
| --- |
|
|
| ## Model Variants |
|
|
| | | UniDepth V1 (CVPR 2024) | UniDepth V2 (2025) | |
| |---|---|---| |
| | Backbone | DINOv2 ViT-L | DINOv2 ViT-S / B / L | |
| | Camera encoding | Spherical Harmonics (81 coefficients) | Sine encoding (64 harmonics) | |
| | Output | (θ, φ, z_log) | (θ, φ, z_log) | |
| | Training data | 8 datasets | 23 datasets (16M images) | |
| | Losses | λ-MSE + Geometric Invariance | + Edge-Guided SSI + Confidence | |
|
|
| This wrapper works with **both V1 and V2** checkpoints. |
|
|
| --- |
|
|
| ## Notes |
|
|
| - **Dynamic resolution**: The model is trained on variable resolutions (0.2–0.6 MP). You can feed any image size; larger images give finer detail but cost more VRAM. |
| - **Normalization**: ImageNet normalization `(0.485, 0.456, 0.406)` mean, `(0.229, 0.224, 0.225)` std is applied automatically. |
| - **Zero-shot**: The model generalizes across indoor, outdoor, and challenging domains without fine-tuning. |
|
|
| --- |
|
|
| ## Citation |
|
|
| ```bibtex |
| @inproceedings{piccinelli2024unidepth, |
| title={UniDepth: Universal Monocular Metric Depth Estimation}, |
| author={Piccinelli, Luigi and Yang, Yuedong and Sakaridis, Christos and Segu, Mattia and Li, Siyuan and Van Gool, Luc and Yu, Fisher}, |
| booktitle={CVPR}, |
| year={2024} |
| } |
| |
| @article{piccinelli2025unidepthv2, |
| title={UniDepthV2: Universal Monocular Metric Depth Estimation Made Simpler}, |
| author={Piccinelli, Luigi and Sakaridis, Christos and Yang, Yuedong and Segu, Mattia and Li, Siyuan and Abbeloos, Marc and Van Gool, Luc}, |
| journal={arXiv:2502.20110}, |
| year={2025} |
| } |
| ``` |
|
|
| ## License |
|
|
| MIT (same as the original repository). |
|
|
| <!-- ml-intern-provenance --> |
| ## Generated by ML Intern |
|
|
| This model repository was generated by [ML Intern](https://github.com/huggingface/ml-intern), an agent for machine learning research and development on the Hugging Face Hub. |
|
|
| - Try ML Intern: https://smolagents-ml-intern.hf.space |
| - Source code: https://github.com/huggingface/ml-intern |
|
|
| ## Usage |
|
|
| ```python |
| from transformers import AutoModelForCausalLM, AutoTokenizer |
| |
| model_id = "bdck/unidepth-inference" |
| tokenizer = AutoTokenizer.from_pretrained(model_id) |
| model = AutoModelForCausalLM.from_pretrained(model_id) |
| ``` |
|
|
| For non-causal architectures, replace `AutoModelForCausalLM` with the appropriate `AutoModel` class. |
|
|