How to Implement Detection Validation and Filtering Workflows in Roboflow Supervision
You can implement detection validation and filtering workflows in Supervision by leveraging the automatic validation in the Detections dataclass constructor and applying NumPy boolean masks to filter detections by confidence, class, or custom criteria.
Every computer vision pipeline in the roboflow/supervision library centers on the Detections object. Before running tracking, annotation, or metrics calculations, you must ensure that bounding boxes, masks, and metadata conform to strict shape and type contracts. The library enforces these contracts through an automatic validation layer and enables flexible filtering through NumPy array indexing.
Detection Validation Architecture
The Detections class in src/supervision/detection/core.py implements a dataclass pattern that validates tensors immediately upon instantiation. This prevents malformed data from propagating to downstream modules.
Automatic Validation in __post_init__
When you create a Detections instance using sv.Detections(...) or any factory method such as from_ultralytics(), the __post_init__ method (lines 59‑68) automatically invokes validate_detections_fields from the validators module. This ensures that every detection tensor meets the expected dimensional requirements before the object becomes usable.
The validation checks include:
validate_xyxy: Enforces a 2‑D ndarray of shape (N, 4)validate_mask: Validates optional 3‑D boolean ndarrays of shape (N, H, W)validate_class_id,validate_confidence,validate_tracker_id: Verify optional 1‑D ndarrays of length Nvalidate_data: Ensures dictionary values are lists or ndarrays all sharing length N
If any field fails validation, the constructor raises a ValueError immediately, providing early feedback and preventing downstream bugs in tracker or annotator modules.
Manual Validation for Custom Tensors
For custom model outputs that bypass the standard factories, you can invoke validators directly from src/supervision/validators/__init__.py before constructing the object:
import numpy as np
import supervision as sv
from supervision.validators import validate_detections_fields
# Raw tensors from a custom detector
xyxy = np.array([[10, 20, 110, 120], [200, 30, 300, 130]])
confidence = np.array([0.92, 0.75])
class_id = np.array([1, 3])
# Explicit validation
validate_detections_fields(
xyxy=xyxy,
mask=None,
class_id=class_id,
confidence=confidence,
tracker_id=None,
data={}
)
# Safe instantiation
detections = sv.Detections(xyxy=xyxy, confidence=confidence, class_id=class_id)
Filtering Detections with Boolean Masks
Supervision treats the Detections object as a thin wrapper around NumPy arrays. The class overloads __getitem__ to accept boolean masks, enabling you to filter detections using standard NumPy logic without copying underlying data.
Built-in Filtering Utilities
The library provides helper utilities in src/supervision/detection/utils/polygons.py and related modules to generate boolean masks for common scenarios:
filter_polygons_by_area: Removes mask-based detections with polygon areas below a thresholdfilter_segments_by_distance: Keeps mask segments whose centroids lie within a specified Euclidean distance from a reference pointPolygonZone.trigger: Generates a boolean mask for detections whose bounding box corners intersect a user-defined polygon zone
Additionally, internal metrics in src/supervision/metrics/recall.py expose _filter_detections_by_size (lines 431‑447), which splits detections into size categories using the same boolean mask pattern.
Compound Filtering Logic
Because Detections supports NumPy boolean indexing, you can combine multiple conditions using bitwise operators. This approach supports arbitrary compound filters across confidence thresholds, class IDs, and spatial zones:
import numpy as np
import supervision as sv
# Assume detections already validated
# Condition 1: Confidence greater than 0.8
conf_mask = detections.confidence > 0.8
# Condition 2: Class is 0 (person) or 2 (car)
class_mask = np.isin(detections.class_id, [0, 2])
# Condition 3: Inside a polygon zone
zone = sv.PolygonZone(
points=np.array([[0, 400], [0, 800], [800, 800], [800, 400]])
)
zone_mask = zone.trigger(detections=detections)
# Combine with bitwise AND
combined_mask = conf_mask & class_mask & zone_mask
filtered = detections[combined_mask]
print(f"Retained {len(filtered)} of {len(detections)} detections")
End-to-End Workflow Examples
Validating Third-Party Model Outputs
When integrating detectors not covered by built-in factories, always validate tensors before creating the Detections object. This pattern ensures your custom integration maintains compatibility with Supervision's tracking and annotation APIs.
Multi-Criteria Filtering by Class and Confidence
Filter detections to include only high-confidence objects from specific categories before passing them to a tracker:
import numpy as np
import supervision as sv
# Sample detections
detections = sv.Detections(
xyxy=np.array([[100, 100, 200, 200], [300, 300, 400, 400]]),
confidence=np.array([0.95, 0.45]),
class_id=np.array([0, 1])
)
# Filter for class 0 with confidence > 0.8
mask = (detections.class_id == 0) & (detections.confidence > 0.8)
high_conf_persons = detections[mask]
Area-Based Filtering Using Bounding Box Dimensions
Remove small bounding boxes that likely represent noise by calculating area directly from the xyxy tensor:
import supervision as sv
import numpy as np
detections = sv.Detections(
xyxy=np.array([[10, 10, 20, 20], [30, 30, 200, 200]]),
confidence=np.array([0.9, 0.85]),
class_id=np.array([0, 1])
)
# Calculate areas (width * height)
widths = detections.xyxy[:, 2] - detections.xyxy[:, 0]
heights = detections.xyxy[:, 3] - detections.xyxy[:, 1]
areas = widths * heights
# Keep detections larger than 5000 pixels squared
large_mask = areas > 5000
large_detections = detections[large_mask]
Summary
- Automatic validation occurs in
src/supervision/detection/core.pyvia__post_init__, which callsvalidate_detections_fieldsto enforce tensor shapes and types. - Manual validation is available through
supervision.validatorsfor custom model integrations. - Filtering uses NumPy boolean masks applied via
detections[mask], supporting efficient compound conditions. - Built-in helpers like
PolygonZone.triggerand metric utilities provide pre-built mask generators for common spatial and size-based filters. - Early validation prevents downstream errors in tracking, annotation, and metrics modules by catching dimensional mismatches at instantiation.
Frequently Asked Questions
How does Supervision validate detection tensors automatically?
According to the roboflow/supervision source code, the Detections dataclass in src/supervision/detection/core.py implements a __post_init__ method (lines 59‑68) that automatically invokes validate_detections_fields. This function checks that xyxy arrays have shape (N, 4), optional masks have shape (N, H, W), and that metadata fields like class_id and confidence are 1‑D arrays of length N. If validation fails, a ValueError raises immediately.
Can I manually validate tensors before creating a Detections object?
Yes. You can import validate_detections_fields from supervision.validators and call it directly on raw tensors before instantiation. This is useful when integrating custom detectors that output non-standard formats, allowing you to catch shape mismatches before the Detections constructor runs.
What is the most efficient way to filter detections by multiple conditions?
Use NumPy's bitwise operators to combine boolean masks. Because Detections overloads __getitem__, you can chain conditions like (detections.confidence > 0.8) & np.isin(detections.class_id, [0, 2]) to create compound filters. This approach avoids data copying and executes at native NumPy speed.
How do I filter detections that fall inside a specific polygon zone?
Create a sv.PolygonZone with your region coordinates, then call zone.trigger(detections=detections) to generate a boolean mask. Apply this mask to your Detections object with detections[zone_mask]. The PolygonZone implementation calculates which bounding box corners intersect the defined polygon, returning a mask suitable for filtering.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →