or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotators.mdcoordinate-conversion.mdcore-data-structures.mddataset-management.mddetection-tools.mddrawing-colors.mdfile-utilities.mdindex.mdiou-nms.mdkeypoint-annotators.mdmetrics.mdtracking.mdvideo-processing.mdvlm-support.md

detection-tools.mddocs/

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

```