Skip to content

Botsort Strategy

app.infrastructure.tracking.botsort_strategy

View source code

Incremental BoT-SORT-style tracking with conservative appearance updates.

See Also

Motion uses the constant-velocity state [cx, cy, w, h, vx, vy, vw, vh], not aspect ratio. High-confidence boxes are associated by spatially gated minimum IoU/appearance cost, then by an unambiguous wide-radius Re-ID pass. Low-confidence boxes only recover existing tracks through motion. No camera-motion compensation or learned model is needed.

Layer: Infrastructure. Context: Implements concrete processing and I/O behind application-facing contracts.

BotSortStrategy

Track boxes incrementally, with optional real appearance descriptors.

ATTRIBUTE DESCRIPTION
uses_appearance

Whether the strategy consumes appearance vectors.

TYPE: bool

embeddings must align with the original frame_boxes order; None or zero vectors mean appearance is unavailable. Explicit embeddings take precedence over extraction from RGB frame pixels. Without either, the strategy operates on motion/IoU alone, never geometry-derived fake Re-ID.

Tracks start only from scores >= max(0.5, min_confidence). Appearance EMA (90% history by default) is initialized/updated only on isolated high-score detections whose IoU with every other input box is strictly below 0.25. Coasting ends at max_age or when linearly decayed confidence falls below min_confidence. Frame indices must be nonnegative and strictly increasing.

Re-ID requires cosine distance <= 0.25 and a >= 0.08 margin over competing tracks AND detections, within a radius scaled by box size, elapsed time, and track velocity. This recovery pass resets stale velocity after relocation.

Note

The persistent motion state is [cx, cy, w, h, vx, vy, vw, vh] and appearance prototypes are updated only from isolated high-confidence observations.

Example

strategy = BotSortStrategy(min_confidence=0.2)

Layer: Infrastructure. Context: Implements concrete processing or I/O behind application-facing contracts.

uses_appearance: bool = True class-attribute instance-attribute

__init__(min_iou: float = 0.3, min_confidence: float = 0.1, confidence_decay: float = 0.05, *, max_age: int = 30, ema_alpha: float = 0.9, appearance_extractor: ReIDExtractorProtocol | None = None) -> None

PARAMETER DESCRIPTION
min_iou

Minimum overlap required for local spatial association.

TYPE: float DEFAULT: 0.3

min_confidence

Minimum confidence retained while coasting and used as the lower threshold for low-confidence recovery.

TYPE: float DEFAULT: 0.1

confidence_decay

Confidence penalty per missed frame.

TYPE: float DEFAULT: 0.05

max_age

Maximum number of missed frames before a track expires.

TYPE: int DEFAULT: 30

ema_alpha

Weight of the previous appearance prototype.

TYPE: float DEFAULT: 0.9

appearance_extractor

Optional replacement for the built-in extractor.

TYPE: ReIDExtractorProtocol | None DEFAULT: None

RAISES DESCRIPTION
ValueError

If a threshold, decay, age, or EMA weight is invalid.

Note: The default appearance extractor is created lazily only when RGB frames are supplied without explicit embeddings.

Example

strategy = BotSortStrategy(ema_alpha=0.9)

track(source_data: ListOfBoxesByFrameIndexAsDict, total_frames: int = 0, *, frames: Mapping[int, np.ndarray] | Sequence[np.ndarray] | None = None, embeddings_by_frame: Mapping[int, Sequence[np.ndarray | None]] | None = None) -> ListOfBoxesByFrameIndexAsDict

Track a fresh batch by calling update_frame in chronological order.

PARAMETER DESCRIPTION
source_data

Sparse per-frame detections.

TYPE: ListOfBoxesByFrameIndexAsDict

total_frames

Number of frames; zero infers it from source_data.

TYPE: int DEFAULT: 0

frames

Optional RGB frames keyed by index or supplied as a sequence.

TYPE: Mapping[int, ndarray] | Sequence[ndarray] | None DEFAULT: None

embeddings_by_frame

Optional per-frame, box-aligned feature vectors.

TYPE: Mapping[int, Sequence[ndarray | None]] | None DEFAULT: None

RETURNS DESCRIPTION
ListOfBoxesByFrameIndexAsDict

Track boxes keyed by frame index.

RAISES DESCRIPTION
ValueError

If frame counts or source-data indices are invalid.

Note

Each batch resets IDs and incremental state. Positive total_frames includes trailing empty frames.

Example

tracked = strategy.track(detections, total_frames=120)

update_frame(frame_idx: int, frame_boxes: Sequence[BBoxViewModel], frame: np.ndarray | None = None, embeddings: Sequence[np.ndarray | None] | None = None) -> list[BBoxViewModel]

Advance to one frame and return observed and bounded coasted boxes.

PARAMETER DESCRIPTION
frame_idx

Nonnegative, strictly increasing frame index.

TYPE: int

frame_boxes

Detections in the original input order.

TYPE: Sequence[BBoxViewModel]

frame

Optional RGB frame for extractor fallback.

TYPE: ndarray | None DEFAULT: None

embeddings

Optional vectors aligned with frame_boxes.

TYPE: Sequence[ndarray | None] | None DEFAULT: None

RETURNS DESCRIPTION
list[BBoxViewModel]

Tracking and coasted boxes for this frame.

RAISES DESCRIPTION
ValueError

If indices, boxes, embeddings, or embedding sizes are invalid.

Note

Skipped frame indices age and predict tracks by the actual elapsed time. Low scores below min_confidence are ignored, but remain part of the same-frame appearance-isolation check.

Example

boxes = strategy.update_frame(0, detections, embeddings=features)