# How to Implement Detection Validation and Filtering Workflows in Roboflow Supervision

> Master detection validation and filtering with Roboflow Supervision. Learn to use automatic validation and NumPy masks to filter detections by confidence, class, and custom criteria.

- Repository: [Roboflow/supervision](https://github.com/roboflow/supervision)
- Tags: how-to-guide
- Published: 2026-04-06

---

**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`](https://github.com/roboflow/supervision/blob/main/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 *N*
- `validate_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`](https://github.com/roboflow/supervision/blob/main/src/supervision/validators/__init__.py) before constructing the object:

```python
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`](https://github.com/roboflow/supervision/blob/main/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 threshold
- **`filter_segments_by_distance`**: Keeps mask segments whose centroids lie within a specified Euclidean distance from a reference point
- **`PolygonZone.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`](https://github.com/roboflow/supervision/blob/main/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:

```python
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:

```python
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:

```python
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.py`](https://github.com/roboflow/supervision/blob/main/src/supervision/detection/core.py) via `__post_init__`, which calls `validate_detections_fields` to enforce tensor shapes and types.
- **Manual validation** is available through `supervision.validators` for custom model integrations.
- **Filtering** uses NumPy boolean masks applied via `detections[mask]`, supporting efficient compound conditions.
- **Built-in helpers** like `PolygonZone.trigger` and 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`](https://github.com/roboflow/supervision/blob/main/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.