Skip to content

Depth Estimation

supervision.depth.core.DepthMap

A per-pixel depth, disparity or relative depth map for one frame.

:class:~supervision.depth.core.DepthMap is to depth what :class:~supervision.key_points.core.KeyPoints is to pose: its own container, with its own :class:~supervision.depth.annotators.DepthAnnotator and model connectors. It belongs to the whole frame, so it is not a :class:~supervision.detection.core.Detections field; :meth:~supervision.depth.core.DepthMap.measure_detections brings the depth under each object into detections.data.

values are float32 in the kind's unit. For disparity_px and depth_m, non-finite values and values <= 0 are no depth; for relative_inverse, non-finite and negative values are no depth, because a normalised map puts its farthest real pixel at exactly 0. A disparity of 0 or less stays no depth even when camera.doffs_px > 0 would make a value in (-doffs_px, 0] convert to a finite distance, so such pixels become NaN in metres instead.

Attributes:

Name Type Description
values NDArray[float32]

(H, W) float32 values in the kind's unit.

kind DepthKind

What the values measure.

camera DepthCamera | None

Optional stereo camera, needed to convert disparity to metric depth.

Examples:

>>> import numpy as np
>>> import supervision as sv
>>> disparity = np.array([[0.0, 10.0], [20.0, 40.0]], dtype=np.float32)
>>> depth_map = sv.DepthMap(
...     disparity,
...     kind="disparity_px",
...     camera=sv.DepthCamera(fx_px=1000.0, baseline_m=0.1),
... )
>>> depth_map.valid_mask
array([[False,  True],
       [ True,  True]])
>>> depth_map.to_depth().to_float()
array([[ nan, 10. ],
       [ 5. ,  2.5]], dtype=float32)
Source code in src/supervision/depth/core.py
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
class DepthMap:
    """A per-pixel depth, disparity or relative depth map for one frame.

    :class:`~supervision.depth.core.DepthMap` is to depth what
    :class:`~supervision.key_points.core.KeyPoints` is to pose: its own container,
    with its own :class:`~supervision.depth.annotators.DepthAnnotator` and model
    connectors. It belongs to the whole frame, so it is not a
    :class:`~supervision.detection.core.Detections` field;
    :meth:`~supervision.depth.core.DepthMap.measure_detections` brings the depth
    under each object into `detections.data`.

    `values` are float32 in the kind's unit. For `disparity_px` and `depth_m`,
    non-finite values and values `<= 0` are no depth; for `relative_inverse`,
    non-finite and negative values are no depth, because a normalised map puts its
    farthest real pixel at exactly 0. A disparity of 0 or less stays no depth even
    when `camera.doffs_px > 0` would make a value in `(-doffs_px, 0]` convert to a
    finite distance, so such pixels become `NaN` in metres instead.

    Attributes:
        values: `(H, W)` float32 values in the kind's unit.
        kind: What the values measure.
        camera: Optional stereo camera, needed to convert disparity to metric depth.

    Examples:
        ```pycon
        >>> import numpy as np
        >>> import supervision as sv
        >>> disparity = np.array([[0.0, 10.0], [20.0, 40.0]], dtype=np.float32)
        >>> depth_map = sv.DepthMap(
        ...     disparity,
        ...     kind="disparity_px",
        ...     camera=sv.DepthCamera(fx_px=1000.0, baseline_m=0.1),
        ... )
        >>> depth_map.valid_mask
        array([[False,  True],
               [ True,  True]])
        >>> depth_map.to_depth().to_float()
        array([[ nan, 10. ],
               [ 5. ,  2.5]], dtype=float32)

        ```
    """

    values: npt.NDArray[np.float32]
    kind: DepthKind
    camera: DepthCamera | None

    def __init__(
        self,
        values: npt.NDArray[np.floating],
        kind: DepthKind | str,
        camera: DepthCamera | None = None,
    ) -> None:
        """Create a depth map from float values in the kind's unit.

        Args:
            values: `(H, W)` float array in the kind's unit; any float dtype is
                stored as float32. A float32 array is stored without a copy, so
                later changes to it show in the map. Masked-array masks are
                ignored: mark missing depth with `NaN`, an infinity or a value the
                kind treats as no depth.
            kind: What the values measure, as a
                :class:`~supervision.depth.core.DepthKind` or its string value.
            camera: Optional stereo camera parameters. A `relative_inverse` map has
                no metric scale for a camera to give, so it takes none.

        Raises:
            ValueError: If the values are not a 2D float array, or the camera is
                invalid or given for a `relative_inverse` map.
        """
        array = np.asarray(values)
        if array.ndim != 2 or array.size == 0:
            raise ValueError(
                f"DepthMap values must be a non-empty (H, W) array, got {array.shape}."
            )
        if not np.issubdtype(array.dtype, np.floating):
            raise ValueError(
                f"DepthMap values must be float, got {array.dtype}. Divide integer "
                "codes, such as a 16-bit PNG's, by your dataset's scale first, or "
                "load the file with sv.DepthMap.from_png16."
            )
        if camera is not None and not isinstance(camera, DepthCamera):
            raise ValueError("DepthMap camera must be a sv.DepthCamera or None.")
        depth_kind = DepthKind.from_value(kind)
        if camera is not None and depth_kind is DepthKind.RELATIVE_INVERSE:
            raise ValueError(
                "A relative_inverse map has no metric scale, so no DepthCamera can "
                "convert it; pass camera=None."
            )
        self.values = array.astype(np.float32, copy=False)
        self.kind = depth_kind
        self.camera = camera

    def __repr__(self) -> str:
        """Summarise the map without printing its values."""
        width, height = self.resolution_wh
        return (
            f"DepthMap(kind={self.kind.value!r}, resolution_wh=({width}, {height}), "
            f"camera={self.camera})"
        )

    def __eq__(self, other: object) -> bool:
        """Compare every field; values compare NaN equal to NaN."""
        if not isinstance(other, DepthMap):
            return NotImplemented
        return (
            self.kind is other.kind
            and self.camera == other.camera
            and np.array_equal(self.values, other.values, equal_nan=True)
        )

    @property
    def resolution_wh(self) -> tuple[int, int]:
        """The map's `(width, height)` in pixels."""
        height, width = self.values.shape
        return int(width), int(height)

    @property
    def valid_mask(self) -> npt.NDArray[np.bool_]:
        """A boolean `(H, W)` array, `True` where the map holds depth."""
        return _holds_depth(self.values, self.kind)

    def to_float(self, no_depth_value: float = np.nan) -> npt.NDArray[np.float32]:
        """Return the values in the kind's unit as a new float32 array.

        Args:
            no_depth_value: The value written where the map has no depth.

        Returns:
            A `(H, W)` float32 array.

        Examples:
            ```pycon
            >>> import numpy as np
            >>> import supervision as sv
            >>> disparity = np.array([[np.nan, 1.0, 10.0]], dtype=np.float32)
            >>> sv.DepthMap(disparity, kind="disparity_px").to_float(0.0)
            array([[ 0.,  1., 10.]], dtype=float32)

            ```
        """
        result: npt.NDArray[np.float32] = self.values.copy()
        result[~self.valid_mask] = no_depth_value
        return result

    @classmethod
    def from_inference(cls, inference_result: Any) -> DepthMap:
        """Create a :class:`~supervision.depth.core.DepthMap` from a depth model served
        by Roboflow Inference.

        Reads the `normalized_depth` that Inference's depth models (Depth Anything,
        YOLO26 depth) return in every `depth_map_format` (`json` nested lists,
        `png16` or `png8` base64 PNGs, or the NumPy array the Inference SDK and
        Workflows decode them to). The map is normalised per image with 1 for
        the nearest pixel and 0 for the farthest, so larger is nearer. It loads as
        `relative_inverse` float32, as it is and with nothing inverted: Inference
        returns larger-is-nearer for every model, Depth Anything V3 included, so do
        not invert it again. Values from different images are not comparable. A
        float32 array is shared with the map, not copied.

        Args:
            inference_result: One result from Inference, the Inference SDK or a
                Workflow's depth estimation step.

        Returns:
            A `relative_inverse` :class:`~supervision.depth.core.DepthMap`.

        Raises:
            ValueError: If the result is a list or carries no `normalized_depth`, or
                the depth is not a decodable single (H, W) map.

        Examples:
            ```python
            import supervision as sv
            from inference_sdk import InferenceHTTPClient

            client = InferenceHTTPClient(
                api_url="https://serverless.roboflow.com", api_key="<ROBOFLOW_API_KEY>"
            )
            result = client.depth_estimation(
                "<SOURCE_IMAGE_PATH>",
                model_id="depth-anything-v3/small",
                depth_map_format="png16",
            )
            depth_map = sv.DepthMap.from_inference(result)
            ```
        """
        if isinstance(inference_result, list):
            raise ValueError(
                "from_inference() operates on a single result at a time. You can "
                "retrieve it like so: inference_result = model.infer(image)[0]"
            )
        # In-process models return an LMMInferenceResponse holding the depth in a
        # `response` dict; Inference's DepthEstimationResponse holds it as a field.
        response = getattr(inference_result, "response", None)
        if isinstance(response, dict):
            inference_result = response
        if isinstance(inference_result, dict):
            normalized = inference_result.get("normalized_depth")
        else:
            normalized = getattr(inference_result, "normalized_depth", None)
        if normalized is None:
            raise ValueError(
                "The inference result has no 'normalized_depth'; pass the result of "
                "a depth estimation model."
            )
        if isinstance(normalized, str):
            values = _decode_normalized_png(normalized)
        else:
            values = _to_numpy(normalized)
        return cls(_squeeze_to_2d(values, "Inference"), kind=DepthKind.RELATIVE_INVERSE)

    @classmethod
    def from_ultralytics(cls, ultralytics_results: Any) -> DepthMap:
        """Create a :class:`~supervision.depth.core.DepthMap` from an Ultralytics YOLO26
        depth result.

        `result.depth.data` holds metric depth in metres at the original image size,
        where values `<= 0` are no depth. A float32 depth is shared with the map,
        not copied.

        Args:
            ultralytics_results: One `Results` object from a depth model.

        Returns:
            A `depth_m` :class:`~supervision.depth.core.DepthMap`.

        Raises:
            ValueError: If the result is a list or carries no depth map, or the depth
                is not a single (H, W) map.

        Examples:
            ```python
            import supervision as sv
            from ultralytics import YOLO

            model = YOLO("yolo26n-depth.pt")
            result = model("<SOURCE_IMAGE_PATH>")[0]
            depth_map = sv.DepthMap.from_ultralytics(result)
            ```
        """
        if isinstance(ultralytics_results, list):
            raise ValueError(
                "from_ultralytics() operates on a single result at a time; pass "
                "results[0]."
            )
        depth = getattr(ultralytics_results, "depth", None)
        if depth is None:
            raise ValueError(
                "The Ultralytics result has no depth map; run a depth model such as "
                "yolo26n-depth.pt."
            )
        values = _to_numpy(getattr(depth, "data", depth))
        return cls(_squeeze_to_2d(values, "Ultralytics"), kind=DepthKind.DEPTH_M)

    @classmethod
    def from_transformers(
        cls, transformers_results: Any, *, kind: DepthKind | str
    ) -> DepthMap:
        """Create a :class:`~supervision.depth.core.DepthMap` from a Hugging Face depth
        estimation result.

        Reads `predicted_depth` from a `depth-estimation` pipeline result or from a
        `post_process_depth_estimation(outputs, target_sizes=...)` entry. A raw model
        output is not supported: it is not resized to the image, and for some models,
        such as Depth Pro, post-processing also converts the prediction. The
        pipeline's `depth` image is an 8-bit per-image stretch for display and is
        ignored.
        Transformers does not say what the model predicts, so `kind` is required:
        `relative_inverse` for Depth Anything V1 and V2 and DPT relative models,
        `depth_m` for metric models such as Depth Pro, ZoeDepth or Depth Anything
        metric. A float32 `predicted_depth` is shared with the map, not copied.

        Args:
            transformers_results: One result holding `predicted_depth` of shape
                `(H, W)` or `(1, H, W)`.
            kind: What the model predicts.

        Returns:
            A float32 :class:`~supervision.depth.core.DepthMap`.

        Raises:
            ValueError: If the result is a list or has no `predicted_depth`, the depth
                is not a single (H, W) map, or `kind` names no kind.

        Examples:
            ```python
            import supervision as sv
            from transformers import pipeline

            estimator = pipeline(
                "depth-estimation", model="depth-anything/Depth-Anything-V2-Small-hf"
            )
            result = estimator("<SOURCE_IMAGE_PATH>")
            depth_map = sv.DepthMap.from_transformers(result, kind="relative_inverse")
            ```
        """
        if isinstance(transformers_results, list):
            raise ValueError(
                "from_transformers() operates on a single result at a time; pass "
                "results[0]."
            )
        if isinstance(transformers_results, dict):
            predicted = transformers_results.get("predicted_depth")
        else:
            predicted = getattr(transformers_results, "predicted_depth", None)
        if predicted is None:
            raise ValueError("The transformers result has no 'predicted_depth'.")
        values = _squeeze_to_2d(_to_numpy(predicted), "Transformers")
        return cls(values, kind=kind)

    @classmethod
    def from_png16(
        cls, path: str | Path, *, scale: float, kind: DepthKind | str
    ) -> DepthMap:
        """Load a depth map from a 16-bit grayscale PNG.

        Values load as float32 `code / scale`. Code 0 is no depth (`NaN`) for every
        kind, including `relative_inverse`; load Inference responses with
        :meth:`~supervision.depth.core.DepthMap.from_inference`. KITTI
        disparity uses `scale=256`; Ultralytics depth datasets store
        millimetres (`scale=1000`) unless the dataset YAML sets `depth_scale`.

        Args:
            path: Path to the PNG.
            scale: Divisor from stored value to the kind's unit.
            kind: What the values measure.

        Returns:
            A float32 :class:`~supervision.depth.core.DepthMap`.

        Raises:
            ValueError: If the file is not a single-channel 16-bit PNG, `scale` is
                not a usable positive number, or `kind` names no kind.

        Examples:
            ```python
            import supervision as sv

            depth_map = sv.DepthMap.from_png16(
                "disp_occ_0/000000_10.png", scale=256, kind="disparity_px"
            )
            ```
        """
        scale_value = _plain_float(scale, "from_png16 scale")
        float32_max = float(np.finfo(np.float32).max)
        # float64 bounds keep `code / scale` finite in float32 for every uint16 code;
        # the chained comparison also rejects NaN.
        if not _UINT16_MAX / float32_max <= scale_value <= float32_max:
            raise ValueError(
                "from_png16 scale must be a positive number whose float32 quotient "
                f"with any 16-bit code is finite, got {scale}."
            )
        DepthKind.from_value(kind)  # a bad kind fails before the file is read
        codes = _read_png16(path)
        values = codes.astype(np.float32) / np.float32(scale_value)
        values[codes == 0] = np.nan
        return cls(values, kind=kind)

    @classmethod
    def from_pfm(
        cls, path: str | Path, *, kind: DepthKind | str = DepthKind.DISPARITY_PX
    ) -> DepthMap:
        """Load a single-channel PFM file, the Middlebury and SceneFlow format.

        Rows are flipped to top first. Infinite values (Middlebury's unknown
        disparity) are no depth. The sign of the header's scale gives the byte
        order; its magnitude is not applied.

        Args:
            path: Path to the `.pfm` file.
            kind: What the values measure; disparity by default.

        Returns:
            A float32 :class:`~supervision.depth.core.DepthMap`.

        Raises:
            ValueError: If the file is not a valid grayscale PFM (bad header, scale
                or truncated), or `kind` names no kind.

        Examples:
            ```python
            import supervision as sv

            depth_map = sv.DepthMap.from_pfm("Adirondack/disp0.pfm")
            ```
        """
        DepthKind.from_value(kind)  # a bad kind fails before the file is read
        return cls(_read_pfm(path), kind=kind)

    def to_depth(self) -> DepthMap:
        """Return the map as metric depth in metres.

        A disparity map converts with `fx_px * baseline_m / (disparity + doffs_px)`;
        pixels where that is not a positive distance become no depth. A `depth_m`
        map is returned as it is.

        Returns:
            A `depth_m` map with float32 values.

        Raises:
            ValueError: If the map is `relative_inverse`, or a disparity map without
                a camera.
        """
        if self.kind is DepthKind.DEPTH_M:
            return self
        conversion = _resolve_conversion(self.kind, self.camera, DepthScale.METRIC)
        return self._converted(DepthKind.DEPTH_M, conversion)

    def _converted(self, kind: DepthKind, conversion: _Conversion) -> DepthMap:
        """Apply a reciprocal conversion, keeping only positive finite results."""
        converted = conversion.apply(self.to_float())
        with np.errstate(invalid="ignore"):
            converted[~_holds_depth(converted, kind)] = np.nan
        return DepthMap(converted, kind=kind, camera=self.camera)

    def _region_depths(
        self, region: npt.NDArray[np.float32], conversion: _Conversion | None
    ) -> npt.NDArray[np.float32]:
        """Return a region's depth values, converted to metres by `conversion` if any.

        Keeps the pixels `to_depth().to_float()` would keep: valid in the map, then,
        after the conversion, a positive finite distance.
        """
        depths = region[_holds_depth(region, self.kind)]
        if conversion is not None:
            depths = conversion.apply(depths)
            with np.errstate(invalid="ignore"):
                depths = depths[_holds_depth(depths, DepthKind.DEPTH_M)]
        return depths

    def resize(
        self,
        resolution_wh: tuple[int, int],
        method: DepthResizeMethod | str = DepthResizeMethod.NEAREST,
    ) -> DepthMap:
        """Return the map resized to `resolution_wh` without blending any pixels.

        Blending would mix no-depth pixels into their neighbours and average a
        foreground edge into the background, inventing depths nobody measured, so
        both methods only pick existing values:

        - `"nearest"` takes the pixel under each target pixel's centre.
        - `"foreground"` keeps, in each group of source pixels a target pixel covers,
          the valid value nearest the camera (the largest disparity, the smallest
          depth), so thin near objects survive shrinking and holes never win over
          depth. An axis that grows samples the nearest pixel.

        Disparity is measured in pixels of the map, so a disparity map's values scale
        with the width ratio, and so do the camera's pixel parameters.

        Args:
            resolution_wh: Target `(width, height)`.
            method: A :class:`~supervision.depth.core.DepthResizeMethod` or its
                case-insensitive string value,
                `"nearest"` (default) or `"foreground"`.

        Returns:
            A new :class:`~supervision.depth.core.DepthMap`.

        Raises:
            ValueError: If the resolution is not positive or the method is unknown.

        Examples:
            ```pycon
            >>> import numpy as np
            >>> import supervision as sv
            >>> disparity = np.array([[8.0, 0.0, 2.0, 2.0]], dtype=np.float32)
            >>> depth_map = sv.DepthMap(disparity, kind="disparity_px")
            >>> depth_map.resize((2, 1), method="foreground").to_float()
            array([[4., 1.]], dtype=float32)

            ```
        """
        width, height = _check_resolution(resolution_wh)
        resize_method = DepthResizeMethod.from_value(method)
        source_width, source_height = self.resolution_wh
        if resize_method is DepthResizeMethod.NEAREST:
            rows = _index_map(source_height, height)
            columns = _index_map(source_width, width)
            values = self.values.take(rows, axis=0).take(columns, axis=1)
        else:
            values = self._pool_foreground(width, height)
        ratio_x = width / source_width
        if self.kind is DepthKind.DISPARITY_PX:
            values = values * np.float32(ratio_x)
        camera = None if self.camera is None else self.camera._scaled(ratio_x)
        return DepthMap(values, kind=self.kind, camera=camera)

    def _pool_foreground(self, width: int, height: int) -> npt.NDArray[np.float32]:
        """Pool each target pixel's source block to its nearest valid value."""
        source_width, source_height = self.resolution_wh
        if width >= source_width and height >= source_height:
            # Neither axis shrinks, so there is nothing to pool: a nearest take on
            # the values with holes as NaN gives the same map without the full-size
            # key temporaries.
            filled = self.to_float()
            return filled.take(_index_map(source_height, height), axis=0).take(
                _index_map(source_width, width), axis=1
            )
        valid = self.valid_mask
        near_is_low = self.kind is DepthKind.DEPTH_M
        signed = -self.values if near_is_low else self.values
        keys = np.where(valid, signed, -np.inf).astype(np.float32, copy=False)
        pooled = _pool_axis(_pool_axis(keys, height, axis=0), width, axis=1)
        restored = -pooled if near_is_low else pooled
        foreground: npt.NDArray[np.float32] = np.where(
            np.isfinite(pooled), restored, np.nan
        ).astype(np.float32, copy=False)
        return foreground

    def crop(self, xyxy: npt.ArrayLike) -> DepthMap:
        """Return the part of the map inside a box.

        Coordinates are rounded and clipped to the map, as in `sv.crop_image`. Values
        are unchanged.

        Args:
            xyxy: Box as `(x_min, y_min, x_max, y_max)` in map pixels.

        Returns:
            A new :class:`~supervision.depth.core.DepthMap`.

        Raises:
            ValueError: If the box is not four finite numbers or does not overlap
                the map.

        Examples:
            ```pycon
            >>> import numpy as np
            >>> import supervision as sv
            >>> depth_map = sv.DepthMap(np.ones((100, 200), np.float32), kind="depth_m")
            >>> depth_map.crop((50, 10, 150, 60)).resolution_wh
            (100, 50)

            ```
        """
        width, height = self.resolution_wh
        box = np.asarray(xyxy, dtype=np.float64).flatten()
        if box.shape != (4,) or not np.isfinite(box).all():
            raise ValueError(
                "Crop box must be four finite numbers (x_min, y_min, x_max, y_max), "
                f"got {np.asarray(xyxy).tolist()}."
            )
        pixel_box = _pixel_boxes(box[np.newaxis], (width, height))[0]
        x_min, y_min, x_max, y_max = pixel_box.tolist()
        if x_max <= x_min or y_max <= y_min:
            raise ValueError(
                f"Crop box {np.asarray(xyxy).tolist()} does not overlap the "
                f"{width}x{height} map."
            )
        return DepthMap(
            self.values[y_min:y_max, x_min:x_max].copy(),
            kind=self.kind,
            camera=self.camera,
        )

    def value_at(
        self,
        x: float,
        y: float,
        resolution_wh: tuple[int, int] | None = None,
    ) -> float | None:
        """Return the value in the kind's unit under a point, or `None`.

        The unit is the map's own: metres for `depth_m`, pixels for `disparity_px`.
        Call :meth:`~supervision.depth.core.DepthMap.to_depth` first for metres
        from a disparity map with a camera. Missing values are `None` here, but
        `NaN` in :meth:`~supervision.depth.core.DepthMap.to_float` and in the
        columns :meth:`~supervision.depth.core.DepthMap.measure_detections` writes.

        Args:
            x: Column of the point.
            y: Row of the point.
            resolution_wh: Size of the space the point is measured in, normally the
                image's, when the map is stretched over an image of another size.
                Without it the point is in map pixels. The point is a continuous
                coordinate, where pixel `i` spans `[i, i + 1)`: for a pixel index,
                pass its centre, `x + 0.5` and `y + 0.5`, to read the value that
                :meth:`~supervision.depth.core.DepthMap.resize` and
                :class:`~supervision.depth.annotators.DepthAnnotator`
                show at that pixel.

        Returns:
            The value, or `None` where the map has no depth or the point is outside
            the map.

        Raises:
            ValueError: If `resolution_wh` is not two positive integers.

        Examples:
            ```pycon
            >>> import numpy as np
            >>> import supervision as sv
            >>> disparity = np.array([[np.nan, 10.0]], dtype=np.float32)
            >>> depth_map = sv.DepthMap(disparity, kind="disparity_px")
            >>> depth_map.value_at(1, 0), depth_map.value_at(0, 0)
            (10.0, None)
            >>> depth_map.value_at(300, 100, resolution_wh=(400, 200))
            10.0
            >>> metric = np.array([[1.0, 2.0, 3.0, 4.0]], dtype=np.float32)
            >>> depth_map = sv.DepthMap(metric, kind="depth_m")
            >>> depth_map.resize((3, 1)).value_at(1, 0)
            3.0
            >>> depth_map.value_at(1 + 0.5, 0 + 0.5, resolution_wh=(3, 1))
            3.0

            ```
        """
        width, height = self.resolution_wh
        scale_x = scale_y = 1.0
        if resolution_wh is not None:
            target_width, target_height = _check_resolution(resolution_wh)
            scale_x, scale_y = width / target_width, height / target_height
        column, row = x * scale_x, y * scale_y
        if not (math.isfinite(column) and math.isfinite(row)):
            return None
        column_index, row_index = math.floor(column), math.floor(row)
        if not (0 <= column_index < width and 0 <= row_index < height):
            return None
        # Only this pixel is checked; `valid_mask` would test the whole frame.
        value = self.values[row_index, column_index]
        if not _holds_depth(value, self.kind):
            return None
        return float(value)

    def measure_detections(
        self,
        detections: Detections,
        resolution_wh: tuple[int, int] | None = None,
    ) -> Detections:
        """Return the detections with the median depth under each object in `data`.

        For each detection, the median of the valid depth pixels inside its mask
        (dense or :class:`~supervision.detection.compact_mask.CompactMask`) or,
        without masks, inside its box (rounded and clipped as in
        :func:`~supervision.utils.image.crop_image`) is stored in a new `data`
        column. The depth is
        in metres, under `"depth_m"`, when the map can give them (a `depth_m` map, or
        a disparity map with a camera), and in the map's own kind otherwise, under
        `"disparity_px"` or `"relative_inverse"`
        (`supervision.config.DEPTH_M_DATA_FIELD` and its siblings), so a disparity
        map without a camera never writes `"depth_m"`. A column of the same name
        already in `data` is replaced. Objects whose
        region holds no depth get `NaN`.

        Pass `resolution_wh` when the detections come from an image of another size
        than the map, such as a monocular model's output: the map is then stretched
        over the image as :class:`~supervision.depth.annotators.DepthAnnotator`
        draws it, each image pixel taking the
        map value under its centre, so even a small box gets depth. The values keep
        the map's own unit; unlike :meth:`~supervision.depth.core.DepthMap.resize`,
        a disparity map's values are not
        rescaled.

        Args:
            detections: :class:`~supervision.detection.core.Detections` in the
                map's pixel coordinates, or in the
                coordinates of an image of `resolution_wh`.
            resolution_wh: Size of the image the detections and their masks belong
                to, when it differs from the map's. Without it they are in map
                pixels.

        Returns:
            A new :class:`~supervision.detection.core.Detections` with the added
            `data` column, float32 of shape
            `(N,)`. It shares the input's arrays (`xyxy`, `mask` and the other `data`
            columns) rather than copying them.

        Raises:
            ValueError: If `resolution_wh` is not two positive integers, or the masks
                do not match the map's size or `resolution_wh`.

        Examples:
            ```pycon
            >>> import numpy as np
            >>> import supervision as sv
            >>> depth = np.full((100, 100), 20.0, dtype=np.float32)
            >>> depth[20:40, 20:40] = 4.0
            >>> depth_map = sv.DepthMap(depth, kind="depth_m")
            >>> detections = sv.Detections(
            ...     xyxy=np.array([[20, 20, 40, 40], [60, 60, 90, 90]], dtype=float)
            ... )
            >>> detections = depth_map.measure_detections(detections)
            >>> detections.data["depth_m"]
            array([ 4., 20.], dtype=float32)
            >>> labels = [f"{d:.1f} m" for d in detections.data["depth_m"]]

            ```
        """
        # Only the gathered pixels are converted to metres, not the whole frame;
        # the conversion is elementwise, so the medians match `to_depth()` exactly.
        conversion = None
        kind = self.kind
        if kind is DepthKind.DISPARITY_PX and self.camera is not None:
            conversion = _resolve_conversion(kind, self.camera, DepthScale.METRIC)
            kind = DepthKind.DEPTH_M
        values = self.values
        if resolution_wh is not None:
            values = _stretch(values, resolution_wh)
        height, width = values.shape
        medians = np.full(len(detections), np.nan, dtype=np.float32)
        mask = detections.mask
        if mask is not None:
            mask_shape = mask.shape[1:]
            if tuple(mask_shape) != (height, width):
                raise ValueError(
                    f"Detection masks are {mask_shape[1]}x{mask_shape[0]} but the "
                    f"depth map is measured at {width}x{height}; pass the masks' "
                    "image size as resolution_wh, or resize the map with "
                    "depth_map.resize(...) first."
                )
        # A CompactMask yields each crop with its origin, so no full-frame mask is
        # decoded per detection.
        regions = (
            (
                _values_in_box(values, box)
                for box in _pixel_boxes(detections.xyxy, (width, height))
            )
            if mask is None
            else (
                _values_under_mask(values, crop, offset)
                for _, crop, offset in _iter_mask_crops(detections)
            )
        )
        for index, region in enumerate(regions):
            depths = self._region_depths(region, conversion)
            if depths.size:
                medians[index] = np.median(depths)
        field = _DATA_FIELD_BY_KIND[kind]
        return replace(detections, data={**detections.data, field: medians})

Attributes

resolution_wh: tuple[int, int] property

The map's (width, height) in pixels.

valid_mask: npt.NDArray[np.bool_] property

A boolean (H, W) array, True where the map holds depth.

Methods:

__eq__(other: object) -> bool

Compare every field; values compare NaN equal to NaN.

Source code in src/supervision/depth/core.py
def __eq__(self, other: object) -> bool:
    """Compare every field; values compare NaN equal to NaN."""
    if not isinstance(other, DepthMap):
        return NotImplemented
    return (
        self.kind is other.kind
        and self.camera == other.camera
        and np.array_equal(self.values, other.values, equal_nan=True)
    )

__init__(values: npt.NDArray[np.floating], kind: DepthKind | str, camera: DepthCamera | None = None) -> None

Create a depth map from float values in the kind's unit.

Parameters:

Name Type Description Default
values
NDArray[floating]

(H, W) float array in the kind's unit; any float dtype is stored as float32. A float32 array is stored without a copy, so later changes to it show in the map. Masked-array masks are ignored: mark missing depth with NaN, an infinity or a value the kind treats as no depth.

required
kind
DepthKind | str

What the values measure, as a :class:~supervision.depth.core.DepthKind or its string value.

required
camera
DepthCamera | None

Optional stereo camera parameters. A relative_inverse map has no metric scale for a camera to give, so it takes none.

None

Raises:

Type Description
ValueError

If the values are not a 2D float array, or the camera is invalid or given for a relative_inverse map.

Source code in src/supervision/depth/core.py
def __init__(
    self,
    values: npt.NDArray[np.floating],
    kind: DepthKind | str,
    camera: DepthCamera | None = None,
) -> None:
    """Create a depth map from float values in the kind's unit.

    Args:
        values: `(H, W)` float array in the kind's unit; any float dtype is
            stored as float32. A float32 array is stored without a copy, so
            later changes to it show in the map. Masked-array masks are
            ignored: mark missing depth with `NaN`, an infinity or a value the
            kind treats as no depth.
        kind: What the values measure, as a
            :class:`~supervision.depth.core.DepthKind` or its string value.
        camera: Optional stereo camera parameters. A `relative_inverse` map has
            no metric scale for a camera to give, so it takes none.

    Raises:
        ValueError: If the values are not a 2D float array, or the camera is
            invalid or given for a `relative_inverse` map.
    """
    array = np.asarray(values)
    if array.ndim != 2 or array.size == 0:
        raise ValueError(
            f"DepthMap values must be a non-empty (H, W) array, got {array.shape}."
        )
    if not np.issubdtype(array.dtype, np.floating):
        raise ValueError(
            f"DepthMap values must be float, got {array.dtype}. Divide integer "
            "codes, such as a 16-bit PNG's, by your dataset's scale first, or "
            "load the file with sv.DepthMap.from_png16."
        )
    if camera is not None and not isinstance(camera, DepthCamera):
        raise ValueError("DepthMap camera must be a sv.DepthCamera or None.")
    depth_kind = DepthKind.from_value(kind)
    if camera is not None and depth_kind is DepthKind.RELATIVE_INVERSE:
        raise ValueError(
            "A relative_inverse map has no metric scale, so no DepthCamera can "
            "convert it; pass camera=None."
        )
    self.values = array.astype(np.float32, copy=False)
    self.kind = depth_kind
    self.camera = camera

__repr__() -> str

Summarise the map without printing its values.

Source code in src/supervision/depth/core.py
def __repr__(self) -> str:
    """Summarise the map without printing its values."""
    width, height = self.resolution_wh
    return (
        f"DepthMap(kind={self.kind.value!r}, resolution_wh=({width}, {height}), "
        f"camera={self.camera})"
    )

crop(xyxy: npt.ArrayLike) -> DepthMap

Return the part of the map inside a box.

Coordinates are rounded and clipped to the map, as in sv.crop_image. Values are unchanged.

Parameters:

Name Type Description Default
xyxy
ArrayLike

Box as (x_min, y_min, x_max, y_max) in map pixels.

required

Returns:

Type Description
DepthMap

A new :class:~supervision.depth.core.DepthMap.

Raises:

Type Description
ValueError

If the box is not four finite numbers or does not overlap the map.

Examples:

>>> import numpy as np
>>> import supervision as sv
>>> depth_map = sv.DepthMap(np.ones((100, 200), np.float32), kind="depth_m")
>>> depth_map.crop((50, 10, 150, 60)).resolution_wh
(100, 50)
Source code in src/supervision/depth/core.py
def crop(self, xyxy: npt.ArrayLike) -> DepthMap:
    """Return the part of the map inside a box.

    Coordinates are rounded and clipped to the map, as in `sv.crop_image`. Values
    are unchanged.

    Args:
        xyxy: Box as `(x_min, y_min, x_max, y_max)` in map pixels.

    Returns:
        A new :class:`~supervision.depth.core.DepthMap`.

    Raises:
        ValueError: If the box is not four finite numbers or does not overlap
            the map.

    Examples:
        ```pycon
        >>> import numpy as np
        >>> import supervision as sv
        >>> depth_map = sv.DepthMap(np.ones((100, 200), np.float32), kind="depth_m")
        >>> depth_map.crop((50, 10, 150, 60)).resolution_wh
        (100, 50)

        ```
    """
    width, height = self.resolution_wh
    box = np.asarray(xyxy, dtype=np.float64).flatten()
    if box.shape != (4,) or not np.isfinite(box).all():
        raise ValueError(
            "Crop box must be four finite numbers (x_min, y_min, x_max, y_max), "
            f"got {np.asarray(xyxy).tolist()}."
        )
    pixel_box = _pixel_boxes(box[np.newaxis], (width, height))[0]
    x_min, y_min, x_max, y_max = pixel_box.tolist()
    if x_max <= x_min or y_max <= y_min:
        raise ValueError(
            f"Crop box {np.asarray(xyxy).tolist()} does not overlap the "
            f"{width}x{height} map."
        )
    return DepthMap(
        self.values[y_min:y_max, x_min:x_max].copy(),
        kind=self.kind,
        camera=self.camera,
    )

from_inference(inference_result: Any) -> DepthMap classmethod

Create a :class:~supervision.depth.core.DepthMap from a depth model served by Roboflow Inference.

Reads the normalized_depth that Inference's depth models (Depth Anything, YOLO26 depth) return in every depth_map_format (json nested lists, png16 or png8 base64 PNGs, or the NumPy array the Inference SDK and Workflows decode them to). The map is normalised per image with 1 for the nearest pixel and 0 for the farthest, so larger is nearer. It loads as relative_inverse float32, as it is and with nothing inverted: Inference returns larger-is-nearer for every model, Depth Anything V3 included, so do not invert it again. Values from different images are not comparable. A float32 array is shared with the map, not copied.

Parameters:

Name Type Description Default
inference_result
Any

One result from Inference, the Inference SDK or a Workflow's depth estimation step.

required

Returns:

Type Description
DepthMap

A relative_inverse :class:~supervision.depth.core.DepthMap.

Raises:

Type Description
ValueError

If the result is a list or carries no normalized_depth, or the depth is not a decodable single (H, W) map.

Examples:

import supervision as sv
from inference_sdk import InferenceHTTPClient

client = InferenceHTTPClient(
    api_url="https://serverless.roboflow.com", api_key="<ROBOFLOW_API_KEY>"
)
result = client.depth_estimation(
    "<SOURCE_IMAGE_PATH>",
    model_id="depth-anything-v3/small",
    depth_map_format="png16",
)
depth_map = sv.DepthMap.from_inference(result)
Source code in src/supervision/depth/core.py
@classmethod
def from_inference(cls, inference_result: Any) -> DepthMap:
    """Create a :class:`~supervision.depth.core.DepthMap` from a depth model served
    by Roboflow Inference.

    Reads the `normalized_depth` that Inference's depth models (Depth Anything,
    YOLO26 depth) return in every `depth_map_format` (`json` nested lists,
    `png16` or `png8` base64 PNGs, or the NumPy array the Inference SDK and
    Workflows decode them to). The map is normalised per image with 1 for
    the nearest pixel and 0 for the farthest, so larger is nearer. It loads as
    `relative_inverse` float32, as it is and with nothing inverted: Inference
    returns larger-is-nearer for every model, Depth Anything V3 included, so do
    not invert it again. Values from different images are not comparable. A
    float32 array is shared with the map, not copied.

    Args:
        inference_result: One result from Inference, the Inference SDK or a
            Workflow's depth estimation step.

    Returns:
        A `relative_inverse` :class:`~supervision.depth.core.DepthMap`.

    Raises:
        ValueError: If the result is a list or carries no `normalized_depth`, or
            the depth is not a decodable single (H, W) map.

    Examples:
        ```python
        import supervision as sv
        from inference_sdk import InferenceHTTPClient

        client = InferenceHTTPClient(
            api_url="https://serverless.roboflow.com", api_key="<ROBOFLOW_API_KEY>"
        )
        result = client.depth_estimation(
            "<SOURCE_IMAGE_PATH>",
            model_id="depth-anything-v3/small",
            depth_map_format="png16",
        )
        depth_map = sv.DepthMap.from_inference(result)
        ```
    """
    if isinstance(inference_result, list):
        raise ValueError(
            "from_inference() operates on a single result at a time. You can "
            "retrieve it like so: inference_result = model.infer(image)[0]"
        )
    # In-process models return an LMMInferenceResponse holding the depth in a
    # `response` dict; Inference's DepthEstimationResponse holds it as a field.
    response = getattr(inference_result, "response", None)
    if isinstance(response, dict):
        inference_result = response
    if isinstance(inference_result, dict):
        normalized = inference_result.get("normalized_depth")
    else:
        normalized = getattr(inference_result, "normalized_depth", None)
    if normalized is None:
        raise ValueError(
            "The inference result has no 'normalized_depth'; pass the result of "
            "a depth estimation model."
        )
    if isinstance(normalized, str):
        values = _decode_normalized_png(normalized)
    else:
        values = _to_numpy(normalized)
    return cls(_squeeze_to_2d(values, "Inference"), kind=DepthKind.RELATIVE_INVERSE)

from_pfm(path: str | Path, *, kind: DepthKind | str = DepthKind.DISPARITY_PX) -> DepthMap classmethod

Load a single-channel PFM file, the Middlebury and SceneFlow format.

Rows are flipped to top first. Infinite values (Middlebury's unknown disparity) are no depth. The sign of the header's scale gives the byte order; its magnitude is not applied.

Parameters:

Name Type Description Default
path
str | Path

Path to the .pfm file.

required
kind
DepthKind | str

What the values measure; disparity by default.

DISPARITY_PX

Returns:

Type Description
DepthMap

A float32 :class:~supervision.depth.core.DepthMap.

Raises:

Type Description
ValueError

If the file is not a valid grayscale PFM (bad header, scale or truncated), or kind names no kind.

Examples:

import supervision as sv

depth_map = sv.DepthMap.from_pfm("Adirondack/disp0.pfm")
Source code in src/supervision/depth/core.py
@classmethod
def from_pfm(
    cls, path: str | Path, *, kind: DepthKind | str = DepthKind.DISPARITY_PX
) -> DepthMap:
    """Load a single-channel PFM file, the Middlebury and SceneFlow format.

    Rows are flipped to top first. Infinite values (Middlebury's unknown
    disparity) are no depth. The sign of the header's scale gives the byte
    order; its magnitude is not applied.

    Args:
        path: Path to the `.pfm` file.
        kind: What the values measure; disparity by default.

    Returns:
        A float32 :class:`~supervision.depth.core.DepthMap`.

    Raises:
        ValueError: If the file is not a valid grayscale PFM (bad header, scale
            or truncated), or `kind` names no kind.

    Examples:
        ```python
        import supervision as sv

        depth_map = sv.DepthMap.from_pfm("Adirondack/disp0.pfm")
        ```
    """
    DepthKind.from_value(kind)  # a bad kind fails before the file is read
    return cls(_read_pfm(path), kind=kind)

from_png16(path: str | Path, *, scale: float, kind: DepthKind | str) -> DepthMap classmethod

Load a depth map from a 16-bit grayscale PNG.

Values load as float32 code / scale. Code 0 is no depth (NaN) for every kind, including relative_inverse; load Inference responses with :meth:~supervision.depth.core.DepthMap.from_inference. KITTI disparity uses scale=256; Ultralytics depth datasets store millimetres (scale=1000) unless the dataset YAML sets depth_scale.

Parameters:

Name Type Description Default
path
str | Path

Path to the PNG.

required
scale
float

Divisor from stored value to the kind's unit.

required
kind
DepthKind | str

What the values measure.

required

Returns:

Type Description
DepthMap

A float32 :class:~supervision.depth.core.DepthMap.

Raises:

Type Description
ValueError

If the file is not a single-channel 16-bit PNG, scale is not a usable positive number, or kind names no kind.

Examples:

import supervision as sv

depth_map = sv.DepthMap.from_png16(
    "disp_occ_0/000000_10.png", scale=256, kind="disparity_px"
)
Source code in src/supervision/depth/core.py
@classmethod
def from_png16(
    cls, path: str | Path, *, scale: float, kind: DepthKind | str
) -> DepthMap:
    """Load a depth map from a 16-bit grayscale PNG.

    Values load as float32 `code / scale`. Code 0 is no depth (`NaN`) for every
    kind, including `relative_inverse`; load Inference responses with
    :meth:`~supervision.depth.core.DepthMap.from_inference`. KITTI
    disparity uses `scale=256`; Ultralytics depth datasets store
    millimetres (`scale=1000`) unless the dataset YAML sets `depth_scale`.

    Args:
        path: Path to the PNG.
        scale: Divisor from stored value to the kind's unit.
        kind: What the values measure.

    Returns:
        A float32 :class:`~supervision.depth.core.DepthMap`.

    Raises:
        ValueError: If the file is not a single-channel 16-bit PNG, `scale` is
            not a usable positive number, or `kind` names no kind.

    Examples:
        ```python
        import supervision as sv

        depth_map = sv.DepthMap.from_png16(
            "disp_occ_0/000000_10.png", scale=256, kind="disparity_px"
        )
        ```
    """
    scale_value = _plain_float(scale, "from_png16 scale")
    float32_max = float(np.finfo(np.float32).max)
    # float64 bounds keep `code / scale` finite in float32 for every uint16 code;
    # the chained comparison also rejects NaN.
    if not _UINT16_MAX / float32_max <= scale_value <= float32_max:
        raise ValueError(
            "from_png16 scale must be a positive number whose float32 quotient "
            f"with any 16-bit code is finite, got {scale}."
        )
    DepthKind.from_value(kind)  # a bad kind fails before the file is read
    codes = _read_png16(path)
    values = codes.astype(np.float32) / np.float32(scale_value)
    values[codes == 0] = np.nan
    return cls(values, kind=kind)

from_transformers(transformers_results: Any, *, kind: DepthKind | str) -> DepthMap classmethod

Create a :class:~supervision.depth.core.DepthMap from a Hugging Face depth estimation result.

Reads predicted_depth from a depth-estimation pipeline result or from a post_process_depth_estimation(outputs, target_sizes=...) entry. A raw model output is not supported: it is not resized to the image, and for some models, such as Depth Pro, post-processing also converts the prediction. The pipeline's depth image is an 8-bit per-image stretch for display and is ignored. Transformers does not say what the model predicts, so kind is required: relative_inverse for Depth Anything V1 and V2 and DPT relative models, depth_m for metric models such as Depth Pro, ZoeDepth or Depth Anything metric. A float32 predicted_depth is shared with the map, not copied.

Parameters:

Name Type Description Default
transformers_results
Any

One result holding predicted_depth of shape (H, W) or (1, H, W).

required
kind
DepthKind | str

What the model predicts.

required

Returns:

Type Description
DepthMap

A float32 :class:~supervision.depth.core.DepthMap.

Raises:

Type Description
ValueError

If the result is a list or has no predicted_depth, the depth is not a single (H, W) map, or kind names no kind.

Examples:

import supervision as sv
from transformers import pipeline

estimator = pipeline(
    "depth-estimation", model="depth-anything/Depth-Anything-V2-Small-hf"
)
result = estimator("<SOURCE_IMAGE_PATH>")
depth_map = sv.DepthMap.from_transformers(result, kind="relative_inverse")
Source code in src/supervision/depth/core.py
@classmethod
def from_transformers(
    cls, transformers_results: Any, *, kind: DepthKind | str
) -> DepthMap:
    """Create a :class:`~supervision.depth.core.DepthMap` from a Hugging Face depth
    estimation result.

    Reads `predicted_depth` from a `depth-estimation` pipeline result or from a
    `post_process_depth_estimation(outputs, target_sizes=...)` entry. A raw model
    output is not supported: it is not resized to the image, and for some models,
    such as Depth Pro, post-processing also converts the prediction. The
    pipeline's `depth` image is an 8-bit per-image stretch for display and is
    ignored.
    Transformers does not say what the model predicts, so `kind` is required:
    `relative_inverse` for Depth Anything V1 and V2 and DPT relative models,
    `depth_m` for metric models such as Depth Pro, ZoeDepth or Depth Anything
    metric. A float32 `predicted_depth` is shared with the map, not copied.

    Args:
        transformers_results: One result holding `predicted_depth` of shape
            `(H, W)` or `(1, H, W)`.
        kind: What the model predicts.

    Returns:
        A float32 :class:`~supervision.depth.core.DepthMap`.

    Raises:
        ValueError: If the result is a list or has no `predicted_depth`, the depth
            is not a single (H, W) map, or `kind` names no kind.

    Examples:
        ```python
        import supervision as sv
        from transformers import pipeline

        estimator = pipeline(
            "depth-estimation", model="depth-anything/Depth-Anything-V2-Small-hf"
        )
        result = estimator("<SOURCE_IMAGE_PATH>")
        depth_map = sv.DepthMap.from_transformers(result, kind="relative_inverse")
        ```
    """
    if isinstance(transformers_results, list):
        raise ValueError(
            "from_transformers() operates on a single result at a time; pass "
            "results[0]."
        )
    if isinstance(transformers_results, dict):
        predicted = transformers_results.get("predicted_depth")
    else:
        predicted = getattr(transformers_results, "predicted_depth", None)
    if predicted is None:
        raise ValueError("The transformers result has no 'predicted_depth'.")
    values = _squeeze_to_2d(_to_numpy(predicted), "Transformers")
    return cls(values, kind=kind)

from_ultralytics(ultralytics_results: Any) -> DepthMap classmethod

Create a :class:~supervision.depth.core.DepthMap from an Ultralytics YOLO26 depth result.

result.depth.data holds metric depth in metres at the original image size, where values <= 0 are no depth. A float32 depth is shared with the map, not copied.

Parameters:

Name Type Description Default
ultralytics_results
Any

One Results object from a depth model.

required

Returns:

Type Description
DepthMap

A depth_m :class:~supervision.depth.core.DepthMap.

Raises:

Type Description
ValueError

If the result is a list or carries no depth map, or the depth is not a single (H, W) map.

Examples:

import supervision as sv
from ultralytics import YOLO

model = YOLO("yolo26n-depth.pt")
result = model("<SOURCE_IMAGE_PATH>")[0]
depth_map = sv.DepthMap.from_ultralytics(result)
Source code in src/supervision/depth/core.py
@classmethod
def from_ultralytics(cls, ultralytics_results: Any) -> DepthMap:
    """Create a :class:`~supervision.depth.core.DepthMap` from an Ultralytics YOLO26
    depth result.

    `result.depth.data` holds metric depth in metres at the original image size,
    where values `<= 0` are no depth. A float32 depth is shared with the map,
    not copied.

    Args:
        ultralytics_results: One `Results` object from a depth model.

    Returns:
        A `depth_m` :class:`~supervision.depth.core.DepthMap`.

    Raises:
        ValueError: If the result is a list or carries no depth map, or the depth
            is not a single (H, W) map.

    Examples:
        ```python
        import supervision as sv
        from ultralytics import YOLO

        model = YOLO("yolo26n-depth.pt")
        result = model("<SOURCE_IMAGE_PATH>")[0]
        depth_map = sv.DepthMap.from_ultralytics(result)
        ```
    """
    if isinstance(ultralytics_results, list):
        raise ValueError(
            "from_ultralytics() operates on a single result at a time; pass "
            "results[0]."
        )
    depth = getattr(ultralytics_results, "depth", None)
    if depth is None:
        raise ValueError(
            "The Ultralytics result has no depth map; run a depth model such as "
            "yolo26n-depth.pt."
        )
    values = _to_numpy(getattr(depth, "data", depth))
    return cls(_squeeze_to_2d(values, "Ultralytics"), kind=DepthKind.DEPTH_M)

measure_detections(detections: Detections, resolution_wh: tuple[int, int] | None = None) -> Detections

Return the detections with the median depth under each object in data.

For each detection, the median of the valid depth pixels inside its mask (dense or :class:~supervision.detection.compact_mask.CompactMask) or, without masks, inside its box (rounded and clipped as in :func:~supervision.utils.image.crop_image) is stored in a new data column. The depth is in metres, under "depth_m", when the map can give them (a depth_m map, or a disparity map with a camera), and in the map's own kind otherwise, under "disparity_px" or "relative_inverse" (supervision.config.DEPTH_M_DATA_FIELD and its siblings), so a disparity map without a camera never writes "depth_m". A column of the same name already in data is replaced. Objects whose region holds no depth get NaN.

Pass resolution_wh when the detections come from an image of another size than the map, such as a monocular model's output: the map is then stretched over the image as :class:~supervision.depth.annotators.DepthAnnotator draws it, each image pixel taking the map value under its centre, so even a small box gets depth. The values keep the map's own unit; unlike :meth:~supervision.depth.core.DepthMap.resize, a disparity map's values are not rescaled.

Parameters:

Name Type Description Default
detections
Detections

:class:~supervision.detection.core.Detections in the map's pixel coordinates, or in the coordinates of an image of resolution_wh.

required
resolution_wh
tuple[int, int] | None

Size of the image the detections and their masks belong to, when it differs from the map's. Without it they are in map pixels.

None

Returns:

Type Description
Detections

A new :class:~supervision.detection.core.Detections with the added

Detections

data column, float32 of shape

Detections

(N,). It shares the input's arrays (xyxy, mask and the other data

Detections

columns) rather than copying them.

Raises:

Type Description
ValueError

If resolution_wh is not two positive integers, or the masks do not match the map's size or resolution_wh.

Examples:

>>> import numpy as np
>>> import supervision as sv
>>> depth = np.full((100, 100), 20.0, dtype=np.float32)
>>> depth[20:40, 20:40] = 4.0
>>> depth_map = sv.DepthMap(depth, kind="depth_m")
>>> detections = sv.Detections(
...     xyxy=np.array([[20, 20, 40, 40], [60, 60, 90, 90]], dtype=float)
... )
>>> detections = depth_map.measure_detections(detections)
>>> detections.data["depth_m"]
array([ 4., 20.], dtype=float32)
>>> labels = [f"{d:.1f} m" for d in detections.data["depth_m"]]
Source code in src/supervision/depth/core.py
def measure_detections(
    self,
    detections: Detections,
    resolution_wh: tuple[int, int] | None = None,
) -> Detections:
    """Return the detections with the median depth under each object in `data`.

    For each detection, the median of the valid depth pixels inside its mask
    (dense or :class:`~supervision.detection.compact_mask.CompactMask`) or,
    without masks, inside its box (rounded and clipped as in
    :func:`~supervision.utils.image.crop_image`) is stored in a new `data`
    column. The depth is
    in metres, under `"depth_m"`, when the map can give them (a `depth_m` map, or
    a disparity map with a camera), and in the map's own kind otherwise, under
    `"disparity_px"` or `"relative_inverse"`
    (`supervision.config.DEPTH_M_DATA_FIELD` and its siblings), so a disparity
    map without a camera never writes `"depth_m"`. A column of the same name
    already in `data` is replaced. Objects whose
    region holds no depth get `NaN`.

    Pass `resolution_wh` when the detections come from an image of another size
    than the map, such as a monocular model's output: the map is then stretched
    over the image as :class:`~supervision.depth.annotators.DepthAnnotator`
    draws it, each image pixel taking the
    map value under its centre, so even a small box gets depth. The values keep
    the map's own unit; unlike :meth:`~supervision.depth.core.DepthMap.resize`,
    a disparity map's values are not
    rescaled.

    Args:
        detections: :class:`~supervision.detection.core.Detections` in the
            map's pixel coordinates, or in the
            coordinates of an image of `resolution_wh`.
        resolution_wh: Size of the image the detections and their masks belong
            to, when it differs from the map's. Without it they are in map
            pixels.

    Returns:
        A new :class:`~supervision.detection.core.Detections` with the added
        `data` column, float32 of shape
        `(N,)`. It shares the input's arrays (`xyxy`, `mask` and the other `data`
        columns) rather than copying them.

    Raises:
        ValueError: If `resolution_wh` is not two positive integers, or the masks
            do not match the map's size or `resolution_wh`.

    Examples:
        ```pycon
        >>> import numpy as np
        >>> import supervision as sv
        >>> depth = np.full((100, 100), 20.0, dtype=np.float32)
        >>> depth[20:40, 20:40] = 4.0
        >>> depth_map = sv.DepthMap(depth, kind="depth_m")
        >>> detections = sv.Detections(
        ...     xyxy=np.array([[20, 20, 40, 40], [60, 60, 90, 90]], dtype=float)
        ... )
        >>> detections = depth_map.measure_detections(detections)
        >>> detections.data["depth_m"]
        array([ 4., 20.], dtype=float32)
        >>> labels = [f"{d:.1f} m" for d in detections.data["depth_m"]]

        ```
    """
    # Only the gathered pixels are converted to metres, not the whole frame;
    # the conversion is elementwise, so the medians match `to_depth()` exactly.
    conversion = None
    kind = self.kind
    if kind is DepthKind.DISPARITY_PX and self.camera is not None:
        conversion = _resolve_conversion(kind, self.camera, DepthScale.METRIC)
        kind = DepthKind.DEPTH_M
    values = self.values
    if resolution_wh is not None:
        values = _stretch(values, resolution_wh)
    height, width = values.shape
    medians = np.full(len(detections), np.nan, dtype=np.float32)
    mask = detections.mask
    if mask is not None:
        mask_shape = mask.shape[1:]
        if tuple(mask_shape) != (height, width):
            raise ValueError(
                f"Detection masks are {mask_shape[1]}x{mask_shape[0]} but the "
                f"depth map is measured at {width}x{height}; pass the masks' "
                "image size as resolution_wh, or resize the map with "
                "depth_map.resize(...) first."
            )
    # A CompactMask yields each crop with its origin, so no full-frame mask is
    # decoded per detection.
    regions = (
        (
            _values_in_box(values, box)
            for box in _pixel_boxes(detections.xyxy, (width, height))
        )
        if mask is None
        else (
            _values_under_mask(values, crop, offset)
            for _, crop, offset in _iter_mask_crops(detections)
        )
    )
    for index, region in enumerate(regions):
        depths = self._region_depths(region, conversion)
        if depths.size:
            medians[index] = np.median(depths)
    field = _DATA_FIELD_BY_KIND[kind]
    return replace(detections, data={**detections.data, field: medians})

resize(resolution_wh: tuple[int, int], method: DepthResizeMethod | str = DepthResizeMethod.NEAREST) -> DepthMap

Return the map resized to resolution_wh without blending any pixels.

Blending would mix no-depth pixels into their neighbours and average a foreground edge into the background, inventing depths nobody measured, so both methods only pick existing values:

  • "nearest" takes the pixel under each target pixel's centre.
  • "foreground" keeps, in each group of source pixels a target pixel covers, the valid value nearest the camera (the largest disparity, the smallest depth), so thin near objects survive shrinking and holes never win over depth. An axis that grows samples the nearest pixel.

Disparity is measured in pixels of the map, so a disparity map's values scale with the width ratio, and so do the camera's pixel parameters.

Parameters:

Name Type Description Default
resolution_wh
tuple[int, int]

Target (width, height).

required
method
DepthResizeMethod | str

A :class:~supervision.depth.core.DepthResizeMethod or its case-insensitive string value, "nearest" (default) or "foreground".

NEAREST

Returns:

Type Description
DepthMap

A new :class:~supervision.depth.core.DepthMap.

Raises:

Type Description
ValueError

If the resolution is not positive or the method is unknown.

Examples:

>>> import numpy as np
>>> import supervision as sv
>>> disparity = np.array([[8.0, 0.0, 2.0, 2.0]], dtype=np.float32)
>>> depth_map = sv.DepthMap(disparity, kind="disparity_px")
>>> depth_map.resize((2, 1), method="foreground").to_float()
array([[4., 1.]], dtype=float32)
Source code in src/supervision/depth/core.py
def resize(
    self,
    resolution_wh: tuple[int, int],
    method: DepthResizeMethod | str = DepthResizeMethod.NEAREST,
) -> DepthMap:
    """Return the map resized to `resolution_wh` without blending any pixels.

    Blending would mix no-depth pixels into their neighbours and average a
    foreground edge into the background, inventing depths nobody measured, so
    both methods only pick existing values:

    - `"nearest"` takes the pixel under each target pixel's centre.
    - `"foreground"` keeps, in each group of source pixels a target pixel covers,
      the valid value nearest the camera (the largest disparity, the smallest
      depth), so thin near objects survive shrinking and holes never win over
      depth. An axis that grows samples the nearest pixel.

    Disparity is measured in pixels of the map, so a disparity map's values scale
    with the width ratio, and so do the camera's pixel parameters.

    Args:
        resolution_wh: Target `(width, height)`.
        method: A :class:`~supervision.depth.core.DepthResizeMethod` or its
            case-insensitive string value,
            `"nearest"` (default) or `"foreground"`.

    Returns:
        A new :class:`~supervision.depth.core.DepthMap`.

    Raises:
        ValueError: If the resolution is not positive or the method is unknown.

    Examples:
        ```pycon
        >>> import numpy as np
        >>> import supervision as sv
        >>> disparity = np.array([[8.0, 0.0, 2.0, 2.0]], dtype=np.float32)
        >>> depth_map = sv.DepthMap(disparity, kind="disparity_px")
        >>> depth_map.resize((2, 1), method="foreground").to_float()
        array([[4., 1.]], dtype=float32)

        ```
    """
    width, height = _check_resolution(resolution_wh)
    resize_method = DepthResizeMethod.from_value(method)
    source_width, source_height = self.resolution_wh
    if resize_method is DepthResizeMethod.NEAREST:
        rows = _index_map(source_height, height)
        columns = _index_map(source_width, width)
        values = self.values.take(rows, axis=0).take(columns, axis=1)
    else:
        values = self._pool_foreground(width, height)
    ratio_x = width / source_width
    if self.kind is DepthKind.DISPARITY_PX:
        values = values * np.float32(ratio_x)
    camera = None if self.camera is None else self.camera._scaled(ratio_x)
    return DepthMap(values, kind=self.kind, camera=camera)

to_depth() -> DepthMap

Return the map as metric depth in metres.

A disparity map converts with fx_px * baseline_m / (disparity + doffs_px); pixels where that is not a positive distance become no depth. A depth_m map is returned as it is.

Returns:

Type Description
DepthMap

A depth_m map with float32 values.

Raises:

Type Description
ValueError

If the map is relative_inverse, or a disparity map without a camera.

Source code in src/supervision/depth/core.py
def to_depth(self) -> DepthMap:
    """Return the map as metric depth in metres.

    A disparity map converts with `fx_px * baseline_m / (disparity + doffs_px)`;
    pixels where that is not a positive distance become no depth. A `depth_m`
    map is returned as it is.

    Returns:
        A `depth_m` map with float32 values.

    Raises:
        ValueError: If the map is `relative_inverse`, or a disparity map without
            a camera.
    """
    if self.kind is DepthKind.DEPTH_M:
        return self
    conversion = _resolve_conversion(self.kind, self.camera, DepthScale.METRIC)
    return self._converted(DepthKind.DEPTH_M, conversion)

to_float(no_depth_value: float = np.nan) -> npt.NDArray[np.float32]

Return the values in the kind's unit as a new float32 array.

Parameters:

Name Type Description Default
no_depth_value
float

The value written where the map has no depth.

nan

Returns:

Type Description
NDArray[float32]

A (H, W) float32 array.

Examples:

>>> import numpy as np
>>> import supervision as sv
>>> disparity = np.array([[np.nan, 1.0, 10.0]], dtype=np.float32)
>>> sv.DepthMap(disparity, kind="disparity_px").to_float(0.0)
array([[ 0.,  1., 10.]], dtype=float32)
Source code in src/supervision/depth/core.py
def to_float(self, no_depth_value: float = np.nan) -> npt.NDArray[np.float32]:
    """Return the values in the kind's unit as a new float32 array.

    Args:
        no_depth_value: The value written where the map has no depth.

    Returns:
        A `(H, W)` float32 array.

    Examples:
        ```pycon
        >>> import numpy as np
        >>> import supervision as sv
        >>> disparity = np.array([[np.nan, 1.0, 10.0]], dtype=np.float32)
        >>> sv.DepthMap(disparity, kind="disparity_px").to_float(0.0)
        array([[ 0.,  1., 10.]], dtype=float32)

        ```
    """
    result: npt.NDArray[np.float32] = self.values.copy()
    result[~self.valid_mask] = no_depth_value
    return result

value_at(x: float, y: float, resolution_wh: tuple[int, int] | None = None) -> float | None

Return the value in the kind's unit under a point, or None.

The unit is the map's own: metres for depth_m, pixels for disparity_px. Call :meth:~supervision.depth.core.DepthMap.to_depth first for metres from a disparity map with a camera. Missing values are None here, but NaN in :meth:~supervision.depth.core.DepthMap.to_float and in the columns :meth:~supervision.depth.core.DepthMap.measure_detections writes.

Parameters:

Name Type Description Default
x
float

Column of the point.

required
y
float

Row of the point.

required
resolution_wh
tuple[int, int] | None

Size of the space the point is measured in, normally the image's, when the map is stretched over an image of another size. Without it the point is in map pixels. The point is a continuous coordinate, where pixel i spans [i, i + 1): for a pixel index, pass its centre, x + 0.5 and y + 0.5, to read the value that :meth:~supervision.depth.core.DepthMap.resize and :class:~supervision.depth.annotators.DepthAnnotator show at that pixel.

None

Returns:

Type Description
float | None

The value, or None where the map has no depth or the point is outside

float | None

the map.

Raises:

Type Description
ValueError

If resolution_wh is not two positive integers.

Examples:

>>> import numpy as np
>>> import supervision as sv
>>> disparity = np.array([[np.nan, 10.0]], dtype=np.float32)
>>> depth_map = sv.DepthMap(disparity, kind="disparity_px")
>>> depth_map.value_at(1, 0), depth_map.value_at(0, 0)
(10.0, None)
>>> depth_map.value_at(300, 100, resolution_wh=(400, 200))
10.0
>>> metric = np.array([[1.0, 2.0, 3.0, 4.0]], dtype=np.float32)
>>> depth_map = sv.DepthMap(metric, kind="depth_m")
>>> depth_map.resize((3, 1)).value_at(1, 0)
3.0
>>> depth_map.value_at(1 + 0.5, 0 + 0.5, resolution_wh=(3, 1))
3.0
Source code in src/supervision/depth/core.py
def value_at(
    self,
    x: float,
    y: float,
    resolution_wh: tuple[int, int] | None = None,
) -> float | None:
    """Return the value in the kind's unit under a point, or `None`.

    The unit is the map's own: metres for `depth_m`, pixels for `disparity_px`.
    Call :meth:`~supervision.depth.core.DepthMap.to_depth` first for metres
    from a disparity map with a camera. Missing values are `None` here, but
    `NaN` in :meth:`~supervision.depth.core.DepthMap.to_float` and in the
    columns :meth:`~supervision.depth.core.DepthMap.measure_detections` writes.

    Args:
        x: Column of the point.
        y: Row of the point.
        resolution_wh: Size of the space the point is measured in, normally the
            image's, when the map is stretched over an image of another size.
            Without it the point is in map pixels. The point is a continuous
            coordinate, where pixel `i` spans `[i, i + 1)`: for a pixel index,
            pass its centre, `x + 0.5` and `y + 0.5`, to read the value that
            :meth:`~supervision.depth.core.DepthMap.resize` and
            :class:`~supervision.depth.annotators.DepthAnnotator`
            show at that pixel.

    Returns:
        The value, or `None` where the map has no depth or the point is outside
        the map.

    Raises:
        ValueError: If `resolution_wh` is not two positive integers.

    Examples:
        ```pycon
        >>> import numpy as np
        >>> import supervision as sv
        >>> disparity = np.array([[np.nan, 10.0]], dtype=np.float32)
        >>> depth_map = sv.DepthMap(disparity, kind="disparity_px")
        >>> depth_map.value_at(1, 0), depth_map.value_at(0, 0)
        (10.0, None)
        >>> depth_map.value_at(300, 100, resolution_wh=(400, 200))
        10.0
        >>> metric = np.array([[1.0, 2.0, 3.0, 4.0]], dtype=np.float32)
        >>> depth_map = sv.DepthMap(metric, kind="depth_m")
        >>> depth_map.resize((3, 1)).value_at(1, 0)
        3.0
        >>> depth_map.value_at(1 + 0.5, 0 + 0.5, resolution_wh=(3, 1))
        3.0

        ```
    """
    width, height = self.resolution_wh
    scale_x = scale_y = 1.0
    if resolution_wh is not None:
        target_width, target_height = _check_resolution(resolution_wh)
        scale_x, scale_y = width / target_width, height / target_height
    column, row = x * scale_x, y * scale_y
    if not (math.isfinite(column) and math.isfinite(row)):
        return None
    column_index, row_index = math.floor(column), math.floor(row)
    if not (0 <= column_index < width and 0 <= row_index < height):
        return None
    # Only this pixel is checked; `valid_mask` would test the whole frame.
    value = self.values[row_index, column_index]
    if not _holds_depth(value, self.kind):
        return None
    return float(value)

supervision.depth.core.DepthCamera dataclass

Pinhole stereo camera parameters that relate disparity to metric depth.

All pixel values are in pixels of the depth map they belong to, so resizing a :class:~supervision.depth.core.DepthMap updates them.

Attributes:

Name Type Description
fx_px float

Focal length in pixels.

baseline_m float

Stereo baseline in metres.

doffs_px float

Difference between the two views' principal points in pixels (Middlebury's doffs), so that depth is fx_px * baseline_m / (disparity + doffs_px).

Examples:

>>> import supervision as sv
>>> camera = sv.DepthCamera(fx_px=721.5, baseline_m=0.54)
>>> round(camera.fx_px * camera.baseline_m / 38.96, 2)
10.0
Source code in src/supervision/depth/core.py
@dataclass(frozen=True)
class DepthCamera:
    """Pinhole stereo camera parameters that relate disparity to metric depth.

    All pixel values are in pixels of the depth map they belong to, so resizing a
    :class:`~supervision.depth.core.DepthMap` updates them.

    Attributes:
        fx_px: Focal length in pixels.
        baseline_m: Stereo baseline in metres.
        doffs_px: Difference between the two views' principal points in pixels
            (Middlebury's `doffs`), so that depth is
            `fx_px * baseline_m / (disparity + doffs_px)`.

    Examples:
        ```pycon
        >>> import supervision as sv
        >>> camera = sv.DepthCamera(fx_px=721.5, baseline_m=0.54)
        >>> round(camera.fx_px * camera.baseline_m / 38.96, 2)
        10.0

        ```
    """

    fx_px: float
    baseline_m: float
    doffs_px: float = 0.0

    def __post_init__(self) -> None:
        """Store plain floats and reject parameters that cannot convert disparity."""
        for name in ("fx_px", "baseline_m", "doffs_px"):
            value = getattr(self, name)
            object.__setattr__(self, name, _plain_float(value, f"DepthCamera {name}"))
        for name in ("fx_px", "baseline_m"):
            value = getattr(self, name)
            if not (math.isfinite(value) and value > 0):
                raise ValueError(f"DepthCamera {name} must be a positive number.")
        if not math.isfinite(self.doffs_px):
            raise ValueError("DepthCamera doffs_px must be a finite number.")

    def _scaled(self, scale_x: float) -> DepthCamera:
        """Return the camera for the map resized to `scale_x` times its width."""
        return replace(
            self, fx_px=self.fx_px * scale_x, doffs_px=self.doffs_px * scale_x
        )

Methods:

__post_init__() -> None

Store plain floats and reject parameters that cannot convert disparity.

Source code in src/supervision/depth/core.py
def __post_init__(self) -> None:
    """Store plain floats and reject parameters that cannot convert disparity."""
    for name in ("fx_px", "baseline_m", "doffs_px"):
        value = getattr(self, name)
        object.__setattr__(self, name, _plain_float(value, f"DepthCamera {name}"))
    for name in ("fx_px", "baseline_m"):
        value = getattr(self, name)
        if not (math.isfinite(value) and value > 0):
            raise ValueError(f"DepthCamera {name} must be a positive number.")
    if not math.isfinite(self.doffs_px):
        raise ValueError("DepthCamera doffs_px must be a finite number.")

supervision.depth.core.DepthKind

Bases: Enum

What the values of :class:~supervision.depth.core.DepthMap measure.

Attributes:

Name Type Description
DISPARITY_PX

Stereo disparity in pixels of the map. Larger is nearer. Metric depth is fx_px * baseline_m / (disparity + doffs_px).

DEPTH_M

Metric depth along the optical axis, in metres. Smaller is nearer.

RELATIVE_INVERSE

Unitless relative depth from a monocular model, with no metric scale, where larger is nearer and 0 is the farthest valid value. Only the order of values is meaningful: maps from different models share no scale or geometry. Depth Anything V1, V2 and DPT output inverse depth up to an unknown scale and shift, which fits as it is; Roboflow Inference's maps run from 0 for the farthest pixel to 1 for the nearest. Invert a relative map that grows with distance, such as raw Depth Anything V3 output, which is linear in depth: pass 1 / values, not -values, whose pixels would all be negative and so without depth. Maps from :meth:~supervision.depth.core.DepthMap.from_inference need no inverting. Set pixels without depth to NaN first, because 0 is a valid value of this kind.

Source code in src/supervision/depth/core.py
class DepthKind(Enum):
    """What the values of :class:`~supervision.depth.core.DepthMap` measure.

    Attributes:
        DISPARITY_PX: Stereo disparity in pixels of the map. Larger is nearer.
            Metric depth is `fx_px * baseline_m / (disparity + doffs_px)`.
        DEPTH_M: Metric depth along the optical axis, in metres. Smaller is nearer.
        RELATIVE_INVERSE: Unitless relative depth from a monocular model, with no
            metric scale, where larger is nearer and 0 is the farthest valid value.
            Only the order of values is meaningful: maps from different models share
            no scale or geometry.
            Depth Anything V1, V2 and DPT output inverse depth up to an unknown scale
            and shift, which fits as it is; Roboflow Inference's maps run from 0 for
            the farthest pixel to 1 for the nearest. Invert a relative map that
            grows with distance, such as raw Depth Anything V3 output, which is
            linear in depth: pass `1 / values`, not `-values`, whose pixels would
            all be negative and so without depth. Maps from
            :meth:`~supervision.depth.core.DepthMap.from_inference` need
            no inverting. Set pixels without depth to `NaN` first, because 0 is a
            valid value of this kind.
    """

    DISPARITY_PX = "disparity_px"
    DEPTH_M = "depth_m"
    RELATIVE_INVERSE = "relative_inverse"

    @classmethod
    def list(cls) -> list[str]:
        """Return the string value of every kind."""
        return [member.value for member in cls]

    @classmethod
    def from_value(cls, value: DepthKind | str) -> DepthKind:
        """Resolve a kind from an enum member or its case-insensitive value.

        Args:
            value: A :class:`~supervision.depth.core.DepthKind` member or one of its
                string values.

        Returns:
            The matching :class:`~supervision.depth.core.DepthKind`.

        Raises:
            ValueError: If `value` names no kind.

        Examples:
            ```pycon
            >>> import supervision as sv
            >>> sv.DepthKind.from_value("depth_m")
            <DepthKind.DEPTH_M: 'depth_m'>

            ```
        """
        if isinstance(value, cls):
            return value
        if isinstance(value, str):
            try:
                return cls(value.lower())
            except ValueError:
                pass
        raise ValueError(f"Invalid depth kind: {value!r}. Must be one of {cls.list()}.")

Methods:

from_value(value: DepthKind | str) -> DepthKind classmethod

Resolve a kind from an enum member or its case-insensitive value.

Parameters:

Name Type Description Default
value
DepthKind | str

A :class:~supervision.depth.core.DepthKind member or one of its string values.

required

Returns:

Type Description
DepthKind

The matching :class:~supervision.depth.core.DepthKind.

Raises:

Type Description
ValueError

If value names no kind.

Examples:

>>> import supervision as sv
>>> sv.DepthKind.from_value("depth_m")
<DepthKind.DEPTH_M: 'depth_m'>
Source code in src/supervision/depth/core.py
@classmethod
def from_value(cls, value: DepthKind | str) -> DepthKind:
    """Resolve a kind from an enum member or its case-insensitive value.

    Args:
        value: A :class:`~supervision.depth.core.DepthKind` member or one of its
            string values.

    Returns:
        The matching :class:`~supervision.depth.core.DepthKind`.

    Raises:
        ValueError: If `value` names no kind.

    Examples:
        ```pycon
        >>> import supervision as sv
        >>> sv.DepthKind.from_value("depth_m")
        <DepthKind.DEPTH_M: 'depth_m'>

        ```
    """
    if isinstance(value, cls):
        return value
    if isinstance(value, str):
        try:
            return cls(value.lower())
        except ValueError:
            pass
    raise ValueError(f"Invalid depth kind: {value!r}. Must be one of {cls.list()}.")

list() -> list[str] classmethod

Return the string value of every kind.

Source code in src/supervision/depth/core.py
@classmethod
def list(cls) -> list[str]:
    """Return the string value of every kind."""
    return [member.value for member in cls]

supervision.depth.core.DepthResizeMethod

Bases: Enum

How :meth:~supervision.depth.core.DepthMap.resize picks the value of each target pixel.

Both methods only pick existing values and never blend them.

Attributes:

Name Type Description
NEAREST

The pixel under each target pixel's centre.

FOREGROUND

In each group of source pixels a target pixel covers, the valid value nearest the camera, so thin near objects survive shrinking.

Source code in src/supervision/depth/core.py
class DepthResizeMethod(Enum):
    """How :meth:`~supervision.depth.core.DepthMap.resize` picks the value of each
    target pixel.

    Both methods only pick existing values and never blend them.

    Attributes:
        NEAREST: The pixel under each target pixel's centre.
        FOREGROUND: In each group of source pixels a target pixel covers, the valid
            value nearest the camera, so thin near objects survive shrinking.
    """

    NEAREST = "nearest"
    FOREGROUND = "foreground"

    @classmethod
    def list(cls) -> list[str]:
        """Return the string value of every resize method."""
        return [member.value for member in cls]

    @classmethod
    def from_value(cls, value: DepthResizeMethod | str) -> DepthResizeMethod:
        """Resolve a resize method from an enum member or its case-insensitive value.

        Args:
            value: A :class:`~supervision.depth.core.DepthResizeMethod` member or
                one of its string values.

        Returns:
            The matching :class:`~supervision.depth.core.DepthResizeMethod`.

        Raises:
            ValueError: If `value` names no resize method.
        """
        if isinstance(value, cls):
            return value
        if isinstance(value, str):
            try:
                return cls(value.lower())
            except ValueError:
                pass
        raise ValueError(
            f"Unknown resize method: {value!r}. Must be one of {cls.list()}."
        )

Methods:

from_value(value: DepthResizeMethod | str) -> DepthResizeMethod classmethod

Resolve a resize method from an enum member or its case-insensitive value.

Parameters:

Name Type Description Default
value
DepthResizeMethod | str

A :class:~supervision.depth.core.DepthResizeMethod member or one of its string values.

required

Returns:

Type Description
DepthResizeMethod

The matching :class:~supervision.depth.core.DepthResizeMethod.

Raises:

Type Description
ValueError

If value names no resize method.

Source code in src/supervision/depth/core.py
@classmethod
def from_value(cls, value: DepthResizeMethod | str) -> DepthResizeMethod:
    """Resolve a resize method from an enum member or its case-insensitive value.

    Args:
        value: A :class:`~supervision.depth.core.DepthResizeMethod` member or
            one of its string values.

    Returns:
        The matching :class:`~supervision.depth.core.DepthResizeMethod`.

    Raises:
        ValueError: If `value` names no resize method.
    """
    if isinstance(value, cls):
        return value
    if isinstance(value, str):
        try:
            return cls(value.lower())
        except ValueError:
            pass
    raise ValueError(
        f"Unknown resize method: {value!r}. Must be one of {cls.list()}."
    )

list() -> list[str] classmethod

Return the string value of every resize method.

Source code in src/supervision/depth/core.py
@classmethod
def list(cls) -> list[str]:
    """Return the string value of every resize method."""
    return [member.value for member in cls]

Comments