0
# Detection Tools
1
2
Spatial analysis tools for counting, tracking, and analyzing objects within defined regions. These tools enable zone-based analytics like counting objects crossing lines or entering specific areas.
3
4
## Capabilities
5
6
### Zone-Based Detection
7
8
Tools for defining spatial regions and detecting object interactions with those zones.
9
10
```python { .api }
11
class LineZone:
12
"""
13
Count objects crossing a predefined line.
14
15
Attributes:
16
in_count (int): Objects crossed from outside to inside
17
out_count (int): Objects crossed from inside to outside
18
in_count_per_class (dict[int, int]): Per-class inside crossings
19
out_count_per_class (dict[int, int]): Per-class outside crossings
20
21
Args:
22
start (Point): Line starting point
23
end (Point): Line ending point
24
triggering_anchors (Iterable[Position]): Detection anchors to consider
25
minimum_crossing_threshold (int): Frames required to confirm crossing
26
"""
27
def __init__(
28
self,
29
start: Point,
30
end: Point,
31
triggering_anchors: Iterable[Position] = (
32
Position.TOP_LEFT,
33
Position.TOP_RIGHT,
34
Position.BOTTOM_LEFT,
35
Position.BOTTOM_RIGHT,
36
),
37
minimum_crossing_threshold: int = 1,
38
): ...
39
40
def trigger(self, detections: Detections) -> tuple[np.ndarray, np.ndarray]:
41
"""
42
Update line zone with new detections.
43
44
Args:
45
detections (Detections): Current frame detections with tracker_id
46
47
Returns:
48
tuple[np.ndarray, np.ndarray]: (crossed_in, crossed_out) boolean arrays
49
"""
50
51
class PolygonZone:
52
"""
53
Define polygon-shaped zones for object detection and counting.
54
55
Attributes:
56
polygon (np.ndarray): Zone polygon coordinates, shape (N, 2)
57
triggering_anchors (Iterable[Position]): Detection anchors to consider
58
current_count (int): Current objects within zone
59
mask (np.ndarray): 2D boolean mask for the zone
60
61
Args:
62
polygon (np.ndarray): Polygon vertices as (x, y) coordinates
63
triggering_anchors (Iterable[Position]): Detection anchor points
64
"""
65
def __init__(
66
self,
67
polygon: np.ndarray,
68
triggering_anchors: Iterable[Position] = (Position.BOTTOM_CENTER,),
69
): ...
70
71
def trigger(self, detections: Detections) -> np.ndarray:
72
"""
73
Check which detections are within the polygon zone.
74
75
Args:
76
detections (Detections): Detections to check
77
78
Returns:
79
np.ndarray: Boolean array indicating detections within zone
80
"""
81
```
82
83
### Zone Visualization
84
85
Annotators for visualizing zones and their status.
86
87
```python { .api }
88
class LineZoneAnnotator:
89
"""
90
Visualize LineZone with crossing counts.
91
92
Args:
93
thickness (int): Line thickness in pixels
94
color (Color): Line color
95
text_thickness (int): Text thickness
96
text_color (Color): Text color
97
text_scale (float): Text size scaling
98
text_offset (float): Text position offset from line
99
text_padding (int): Text background padding
100
custom_in_text (str | None): Custom text for in count
101
custom_out_text (str | None): Custom text for out count
102
display_in_count (bool): Whether to show in count
103
display_out_count (bool): Whether to show out count
104
"""
105
def __init__(
106
self,
107
thickness: int = 2,
108
color: Color = Color.WHITE,
109
text_thickness: int = 2,
110
text_color: Color = Color.BLACK,
111
text_scale: float = 0.5,
112
text_offset: float = 1.5,
113
text_padding: int = 10,
114
custom_in_text: str | None = None,
115
custom_out_text: str | None = None,
116
display_in_count: bool = True,
117
display_out_count: bool = True,
118
): ...
119
120
def annotate(self, frame: np.ndarray, line_counter: LineZone) -> np.ndarray:
121
"""Draw line zone with counts on frame."""
122
123
class LineZoneAnnotatorMulticlass:
124
"""Multi-class version of LineZoneAnnotator with per-class counting."""
125
126
class PolygonZoneAnnotator:
127
"""
128
Visualize PolygonZone with object counts.
129
130
Args:
131
color (Color): Zone boundary color
132
thickness (int): Boundary line thickness
133
text_color (Color): Count text color
134
text_scale (float): Text size scaling
135
text_thickness (int): Text thickness
136
text_padding (int): Text background padding
137
display_in_zone (bool): Whether to show objects in zone count
138
"""
139
def __init__(
140
self,
141
color: Color = Color.RED,
142
thickness: int = 2,
143
text_color: Color = Color.WHITE,
144
text_scale: float = 0.5,
145
text_thickness: int = 1,
146
text_padding: int = 10,
147
display_in_zone: bool = True,
148
): ...
149
150
def annotate(self, scene: np.ndarray, zone: PolygonZone, label: str | None = None) -> np.ndarray:
151
"""Draw polygon zone with count on scene."""
152
```
153
154
### Processing and Analysis Tools
155
156
Tools for advanced detection processing and analysis.
157
158
```python { .api }
159
class InferenceSlicer:
160
"""
161
Slice large images into smaller tiles for inference, then reconstruct results.
162
163
Useful for processing high-resolution images that exceed model input limitations.
164
165
Args:
166
slice_wh (tuple[int, int]): Slice dimensions (width, height)
167
overlap_ratio_wh (tuple[float, float]): Overlap ratios (width, height)
168
iou_threshold (float): IoU threshold for NMS across slices
169
callback (callable): Inference callback function
170
thread_workers (int): Number of worker threads
171
"""
172
def __init__(
173
self,
174
slice_wh: tuple[int, int] = (320, 320),
175
overlap_ratio_wh: tuple[float, float] = (0.2, 0.2),
176
iou_threshold: float = 0.5,
177
callback: callable = None,
178
thread_workers: int = 1,
179
): ...
180
181
def __call__(self, image: np.ndarray) -> Detections:
182
"""Process image through slicing and return merged detections."""
183
184
class DetectionsSmoother:
185
"""
186
Smooth detection results over time to reduce jitter and noise.
187
188
Args:
189
length (int): Number of frames to smooth over
190
"""
191
def __init__(self, length: int): ...
192
193
def update_with_detections(self, detections: Detections) -> Detections:
194
"""
195
Update smoother with new detections and return smoothed results.
196
197
Args:
198
detections (Detections): Current frame detections
199
200
Returns:
201
Detections: Smoothed detections
202
"""
203
```
204
205
### Data Export Tools
206
207
Tools for exporting detection results to various formats.
208
209
```python { .api }
210
class CSVSink:
211
"""
212
Export detection results to CSV format.
213
214
Args:
215
file_name (str): Output CSV file path
216
overwrite (bool): Whether to overwrite existing file
217
"""
218
def __init__(self, file_name: str, overwrite: bool = True): ...
219
220
def append(self, detections: Detections, custom_data: dict = None) -> None:
221
"""Add detection results to CSV file."""
222
223
def __enter__(self) -> "CSVSink": ...
224
def __exit__(self, exc_type, exc_val, exc_tb) -> None: ...
225
226
class JSONSink:
227
"""
228
Export detection results to JSON format.
229
230
Args:
231
file_name (str): Output JSON file path
232
overwrite (bool): Whether to overwrite existing file
233
"""
234
def __init__(self, file_name: str, overwrite: bool = True): ...
235
236
def append(self, detections: Detections, custom_data: dict = None) -> None:
237
"""Add detection results to JSON file."""
238
239
def __enter__(self) -> "JSONSink": ...
240
def __exit__(self, exc_type, exc_val, exc_tb) -> None: ...
241
```
242
243
## Usage Examples
244
245
### Line Crossing Counter
246
247
```python
248
import supervision as sv
249
from ultralytics import YOLO
250
251
# Setup model and tracker
252
model = YOLO("yolov8n.pt")
253
tracker = sv.ByteTrack()
254
255
# Define line zone
256
start = sv.Point(x=0, y=400)
257
end = sv.Point(x=1280, y=400)
258
line_zone = sv.LineZone(start=start, end=end)
259
line_annotator = sv.LineZoneAnnotator()
260
261
# Process video frames
262
for frame in sv.get_video_frames_generator("video.mp4"):
263
# Run inference and tracking
264
results = model(frame)[0]
265
detections = sv.Detections.from_ultralytics(results)
266
detections = tracker.update_with_detections(detections)
267
268
# Update line zone
269
crossed_in, crossed_out = line_zone.trigger(detections)
270
271
# Annotate frame
272
annotated_frame = line_annotator.annotate(frame, line_zone)
273
274
print(f"In: {line_zone.in_count}, Out: {line_zone.out_count}")
275
```
276
277
### Polygon Zone Analysis
278
279
```python
280
import supervision as sv
281
import numpy as np
282
283
# Define polygon zone
284
polygon = np.array([
285
[100, 200],
286
[300, 200],
287
[400, 400],
288
[100, 400]
289
])
290
291
zone = sv.PolygonZone(polygon=polygon)
292
zone_annotator = sv.PolygonZoneAnnotator()
293
294
# Process detections
295
for frame in frames:
296
detections = get_detections(frame) # Your detection logic
297
298
# Check zone occupancy
299
in_zone = zone.trigger(detections)
300
301
# Annotate
302
annotated_frame = zone_annotator.annotate(frame, zone)
303
304
print(f"Objects in zone: {zone.current_count}")
305
```
306
307
### High-Resolution Image Processing
308
309
```python
310
import supervision as sv
311
312
def yolo_callback(image_slice: np.ndarray) -> sv.Detections:
313
"""Callback for processing image slices."""
314
results = model(image_slice)[0]
315
return sv.Detections.from_ultralytics(results)
316
317
# Setup slicer for large images
318
slicer = sv.InferenceSlicer(
319
slice_wh=(640, 640),
320
overlap_ratio_wh=(0.2, 0.2),
321
iou_threshold=0.5,
322
callback=yolo_callback
323
)
324
325
# Process large image
326
large_image = cv2.imread("large_image.jpg")
327
detections = slicer(large_image)
328
```
329
330
### Export Detection Results
331
332
```python
333
import supervision as sv
334
335
# Export to CSV
336
with sv.CSVSink("detections.csv") as csv_sink:
337
for frame_idx, detections in enumerate(detection_stream):
338
csv_sink.append(detections, custom_data={"frame": frame_idx})
339
340
# Export to JSON
341
with sv.JSONSink("detections.json") as json_sink:
342
for frame_idx, detections in enumerate(detection_stream):
343
json_sink.append(detections, custom_data={"frame": frame_idx})
344
```
345
346
## Types
347
348
```python { .api }
349
# Zone trigger results
350
ZoneTriggerResult = np.ndarray # Boolean array indicating detections in zone
351
LineCrossingResult = tuple[np.ndarray, np.ndarray] # (crossed_in, crossed_out)
352
353
# Callback function signature for InferenceSlicer
354
InferenceCallback = Callable[[np.ndarray], Detections]
355
```