swarmsort.track_state module

SwarmSort Track State Management

This module contains the core data structures for managing track states in the SwarmSort tracking system. It includes both active track states and pending detections that are waiting to be confirmed as tracks.

Classes:

PendingDetection: Detection waiting to become a confirmed track FastTrackState: State representation of an active tracked object

class swarmsort.track_state.FastTrackState(id, class_id=None, position=<factory>, velocity=<factory>, predicted_position=<factory>, bbox=<factory>, kalman_state=<factory>, last_detection_pos=<factory>, last_detection_frame=0, observation_history=<factory>, observation_frames=<factory>, observation_history_array=<factory>, observation_frames_array=<factory>, kalman_type='simple', velocity_damping=0.95, embedding_frozen=False, last_safe_embedding=None, embedding_history=<factory>, embedding_method='average', embedding_score_history=<factory>, _cached_avg_embedding=None, _cache_valid=False, _cached_representative_embedding=None, _representative_cache_valid=False, avg_embedding=None, embedding_update_count=0, age=0, hits=0, misses=0, confirmed=False, detection_confidence=0.0, confidence_score=0.5, lost_frames=0, recent_match_history=<factory>)[source]

Bases: object

Enhanced track state with N-embedding history and kalman_type support.

add_embedding(embedding)[source]

Add new embedding to history with safe normalization.

When the track is frozen (embedding_frozen=True), this method returns immediately without modifying the embedding_history. This protects the appearance model during collisions or crowded areas.

Parameters:

embedding (ndarray) – The embedding vector to add (will be L2-normalized)

add_embedding_fast(embedding, pre_normalized=True)[source]

Fast embedding addition without expensive checks.

age: int = 0
avg_embedding: ndarray | None = None
bbox: ndarray
class_id: int | None = None
confidence_score: float = 0.5
confirmed: bool = False
detection_confidence: float = 0.0
embedding_frozen: bool = False
embedding_history: deque
embedding_method: Literal['average', 'best_match', 'weighted_average', 'last', 'median'] = 'average'
embedding_score_history: deque
embedding_update_count: int = 0
freeze_embeddings()[source]

Freeze embeddings when collision/crowded area detected.

When frozen, add_embedding() will return early without modifying the embedding_history. This protects the track’s appearance model from being corrupted by mixed-object detections during collisions.

The freeze/unfreeze is controlled by core.py’s _update_collision_states() which uses embedding_freeze_density with hysteresis to prevent oscillation.

Note: last_safe_embedding stores a reference embedding from before the collision. This can be useful for debugging or future ReID improvements.

get_observation_prediction(current_frame, max_history=5)[source]

Get observation-based prediction using recent detection history.

Return type:

ndarray

get_predicted_position(current_frame)[source]

Get predicted position based on kalman_type.

Return type:

ndarray

get_recent_miss_ratio()[source]

Get the ratio of misses in recent frames.

Return type:

float

Returns:

Float in [0, 1] where 0 = all hits, 1 = all misses. Returns 0 if no history yet.

get_representative_embedding()[source]

Get representative embedding based on configured method.

Return type:

Optional[ndarray]

hits: int = 0
id: int
kalman_state: ndarray
kalman_type: str = 'simple'
last_detection_frame: int = 0
last_detection_pos: ndarray
last_safe_embedding: ndarray | None = None
lost_frames: int = 0
misses: int = 0
observation_frames: deque
observation_frames_array: ndarray
observation_history: deque
observation_history_array: ndarray
position: ndarray
predict_only(current_frame=None)[source]

Prediction step for UNMATCHED tracks - updates position AND counters.

This is called for tracks that were NOT matched to a detection. For matched tracks, use update_with_detection() instead.

predict_position(current_frame=None)[source]

Update predicted_position using Kalman filter WITHOUT modifying counters.

This should be called for ALL tracks BEFORE assignment to ensure predicted_position is up-to-date for cost matrix computation.

predicted_position: ndarray
recent_match_history: deque
set_embedding_params(max_embeddings=5, method='average', score_history_length=5)[source]

Configure embedding storage parameters.

Parameters:
  • max_embeddings (int) – Maximum number of embeddings to keep in history

  • method (Literal['average', 'best_match', 'weighted_average', 'last', 'median']) – Method for computing representative embedding

  • score_history_length (int) – Number of recent match scores to keep

set_uncertainty_window(window_size)[source]

Set the window size for uncertainty tracking.

Parameters:

window_size (int) – Number of recent frames to track (default: 10)

unfreeze_embeddings()[source]

Unfreeze embeddings when collision area is cleared.

Since add_embedding() returns early when frozen, the embedding_history should still contain only pre-collision embeddings at this point. No restoration is needed - the history is already clean.

Note: We don’t clear last_safe_embedding here in case it’s useful for debugging or comparison purposes.

update_observation_history(position, frame)[source]

Update observation history for observation-based prediction.

update_with_detection(position, embedding=None, bbox=None, frame=0, det_conf=0.0, is_reid=False)[source]

Update track state with new detection.

velocity: ndarray
velocity_damping: float = 0.95
class swarmsort.track_state.PendingDetection(position, embedding=None, bbox=<factory>, class_id=None, confidence=1.0, first_seen_frame=0, last_seen_frame=0, consecutive_frames=1, total_detections=1, average_position=<factory>)[source]

Bases: object

Represents a detection waiting to become a track.

average_position: ndarray
bbox: ndarray
class_id: int | None = None
confidence: float = 1.0
consecutive_frames: int = 1
embedding: ndarray | None = None
first_seen_frame: int = 0
is_ready_for_promotion(min_consecutive, max_gap, current_frame)[source]

Check if pending detection should become a track.

Return type:

bool

last_seen_frame: int = 0
position: ndarray
total_detections: int = 1
update(position, embedding=None, bbox=None, confidence=1.0)[source]

Update pending detection with new observation.