---
comments: true
description: Learn about monocular depth estimation using YOLO26. Predict per-pixel depth maps from single RGB images with NYU Depth V2 and custom dataset support.
keywords: monocular depth estimation, YOLO26, depth map, per-pixel depth, NYU Depth V2, DPT, dense prediction, Depth Anything V2, Ultralytics
model_name: yolo26n-depth
---

# Monocular Depth Estimation

<img width="1024" src="https://cdn.jsdelivr.net/gh/ultralytics/assets@main/docs/depth-estimation-examples.avif" alt="Monocular depth estimation examples">

Monocular depth estimation predicts a per-pixel depth map from a single RGB image. Each output pixel holds a depth value in meters representing the estimated distance from the camera to that surface point.

The output of a depth model is a dense float map of shape `(H, W)` aligned to the input image. This per-pixel representation makes monocular depth estimation well-suited for 3D scene reconstruction, robot navigation, AR/VR content creation, and any application that requires spatial layout from a single camera.

!!! tip

    Use `task=depth` or the `yolo depth` CLI task for monocular depth estimation. YOLO26 depth model files use the `-depth` suffix, such as `yolo26n-depth.pt`.

<p align="center">
  <br>
  <iframe loading="lazy" width="720" height="405" src="https://www.youtube.com/embed/i-V1kRCJD0M"
    title="YouTube video player" frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    allowfullscreen>
  </iframe>
  <br>
  <strong>Watch:</strong> Monocular Depth Estimation with Ultralytics YOLO26 | Python Tutorial | Vision AI 🚀
</p>

## [Models](https://github.com/ultralytics/ultralytics/tree/main/ultralytics/cfg/models/26)

YOLO26 depth models pretrained on a broad multi-dataset mix (indoor + outdoor, ~2.19M images) are shown below. The metrics columns are reported on the [NYU Depth V2](https://cs.nyu.edu/~silberman/datasets/nyu_depth_v2.html) Eigen test split.

[Models](https://github.com/ultralytics/ultralytics/tree/main/ultralytics/cfg/models) download automatically from the latest Ultralytics [release](https://github.com/ultralytics/assets/releases) on first use.

{% include "macros/yolo-depth-perf.md" %}

- **delta1<sup>NYU</sup>** is the percentage of pixels where the predicted depth is within a factor of 1.25 of the ground truth, on the NYU Depth V2 Eigen test split (654 images) with multi-scale + horizontal-flip TTA and log-least-squares alignment.
- Single-scale accuracy without TTA is reproducible with `yolo depth val model=yolo26n-depth.pt data=nyu-depth.yaml imgsz=768 device=0` (substitute `model=` for each size), which uses median (scale-only) alignment and scores lower: delta1 0.785 (n), 0.786 (s), 0.827 (m), 0.839 (l), 0.843 (x).
- **abs_rel** is the mean absolute relative error between predicted and ground-truth depth values.
- **rmse** is the root mean squared error in meters.
- **Speed** is inference-only latency (pre/post-processing excluded) at `imgsz=768`, `batch=1`, reported as mean ± std over timed runs after warmup. **CPU ONNX** is ONNX Runtime fp32 on a 32-core Intel Xeon (Skylake); **T4 TensorRT10** is TensorRT fp16 on a Tesla T4.
- **params** and **FLOPs** are measured at 768×768, the training resolution of the released weights.

## Speed compared to Depth Anything V2

Depth Anything V2 is a widely used open baseline for monocular depth. Its DINOv2 [vision transformer](https://www.ultralytics.com/glossary/vision-transformer-vit) backbone and DPT decoder are compute-heavy, so on the same Tesla T4 under TensorRT fp16 the smallest released Depth Anything V2 model is slower than every YOLO26 depth model — including YOLO26x-depth, which carries more than twice the parameters.

At ~768 px — `imgsz=768` for YOLO26, the resolution its released weights are trained at, and 770 px for Depth Anything V2, whose DINOv2 backbone requires a multiple of its patch size of 14:

| Model                   | params (M) | FLOPs (B) | T4 TensorRT10 (ms) |   FPS | Speedup vs V2 Small | Speedup vs V2 Base |
| ----------------------- | ---------: | --------: | -----------------: | ----: | ------------------: | -----------------: |
| Depth Anything V2 Base  |       97.5 |    1025.5 |              55.40 |  18.1 |                   — |                  — |
| Depth Anything V2 Small |       24.8 |     346.9 |              20.99 |  47.6 |                   — |                  — |
| YOLO26x-depth           |       57.0 |     302.0 |              13.57 |  73.7 |                1.5× |               4.1× |
| YOLO26l-depth           |       27.7 |     157.2 |               7.68 | 130.2 |                2.7× |               7.2× |
| YOLO26m-depth           |       23.3 |     130.7 |               6.00 | 166.7 |                3.5× |               9.2× |
| YOLO26s-depth           |       13.2 |      67.9 |               3.82 | 261.6 |                5.5× |              14.5× |
| YOLO26n-depth           |        6.4 |      46.9 |               2.73 | 365.8 |                7.7× |              20.3× |

At ~640 px — `imgsz=640` and 644 px respectively — the ordering is unchanged, and YOLO26n-depth is 5.9× faster than Depth Anything V2 Small:

| Model                   | T4 TensorRT10 (ms) |   FPS |
| ----------------------- | -----------------: | ----: |
| Depth Anything V2 Base  |              35.10 |  28.5 |
| Depth Anything V2 Small |              13.62 |  73.4 |
| YOLO26x-depth           |              10.26 |  97.5 |
| YOLO26l-depth           |               6.14 | 162.8 |
| YOLO26m-depth           |               4.71 | 212.1 |
| YOLO26s-depth           |               3.08 | 324.4 |
| YOLO26n-depth           |               2.29 | 436.9 |

- Latency is inference-only, `batch=1`, TensorRT fp16 on a Tesla T4 — the same harness as the model table above, shown here to two decimals; FPS is the reciprocal of the unrounded latency. The **Speedup** columns divide the Depth Anything V2 Small (20.99 ms) and Base (55.40 ms) latency by the YOLO26 latency.
- Depth Anything V2 Small and Base are the released ViT-S and ViT-B checkpoints.
- The comparison covers latency only — the two model families are not evaluated here under a shared accuracy protocol.

## Depth range and the log-depth head

The depth head predicts `exp(logit)` — **unbounded** (~0.02–150 m) — and **decouples scene shape from absolute scale**: the network predicts a relative log-depth field, and absolute meters are set by a separate two-parameter transform (`exp(a·log d + b)`) recovered at evaluation, by lightweight calibration, or by fine-tuning. The common alternative, a bounded `sigmoid × max_depth` head, instead bakes a fixed ceiling into the architecture, so any depth beyond `max_depth` is clipped — which prevents training on, and predicting, longer-range scenes.

### Why the head is unbounded: evidence across depth ranges

**Controlled A/B — same data, same schedule, only the head differs.** Training both heads from scratch on an identical mix of indoor (≤10 m) and outdoor (≤80 m) data:

| Head                         | Output range   | Mixed-range val δ1 | Training behavior       |
| ---------------------------- | -------------- | -----------------: | ----------------------- |
| `sigmoid × max_depth` (10 m) | bounded 0–10 m |              0.221 | **plateaus at epoch 1** |
| `log` (unbounded)            | 0–~150 m       |   **0.367** (+66%) | improves throughout     |

The bounded head cannot represent the >10 m majority of outdoor pixels, so it stops improving almost immediately; the `log` head learns from the full range.

**The failure mode it fixes — single-dataset fine-tuning, stratified by range.** Fine-tuning a bounded (10 m) head on individual datasets works when the data fits the cap and collapses when it exceeds it:

| Dataset   | Depth range  |                                    Bounded-head δ1 |
| --------- | ------------ | -------------------------------------------------: |
| SUN RGB-D | ≤10 m        |                                            0.78 ✅ |
| Hypersim  | mostly ≤10 m |                                            0.74 ✅ |
| KITTI     | ~80 m        | 0.08 ❌ (abs_rel ≈ 7.0 — the 80/10 scale mismatch) |
| vKITTI2   | 80 m         |                                            0.04 ❌ |

The collapse lands exactly at the cap boundary. The `log` head has no such boundary.

**Released models — cross-range performance.** The shipped `log`-head family, evaluated across benchmarks spanning 10 m (NYU, iBims-1) to 80 m (KITTI), with scale-aligned δ1:

| Benchmark   | Range | YOLO26x-depth (`log`) | prior bounded release |
| ----------- | ----- | --------------------: | --------------------: |
| NYU Eigen   | 10 m  |                 0.933 |                 0.934 |
| iBims-1     | 10 m  |                 0.961 |                 0.945 |
| ETH3D       | ~60 m |                 0.959 |                 0.931 |
| Make3D      | ~70 m |                 0.302 |                 0.296 |
| KITTI Eigen | 80 m  |             **0.942** |                 0.891 |
| **Mean**    | —     |             **0.819** |                 0.799 |

The largest gains are on the longer-range outdoor benchmarks (KITTI, ETH3D) — exactly where a fixed 10 m ceiling hurts most — while indoor performance is retained.

## Train

Train YOLO26n-depth on the [Depth8](../datasets/depth/depth8.md) dataset for 100 [epochs](https://www.ultralytics.com/glossary/epoch) at image size 640. For a full list of available arguments see the [Configuration](../usage/cfg.md) page.

!!! example

    === "Python"

        ```python
        from ultralytics import YOLO

        # Load a model
        model = YOLO("yolo26n-depth.yaml")  # build a new model from YAML
        model = YOLO("yolo26n-depth.pt")  # load a pretrained model (recommended for training)
        model = YOLO("yolo26n-depth.yaml").load("yolo26n-depth.pt")  # build from YAML and transfer weights

        # Train the model
        results = model.train(data="depth8.yaml", epochs=100, imgsz=640)
        ```

    === "CLI"

        ```bash
        # Build a new model from YAML and start training from scratch
        yolo depth train data=depth8.yaml model=yolo26n-depth.yaml epochs=100 imgsz=640

        # Start training from a pretrained *.pt model
        yolo depth train data=depth8.yaml model=yolo26n-depth.pt epochs=100 imgsz=640

        # Build a new model from YAML, transfer pretrained weights to it and start training
        yolo depth train data=depth8.yaml model=yolo26n-depth.yaml pretrained=yolo26n-depth.pt epochs=100 imgsz=640
        ```

See full `train` mode details in the [Train](../modes/train.md) page.

### Fine-tuning on your own data

When adapting a pretrained depth model to a custom dataset, **lower the learning rate and use the AdamW optimizer**. The default optimizer settings are tuned for training from scratch (SGD with `lr0=0.01`); applied to an already-converged depth model they can overwrite the pretrained knowledge and degrade results — especially when fine-tuning on a single domain.

!!! example "Recommended fine-tuning recipe"

    === "Python"

        ```python
        from ultralytics import YOLO

        model = YOLO("yolo26s-depth.pt")  # start from pretrained weights

        model.train(
            data="path/to/your_dataset.yaml",
            epochs=20,
            imgsz=640,
            optimizer="AdamW",
            lr0=1e-4,  # ~100x below the from-scratch default
            warmup_bias_lr=1e-4,  # keep warmup gentle too
        )
        ```

    === "CLI"

        ```bash
        yolo depth train data=path/to/your_dataset.yaml model=yolo26s-depth.pt \
          epochs=20 imgsz=640 optimizer=AdamW lr0=1e-4 warmup_bias_lr=1e-4
        ```

Additional tips:

- **Augmentation is controlled by the standard args** (`degrees`, `translate`, `scale`, `shear`, `perspective`, `flipud`, `fliplr`, `hsv_h`, `hsv_s`, `hsv_v`); the geometric warp and flips are applied identically to the paired depth map. To see the exact recipe used for the released YOLO26-Depth weights, inspect the `train_args` stored in the checkpoint — see [Inspecting YOLO26 Checkpoint Training Args](../guides/yolo26-training-recipe.md#inspecting-yolo26-checkpoint-training-args).
- **`mosaic`, `mixup`, `cutmix`, and `copy_paste` are not implemented for depth.** The depth dataset loader automatically sets these probabilities to 0, so passing them has no effect. These augmentations are not supported because they combine multiple images, which would produce invalid paired depth maps.
- **Any depth range works out of the box.** The `log`-head models predict unbounded depth, so they adapt to short-range (macro) or long-range (outdoor/driving) data without changes. Setting `max_depth:` in your dataset YAML (in meters) bounds which GT pixels count toward validation metrics.
- **Retain general performance.** If you need the model to stay accurate on scenes beyond your training set, mix a small fraction (~5–10%) of diverse general-purpose images into your training data; this substantially reduces forgetting during fine-tuning.
- **Train from scratch** (`model=yolo26s-depth.yaml`) only if your domain is very different and you have a large dataset — there the default SGD `lr0=0.01` is appropriate, since there are no pretrained weights to preserve.

### Calibrating the depth scale

The depth head separates **shape** (relative scene structure) from **scale** (absolute meters). If a model already produces good relative depth on your scenes but the absolute values are off for your camera, you can correct the scale in seconds with `model.calibrate()` — a closed-form fit of a two-parameter log-affine against a small labeled set, with **no gradient training and no change to the network weights**, so it cannot degrade the relative structure.

!!! example "Scale calibration"

    === "Python"

        ```python
        from ultralytics import YOLO

        model = YOLO("yolo26s-depth.pt")

        # Fit scale on a labeled split (~100+ images is enough), then persist it
        model.calibrate(data="path/to/your_dataset.yaml")
        model.save("yolo26s-depth-calibrated.pt")
        ```

Calibration needs ground-truth depth to fit against, so it runs on a labeled split — it is not something that can happen at blind inference. Use it when relative depth is already good and only the scale/range is wrong; if the relative structure itself needs to change for your domain, [fine-tune](#fine-tuning-on-your-own-data) instead.

Training does this for you automatically: after `model.train(...)` completes, the best and last checkpoints are calibrated on the validation set so they output metric-scaled depth out of the box.

The released `yolo26*-depth.pt` checkpoints ship with this calibration already baked in, fit on the pretraining validation mix. It is a single global scale across all domains, so for the most accurate absolute depth on a specific camera or scene type, run `model.calibrate()` on a small labeled split from your own data — it replaces the baked-in fit.

### Dataset format

Depth estimation datasets pair each RGB image with a corresponding depth file. Depth targets are stored as `.npy` arrays containing float32 values in meters. The dataset YAML points to an `images/` directory; the loader derives the depth file path by replacing the `images` component with `depth` and replacing the image extension with `.npy`.

```text
dataset/
├── images/
│   ├── train/
│   └── val/
└── depth/
    ├── train/
    └── val/
```

For example, an image at `images/train/scene_001.jpg` is paired with a depth map at `depth/train/scene_001.npy`. See the [Depth Estimation Dataset Guide](../datasets/depth/index.md) for the full format specification.

## Val

Validate a trained YOLO26n-depth model [accuracy](https://www.ultralytics.com/glossary/accuracy) on a depth estimation dataset. Pass `data` explicitly so validation uses the intended dataset YAML. The released weights are trained at `imgsz=768`, so validate and predict at that size for best accuracy.

!!! example

    === "Python"

        ```python
        from ultralytics import YOLO

        # Load a model
        model = YOLO("yolo26n-depth.pt")  # load an official model
        model = YOLO("path/to/best.pt")  # load a custom model

        # Validate the model
        metrics = model.val(data="nyu-depth.yaml")
        metrics.delta1  # percentage of pixels within threshold δ=1.25
        metrics.abs_rel  # mean absolute relative error
        metrics.rmse  # root mean squared error (meters)
        metrics.silog  # scale-invariant logarithmic error
        ```

    === "CLI"

        ```bash
        yolo depth val model=yolo26n-depth.pt data=nyu-depth.yaml   # validate official model
        yolo depth val model=path/to/best.pt data=path/to/data.yaml # validate custom model
        ```

## Predict

Use a trained YOLO26n-depth model to run predictions on images.

!!! example

    === "Python"

        ```python
        from ultralytics import YOLO

        # Load a model
        model = YOLO("yolo26n-depth.pt")  # load an official model
        model = YOLO("path/to/best.pt")  # load a custom model

        # Predict with the model
        results = model("https://ultralytics.com/images/bus.jpg")  # predict on an image

        # Access the results
        for result in results:
            depth_map = result.depth.data.cpu().numpy()  # torch.Tensor -> NumPy float32, shape (H, W), meters
        ```

    === "CLI"

        ```bash
        yolo depth predict model=yolo26n-depth.pt source='https://ultralytics.com/images/bus.jpg' # predict with official model
        yolo depth predict model=path/to/best.pt source='https://ultralytics.com/images/bus.jpg'  # predict with custom model
        ```

See full `predict` mode details in the [Predict](../modes/predict.md) page.

### Results Output

YOLO depth estimation returns one `Results` object per image. Each result stores one dense float depth map for the full image.

| Attribute           | Type           | Shape   | Description                                              |
| ------------------- | -------------- | ------- | -------------------------------------------------------- |
| `result.depth`      | `DepthMap`     | `(H,W)` | Dense per-pixel depth map.                               |
| `result.depth.data` | `torch.Tensor` | `(H,W)` | Depth values in meters; call `.cpu().numpy()` for NumPy. |
| `result.boxes`      | -              | -       | No instance boxes.                                       |
| `result.masks`      | -              | -       | No instance masks.                                       |

For task-specific `Results` fields across every task, see the [Predict Results by Task](../modes/predict.md#results-by-task) section.

### Colorizing the depth map

The raw depth map is a single-channel float array in meters — useful for computation, but hard to read directly. To turn it into a color image, use the `colorize_depth` helper in `ultralytics.utils.plotting`, which maps the `(H, W)` depth array to a `(H, W, 3)` BGR `uint8` image (invalid pixels `<= 0` are rendered black).

`result.plot()` already blends this colorization over the input image using the defaults (`cmap="jet"`, `mode="disparity"`); call `colorize_depth` directly when you want a standalone colored depth image or a different colormap or normalization.

!!! example "Colorize a predicted depth map"

    === "Python"

        ```python
        import cv2

        from ultralytics import YOLO
        from ultralytics.utils.plotting import colorize_depth

        model = YOLO("yolo26n-depth.pt")
        result = model("https://ultralytics.com/images/bus.jpg")[0]

        depth = result.depth.data.cpu().numpy()  # (H, W) float32, meters

        # Colorize with near = warm and save
        cv2.imwrite("depth_colored.png", colorize_depth(depth, cmap="spectral"))  # (H, W, 3) BGR uint8

        # Fix the range to 0-20 m so the same color means the same distance across frames
        cv2.imwrite("depth_metric.png", colorize_depth(depth, vmin=0.0, vmax=20.0, cmap="inferno", mode="metric"))

        # Blended overlay straight from the Results object (uses cmap="jet", mode="disparity")
        result.save("depth_overlay.png")
        ```

Every colormap runs cool/dark → warm/bright. The `mode` decides which end is near, and `vmin`/`vmax` lock the range across frames so a color always means the same distance.

| Argument | Value                 | Description                                                                                                           |
| -------- | --------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `cmap`   | `jet` (default)       | High-contrast blue → green → red, the palette `result.plot()` uses.                                                   |
| `cmap`   | `inferno`             | Black → purple → orange → yellow. Perceptually uniform, colorblind-friendly, readable in grayscale.                   |
| `cmap`   | `spectral`            | Red → yellow → green → blue (matplotlib `Spectral_r`).                                                                |
| `mode`   | `disparity` (default) | Normalizes inverse depth (`1/d`) between the 2nd and 98th percentiles; warm marks near and far outliers are absorbed. |
| `mode`   | `metric`              | Normalizes depth in meters linearly between `vmin` and `vmax`; warm marks far, so colors track true distance.         |

## Export

Export a YOLO26n-depth model to a different format like ONNX, CoreML, etc.

!!! example

    === "Python"

        ```python
        from ultralytics import YOLO

        # Load a model
        model = YOLO("yolo26n-depth.pt")  # load an official model
        model = YOLO("path/to/best.pt")  # load a custom model

        # Export the model
        model.export(format="onnx")
        ```

    === "CLI"

        ```bash
        yolo export model=yolo26n-depth.pt format=onnx # export official model
        yolo export model=path/to/best.pt format=onnx  # export custom model
        ```

Available YOLO26 depth estimation export formats are in the table below. You can export to any format using the `format` argument, i.e., `format='onnx'` or `format='engine'`. You can predict or validate directly on exported models, i.e., `yolo predict model=yolo26n-depth.onnx`. Usage examples are shown for your model after export completes.

{% include "macros/export-table.md" %}

See full `export` details in the [Export](../modes/export.md) page.

## FAQ

### How do I train a YOLO26 depth estimation model on a custom dataset?

Prepare paired RGB images and `.npy` depth files, then create a dataset YAML pointing to your `images/` directory. The loader finds depth files automatically by replacing `images` with `depth` in the path and swapping the image extension for `.npy`.

Start from pretrained weights and use a low learning rate with AdamW so the fine-tune retains what the model already knows (see [Fine-tuning on your own data](#fine-tuning-on-your-own-data) for why):

!!! example

    === "Python"

        ```python
        from ultralytics import YOLO

        # Load a pretrained YOLO26 depth model
        model = YOLO("yolo26s-depth.pt")

        # Fine-tune on a custom depth dataset
        results = model.train(
            data="path/to/your_dataset.yaml",
            epochs=20,
            imgsz=640,
            optimizer="AdamW",
            lr0=1e-4,
            warmup_bias_lr=1e-4,
        )
        ```

    === "CLI"

        ```bash
        yolo depth train data=path/to/your_dataset.yaml model=yolo26s-depth.pt \
          epochs=20 imgsz=640 optimizer=AdamW lr0=1e-4 warmup_bias_lr=1e-4
        ```

Check the [Configuration](../usage/cfg.md) page for more available arguments.

### What metrics does YOLO26 depth estimation report?

Depth estimation validation reports the metric set used by Depth Anything and related monocular-depth work:

- **delta1 / delta2 / delta3** — percentage of pixels where the ratio of predicted to ground-truth depth (or its inverse) is below 1.25, 1.25², and 1.25³ respectively. Higher is better.
- **abs_rel** — mean absolute relative error. Lower is better.
- **rmse** — root mean squared error in meters. Lower is better.
- **silog** — scale-invariant logarithmic error. Lower is better.

Each prediction is median-aligned to its ground truth per image, and the statistics are then pooled over every valid pixel of the validation set (images with more valid depth pixels weigh proportionally more). Papers that instead average per-image metrics can report slightly different values on the same predictions.

### What is the depth map output format?

The depth map is stored as a `torch.Tensor` of shape `(H, W)` where each value is the predicted depth in meters (use `result.depth.data.cpu().numpy()` for a NumPy `float32` array). Access it through `result.depth.data` after running prediction. The map is aligned to the input image resolution.

### What datasets are supported for depth estimation?

Ultralytics YOLO26 provides built-in dataset YAML configurations for several depth estimation datasets including NYU Depth V2, KITTI, Hypersim, SUN RGB-D, and ARKitScenes. See the [Depth Estimation Dataset Guide](../datasets/depth/index.md) for the full list and format details.

### How do I validate a pretrained YOLO26 depth estimation model?

Validate a pretrained YOLO26 depth model by supplying the dataset YAML used for evaluation:

!!! example

    === "Python"

        ```python
        from ultralytics import YOLO

        # Load a pretrained model
        model = YOLO("yolo26n-depth.pt")

        # Validate the model
        metrics = model.val(data="nyu-depth.yaml")
        print("delta1:", metrics.delta1)
        print("abs_rel:", metrics.abs_rel)
        print("rmse:", metrics.rmse)
        ```

    === "CLI"

        ```bash
        yolo depth val model=yolo26n-depth.pt data=nyu-depth.yaml
        ```

### How can I export a YOLO26 depth estimation model to ONNX format?

Export a YOLO26 depth model to ONNX with Python or CLI:

!!! example

    === "Python"

        ```python
        from ultralytics import YOLO

        # Load a pretrained model
        model = YOLO("yolo26n-depth.pt")

        # Export the model to ONNX format
        model.export(format="onnx")
        ```

    === "CLI"

        ```bash
        yolo export model=yolo26n-depth.pt format=onnx
        ```

For more details on exporting to various formats, refer to the [Export](../modes/export.md) page.
