Skip to content

feat(depth): load depth maps from Inference, Ultralytics, Transformers and dataset files - #2694

Merged
Borda merged 26 commits into
developfrom
feat/depth-4-loaders
Oct 9, 2026
Merged

Borda merged 26 commits into
developfrom
feat/depth-4-loaders

Conversation

@cfviotti

@cfviotti cfviotti commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor
Depth from Depth Anything V3, YOLO26 depth and a dataset PNG, each loaded with one line and coloured by sv.DepthAnnotator

One frame, three sources, one line each to load. Left: Depth Anything V3 through Roboflow's hosted API. Middle: YOLO26 depth, in metres; it sees the opening in the rock as far and everything else as close. Right: the dataset's true depth, read from its 16-bit PNG.

▶️📓 Notebook Playground Demo (all 4 PRs together)

Description

Every depth model returns its map in its own shape and unit: a base64 16-bit PNG normalised to 0..1, a torch tensor in metres, a predicted_depth of unknown kind. These loaders turn each into a sv.DepthMap with the right kind, the same way sv.Detections.from_ultralytics does for boxes:

depth_map = sv.DepthMap.from_inference(result)            # depth models served by Roboflow Inference
depth_map = sv.DepthMap.from_ultralytics(results[0])      # YOLO26 depth, metres
depth_map = sv.DepthMap.from_transformers(output, kind="relative_inverse")
depth_map = sv.DepthMap.from_png16("disp_occ_0/000000_10.png", scale=256, kind="disparity_px")  # KITTI
depth_map = sv.DepthMap.from_pfm("disp0GT.pfm", kind="disparity_px")                            # Middlebury

Part 4 of 4. Needs PR 1 (#2691).

Motivation and Context

Follows #2691, where a map is built from an array by hand.

Changes Made

  • from_inference: every depth_map_format (JSON lists, 8- or 16-bit PNG, and the array the SDK and Workflows decode), plus an in-process model's response, as relative_inverse.
  • from_ultralytics: result.depth.data, metres at the original image size.
  • from_transformers: predicted_depth from the depth-estimation pipeline or a model output. Transformers does not say what a model predicts, so kind is required.
  • from_png16(path, scale, kind): 16-bit PNGs divided by the dataset's scale, with 0 as no depth (KITTI disparity uses 256, Ultralytics depth datasets 1000 by default).
  • from_pfm(path, kind): Middlebury and SceneFlow PFM files, with unknown values as no depth.
  • Docs: the how-to's loading section, docstring examples and a changelog entry.

Testing

pytest tests/depth --doctest-modules src/supervision/depth   63 passed (24 new)
pytest                                                       4856 passed, 79 skipped
pre-commit run                                               all hooks pass
mkdocs build                                                 no new warnings
  • Added/updated tests, and the full suite passes locally
  • Updated docs (docstrings / mkdocs entry) for new or changed public API
  • Added a changelog entry in docs/changelog.md under Unreleased
  • from_inference on hosted depth-anything-v3/small, in both png16 and JSON formats: full image size, every pixel valid, near objects warm (image above)
  • from_ultralytics on yolo26n-depth.pt: metres at the image's exact size (image above)
  • Tests are offline: model outputs are built in the tests, no downloads

Additional Notes

  • inference, ultralytics, transformers and torch are not imported by supervision. The loaders read the objects these libraries return.

cfviotti and others added 4 commits October 7, 2026 13:09
Colour any depth array over an image. Wrap a stereo disparity, metric
depth or relative depth array in sv.DepthMap with the kind of value it
holds, then draw it with sv.DepthAnnotator: near objects come out warm,
far ones cool, and pixels without depth stay unpainted so the image
shows through. It works on NumPy and Pillow images without OpenCV.

- sv.DepthKind names what the values measure. NaN, infinities and
  values at or below 0 (below 0 for relative maps) are no depth, and
  valid_mask marks the rest.
- sv.DepthAnnotator takes a colour table (sv.DepthColormap: Turbo,
  Viridis, Cividis, Inferno, Magma or grayscale), a display_range of
  "auto" (the map's own 2nd to 98th percentile) or a fixed (low, high)
  tuple, and an opacity. A metric map is coloured as inverse depth, so
  near detail gets most of the colours.
- Reference pages, a how-to guide and a changelog entry.

Closes #1313

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s and dataset files

Load a depth map straight from a model result or a dataset file instead
of converting it by hand.

- from_inference reads a Roboflow depth model's result in every
  depth_map_format (JSON lists, 8- or 16-bit PNG, or the array the
  Inference SDK and Workflows decode), including an in-process model's
  response, as relative_inverse.
- from_ultralytics reads YOLO26 depth results as metric depth in metres.
- from_transformers reads predicted_depth from the depth-estimation
  pipeline or a model output; Transformers does not say what a model
  predicts, so the kind is required.
- from_png16 loads 16-bit PNGs divided by the dataset's scale (KITTI,
  DrivingStereo, InStereo2K, Ultralytics depth datasets), and from_pfm
  loads Middlebury and SceneFlow PFM files, with unknown values as no
  depth.
- The how-to's loading section, docstring examples and a changelog
  entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	docs/changelog.md
@Borda
Borda requested a balanced review from Copilot October 7, 2026 17:31
@Borda Borda added the enhancement New feature or request label Oct 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Workflow tensors, PFM scale factors, and non-PNG payload validation are not handled correctly.

3 open findings
What changed in this PR

Adds standardized DepthMap loaders for model outputs and common depth dataset formats.

Changes:

  • Adds Inference, Ultralytics, Transformers, PNG16, and PFM loaders.
  • Adds offline tests for formats, validation, and byte order.
  • Updates depth documentation, examples, and changelog.

Assessment: Code quality 3/5 · Testing 4/5 · Documentation 4/5

File Description
src/​supervision/​depth/​core.py Adds model and file loader APIs.
src/​supervision/​depth/​readers.py Adds PNG16 and PFM readers.
src/​supervision/​depth/​annotators.py Updates the annotator example.
tests/​depth/​test_core.py Tests new DepthMap loaders.
tests/​depth/​test_readers.py Tests PFM parsing and validation.
docs/​how_to/​visualize_depth.md Documents supported loading workflows.
docs/​depth/​core.md Updates API-page metadata.
docs/​changelog.md Records the new loaders.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/supervision/depth/core.py Outdated
Comment thread src/supervision/depth/core.py
Comment thread src/supervision/depth/readers.py Outdated
cfviotti and others added 3 commits October 7, 2026 14:43
The how-to and the DepthAnnotator example read the image through
supervision._cv2, which the OpenCV migration guide marks private and not
application API. They now open it with Pillow, so the examples stay
OpenCV-free like the feature itself.

A fixed display_range narrower than 1e-20 no longer gets stretched by a
floor on its width; every range is already validated as low < high.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	docs/how_to/visualize_depth.md
#	src/supervision/depth/annotators.py
cfviotti and others added 4 commits October 7, 2026 15:06
The six colour tables now come from matplotlib, already a dependency,
instead of 140 lines of vendored hex. Colours are byte-identical to the
old tables on matplotlib 3.6.3 and 3.10.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No other annotator validates opacity, so DepthAnnotator no longer does
either. Also fixes a test docstring that mentioned cameras, which this
PR does not add.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The changelog says the annotator does not require OpenCV rather than
that it runs without it, and uses the ([#N](...)) link style. The
DepthKind docstring says relative_inverse only promises larger is nearer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cfviotti and others added 3 commits October 7, 2026 15:15
# Conflicts:
#	docs/changelog.md
#	docs/how_to/visualize_depth.md
The readers are only used by DepthMap.from_png16 and from_pfm, so they
are now underscored, and _UINT16_MAX is defined once. Test helper
constructors get one-line docstrings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each loading tab in the guide now runs as written: the image is opened
once with Pillow before the tabs. Inference loading is described as
depth models served by Roboflow Inference (Depth Anything, YOLO26
depth), from_png16 lists only sourced scales (KITTI disparity 256,
Ultralytics depth datasets 1000 by default), and the DepthMap class
docstring drops loader tabs that repeat each method's own example. The
changelog bullet is shorter with the ([#N](...)) link style.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base automatically changed from feat/depth-1-show to develop October 8, 2026 22:28
Brings in the squash-merged #2691 with Jirka's follow-ups. Adaptations:
- DepthMap._percentile_range stays removed (it now lives in annotators.py
  as _percentile_range); the loaders never called it.
- visualize_depth.md: the relative-depth inversion example imports numpy
  itself, since the loading section now imports numpy only in the Stereo tab.
- from_transformers docstring: relative_inverse is suggested for Depth
  Anything V1 and V2 (not V3, whose map grows with distance per DepthKind).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.01325% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 93%. Comparing base (2807e71) to head (c756bce).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop   #2694    +/-   ##
========================================
  Coverage       93%     93%            
========================================
  Files           82      83     +1     
  Lines        12822   12973   +151     
========================================
+ Hits         11967   12115   +148     
- Misses         855     858     +3     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

cfviotti and others added 3 commits October 9, 2026 01:12
Tests now pin what users hit when loading depth: a transformers model output
in bfloat16 that still carries grad loads like any other, and a zero
from_png16 scale, an undecodable from_inference PNG and a PFM with a cut-off
header each raise ValueError.

The 16-bit PNG reader now always casts to uint16 instead of branching on
dtype. Pillow before 10.3 opens these PNGs as int32, which the cast still
handles; its 16-bit range check is gone because a PNG cannot hold more.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Inference tab above loads Depth Anything V3 through from_inference,
which is already larger-is-nearer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move the PFM cases next to the PNG ones and drop the import of the
private reader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cfviotti
cfviotti marked this pull request as ready for review October 9, 2026 05:50
@cfviotti
cfviotti requested a review from SkalskiP as a code owner October 9, 2026 05:50
…cale files

from_inference now moves a tensor normalized_depth (as Workflows can return,
possibly on CUDA) to a NumPy array instead of failing. A base64 JPEG or GIF is
refused instead of being read as the lossless PNG the server sends. A PFM with
a zero or non-finite scale is refused; the scale's sign still gives the byte
order and its magnitude is not applied, as in the Middlebury reader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Borda
Borda requested a balanced review from Copilot October 9, 2026 07:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The PFM reader ignores the header’s scale magnitude, producing incorrect values for valid non-unit scales.

2 open findings
3 resolved since last review

🧠 Review effort: Balanced

Comment thread src/supervision/depth/readers.py
Comment thread src/supervision/depth/core.py
Brings in #2691 and #2692 (DepthClipRange) as merged, with the
maintainer's edits.

Adaptations:
- changelog: loaders bullet (#2694) sits above the new #2692 and #2697
  bullets.
- visualize_depth.md front matter: description covers loading and
  colouring over images and video.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	docs/changelog.md
#	docs/depth/core.md
#	docs/how_to/visualize_depth.md
#	src/supervision/depth/core.py
#	tests/depth/test_core.py
Borda and others added 4 commits October 9, 2026 20:40
- fix(depth): read the PFM scale through the guarded header loop
- fix(depth): wrap Pillow decode errors in from_png16 as ValueError
- docs(depth): comment the PFM header token loop

[resolve group] PR #2694 — items 5 6 23

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
- test(depth): cover from_png16 rejection of bad files and scales
- test(depth): pin from_pfm default kind, scale handling and header guards
- test(depth): cover from_inference null, shape, PNG mode and base64 edges
- test(depth): cover from_ultralytics batch, list, raw-array and integer inputs

[resolve group] PR #2694 — items 12 13 14 16

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
- fix(depth): reject str, bool and out-of-range scales in from_png16
- fix(depth): reject a list of results in from_ultralytics
- fix(depth): wrap invalid base64 depth in a ValueError
- fix(depth): reject integer depth before the float cast in model loaders
- docs(depth): note that model connectors share float32 inputs
- docs(depth): list the reachable errors of each loader
- docs(depth): state that from_inference maps need no inversion
- docs(depth): describe from_png16 scale and Ultralytics millimetres
- docs(depth): fix the from_ultralytics no-depth claim
- fix(depth): divide in float32 to fix the mypy error
- docs(depth): limit from_transformers to pipeline and post-processed results
- feat(depth): make scale and kind keyword-only in from_png16 and from_pfm
- docs(depth): state that from_png16 code 0 is no depth for every kind
- docs(depth): note that only the order of relative_inverse values is meaningful

[resolve group] PR #2694 — items 7 8 9 10 11 17 18 19 20 22 27 28 29 30

---
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
@Borda
Borda merged commit 60b4503 into develop Oct 9, 2026
38 of 39 checks passed
@Borda
Borda deleted the feat/depth-4-loaders branch October 9, 2026 19:37
Borda added a commit to Talhax55z/supervision that referenced this pull request Oct 11, 2026
Changes:
- Integrate target updates for DepthMap loaders and measurement, keypoint mAP, compact-mask resizing, and mAP support with their exports, docs, and tests.
- Resolve the changelog collision by preserving the PR mAR entry and target PR roboflow#2694, roboflow#2693, roboflow#2692, and roboflow#2697 entries; update date_modified.

Impact:
- The PR branch includes the fetched develop changes before report-item work, so follow-up validation runs against integrated code.
- The changelog keeps both sets of release notes without dropping target or PR intent.

Verification:
- git diff --check passed after resolution.
- Changelog assertions confirmed the PR and target entries and no conflict markers.
- git diff --name-only --diff-filter=U returned no paths.

Residual limits:
- The full project gate bundle remains before remediation closure.
- No source-specific regression tests have run after integration.

---

Co-authored-by: Codex <codex@openai.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants