Depth estimation

Depth estimation predicts how far each pixel is from the camera using a single image. LibreYOLO exposes it as the depth task, which returns a dense relative inverse-depth map on the original image canvas.

Definition

The depth task predicts one value per pixel from a single RGB image. LibreYOLO defines that value as relative inverse depth: higher means closer to the camera, and the numbers carry no metric unit and no scale that holds across two images. Comparing depth between two pixels of the same prediction is meaningful; comparing a value to a value from another image is not.

A prediction fills result.depth_map, a DepthMap payload holding an (H, W) array on the original image canvas. .min, .max and .mean read the finite values, and .normalized() rescales the map to [0, 1] for display. result.boxes stays empty, so conf, iou and max_det have no effect, and save=True writes a colormapped image of the map rather than an annotated photo.

Models

Six families serve depth.

Depth Anything V2 pairs a DINOv2 encoder with a DPT decoder and is the general-purpose default here. Licensing decides the size as much as accuracy does: the Small checkpoint is Apache-2.0 while Base and Large are non-commercial, so check the checkpoint table on its page before picking one.

Depth Anything 3 ports the DA3MONO-LARGE checkpoint, a plain transformer with no architectural specialization for depth.

ZipDepth is the compact tier: a reparameterizable CNN distilled from Depth Anything V2 Large, with a second checkpoint whose decoder avoids gather and unfold operations for NPU compilers that lack them.

MiDaS is the line of work that established the zero-shot relative-depth protocol the other families are measured with. It is the one depth family LibreYOLO does not republish: requesting a checkpoint downloads the official asset from its authors' GitHub release and checks a pinned SHA-256.

LibreMODUS reaches depth as one target of an any-to-any model rather than as a dedicated head. It needs the modus extra and your own authenticated Hugging Face account, and it offers neither val() nor export().

SenseNova-Vision generates the depth map as an image through a diffusion decode, from the same 7B checkpoint that serves its six other tasks. It needs the sensenova extra, and its weights are restricted to non-commercial use; the license is on its page.

Predict

Weights download from Hugging Face on first use and are cached locally, except for the two families noted above.

Predict a depth map
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreDepthAnythingV2s-depth.pt")result = model(SAMPLE_IMAGE, save=True) depth = result.depth_mapprint(depth.data.shape)              # (H, W) on the original canvasprint(depth.min, depth.max, depth.mean)
Work with the values
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreDepthAnythingV2s-depth.pt")result = model(SAMPLE_IMAGE) depth = result.depth_mapraw = depth.data          # higher is closer; no metric unit, no scalegray = depth.normalized() # rescaled to [0, 1] for visualizationprint(raw.shape, float(gray.max()))
A compact alternative
from libreyolo import LibreYOLO, SAMPLE_IMAGE # Same task contract, a much smaller network built for edge runtimes.model = LibreYOLO("LibreZipDepthb-depth.pt")result = model(SAMPLE_IMAGE) print(result.depth_map.data.shape)

Input resolution is constrained per family. Depth Anything V2 and Depth Anything 3 build on a DINOv2 patch grid, so imgsz must divide evenly by 14, which LibreYOLO checks before running. Results.plot() does not cover this task; it is defined for surface normals and edges only. See prediction for sources, streaming and result handling.

Dataset format

Depth validation pairs each image with a dense single-channel depth map that has the same resolution, found by substituting the depth directory into the image path.

dataset/
  data.yaml
  images/
    val/room.jpg
  depths/
    val/room.png
yaml
path: dataset
val: images/val
depths_dir: depths
nc: 1
names: {0: depth}

Maps are single-channel PNG or TIF, or .npy. Values are plain depth in a unit the dataset keeps consistent, and 0, negative, NaN and infinite pixels mark invalid samples that are excluded from the metrics. Integer maps are divided by depth_scale, which defaults to 256.0, the 16-bit PNG convention; float .npy maps are used as they are. depth_stem_suffix and depth_mask_suffix cover datasets that name their depth files or validity masks differently. See dataset formats for the full contract.

Train

No depth family in LibreYOLO has a training implementation: train() raises NotImplementedError on all six. Each model page names the conversion script that turns a checkpoint trained upstream into one LibreYOLO can load.

Validate

val() runs the shared depth validator. Relative depth has no absolute scale, so each prediction is first fitted to the inverse of its ground truth with a per-image least-squares scale and shift, then inverted back to depth. Every metric below is computed per image on that aligned map and averaged over the dataset, counting only pixels the dataset marks valid.

Validate and read the metric keys
from libreyolo import LibreYOLO model = LibreYOLO("LibreDepthAnythingV2s-depth.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/abs_rel"])print(metrics["metrics/rmse"])print(metrics["metrics/delta1"])   # fitnessprint(metrics["metrics/delta2"], metrics["metrics/delta3"])

metrics/abs_rel is the mean absolute relative error, the residual divided by the ground-truth depth, and lower is better. metrics/rmse is the root mean squared error in the dataset's own depth unit, also lower is better. metrics/delta1, metrics/delta2 and metrics/delta3 are the threshold accuracies: the fraction of valid pixels whose ratio to ground truth, taken in whichever direction is larger, falls under 1.25, 1.25 squared and 1.25 cubed, so higher is better. metrics/delta1 is also fitness, the number best-checkpoint selection reads.

Export

An exported depth model loads back through LibreYOLO() on its file suffix, so a .onnx or .engine file behaves like a checkpoint and returns the same Results, with depth_map in place of boxes.

Export
from libreyolo import LibreYOLO model = LibreYOLO("LibreDepthAnythingV2s-depth.pt")model.export(format="onnx")
Run the exported file
from libreyolo import LibreYOLO, SAMPLE_IMAGE # The factory routes on the file suffix, so an exported artifact loads# like any checkpoint and returns the same Results object.model = LibreYOLO("LibreDepthAnythingV2s-depth.onnx")result = model(SAMPLE_IMAGE) print(result.depth_map.data.shape)

Coverage differs per family, and Depth Anything 3 rejects any format outside its validated set rather than attempting an unvalidated conversion. Check the model page and the full export matrix before committing to a target. LibreMODUS and SenseNova-Vision do not export at all. Export lists the arguments every format accepts.

Verified against LibreYOLO v1.5.0.