Skip to content

Tracker

BoxMOT tracking utilities and unified tracker interface.

This module provides the Tracker class for BoxMOT tracking and post-processing utilities for infilling, clustering, and filtering tracks.

MOTModels

Bases: StrEnum

Supported tracker backends exposed by BoxMOT.

Attributes:

Name Type Description
BOTSORT str

BoT-SORT tracker name used by BoxMOT. Good default when you want motion + appearance matching.

BOOSTTRACK str

BoostTrack tracker name used by BoxMOT. Usually improves association under difficult motion/crowding.

BYTE_TRACK str

ByteTrack tracker name used by BoxMOT. Faster and simpler; does not require ReID weights.

OCSORT str

OCSORT tracker name used by BoxMOT. Motion-centric tracker; useful when appearance features are unreliable.

STRONGSORT str

StrongSORT tracker name used by BoxMOT. Appearance-heavy tracker; typically more robust to long occlusions.

DEEPOCSORT str

DeepOCSORT tracker name used by BoxMOT. OCSORT variant enhanced with appearance features.

HYBRIDSORT str

HybridSORT tracker name used by BoxMOT. Hybrid strategy between motion and appearance matching.

SFSORT str

SFSort tracker name used by BoxMOT. Lightweight motion-centric tracking for real-time pipelines.

ReIDWeights

Bases: StrEnum

Built-in BoxMOT ReID weight file names.

Use these enum values for reid_weights in tracker parameter dataclasses.

MOTBaseConfig dataclass

MOTBaseConfig(
    *,
    model: MOTModels = MOTModels.BOTSORT,
    per_class: bool = False,
    extra_kwargs: dict[str, Any] = dict(),
    dnt_config_version: int = CONFIG_VERSION,
)

Common configuration fields for BoxMOT tracker creation.

Attributes:

Name Type Description
model MOTModels

BoxMOT tracker backend for this parameter bundle (default: MOTModels.BOTSORT).

per_class bool

Whether to run tracking independently per class (default: False). Options: True, False. Setting True reduces cross-class ID switches but can create more tracks.

extra_kwargs dict[str, Any]

Additional kwargs merged into tracker construction arguments (default: {}). Use this for BoxMOT arguments not explicitly represented in dataclasses.

dnt_config_version int

Format marker for mappings produced by dnt >= 0.3.3 (always 2).

__post_init__

__post_init__() -> None

Coerce model, check the format version, flag unpacked 0.3.2.x dicts.

Source code in src/dnt/track/tracker.py
200
201
202
203
204
205
206
207
208
209
210
def __post_init__(self) -> None:
    """Coerce `model`, check the format version, flag unpacked 0.3.2.x dicts."""
    if not isinstance(self.model, MOTModels):
        self.model = MOTModels(str(self.model))
    if self.dnt_config_version != CONFIG_VERSION:
        msg = (
            f"Unsupported dnt_config_version {self.dnt_config_version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    self._warn_if_unpacked_legacy()

tuning_values

tuning_values() -> dict[str, Any]

Return the tuning fields the user set (non-None), excluding non-tuning fields.

Source code in src/dnt/track/tracker.py
231
232
233
234
235
236
237
def tuning_values(self) -> dict[str, Any]:
    """Return the tuning fields the user set (non-None), excluding non-tuning fields."""
    return {
        f.name: getattr(self, f.name)
        for f in fields(self)
        if f.name not in self.NON_TUNING and getattr(self, f.name) is not None
    }

to_kwargs

to_kwargs() -> dict[str, Any]

Convert dataclass fields to keyword arguments (kept for compatibility).

Source code in src/dnt/track/tracker.py
239
240
241
242
243
244
245
def to_kwargs(self) -> dict[str, Any]:
    """Convert dataclass fields to keyword arguments (kept for compatibility)."""
    kwargs = asdict(self)
    for key in ("model", "extra_kwargs", "dnt_config_version"):
        kwargs.pop(key, None)
    kwargs.update(self.extra_kwargs)
    return kwargs

to_dict

to_dict() -> dict[str, Any]

Return a serializable mapping that starts with dnt_config_version.

Source code in src/dnt/track/tracker.py
247
248
249
250
def to_dict(self) -> dict[str, Any]:
    """Return a serializable mapping that starts with `dnt_config_version`."""
    data = self._yaml_safe(asdict(self))
    return {"dnt_config_version": data.pop("dnt_config_version"), **data}

from_dict classmethod

from_dict(
    data: dict[str, Any],
    legacy: bool | str = "auto",
    *,
    _source: str = "dict",
) -> MOTBaseConfig

Build a config from a mapping (spec §2.7).

Parameters:

Name Type Description Default
data dict

Mapping from to_dict() (any dnt version) or hand-written.

required
legacy (auto, True, False)

"auto" migrates a mapping only if it has no dnt_config_version and exactly the 0.3.2.4 field set; True requires that shape; False never migrates.

"auto"
Source code in src/dnt/track/tracker.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
@classmethod
def from_dict(
    cls, data: dict[str, Any], legacy: bool | str = "auto", *, _source: str = "dict"
) -> "MOTBaseConfig":
    """Build a config from a mapping (spec §2.7).

    Parameters
    ----------
    data : dict
        Mapping from `to_dict()` (any dnt version) or hand-written.
    legacy : {"auto", True, False}
        "auto" migrates a mapping only if it has no `dnt_config_version` and exactly the
        0.3.2.4 field set; True requires that shape; False never migrates.

    """
    if legacy not in ("auto", True, False):
        raise ValueError("legacy must be 'auto', True or False.")
    data = dict(data)
    version = data.pop("dnt_config_version", None)
    if version is not None and version != CONFIG_VERSION:
        msg = (
            f"{_source}: unsupported dnt_config_version {version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    shaped = version is None and bx.is_legacy_shape(data)
    if legacy is True and not shaped:
        msg = (
            f"{_source}: not a dnt 0.3.2.x config (legacy=True needs the exact 0.3.2.4 field "
            "set and no dnt_config_version)."
        )
        raise ValueError(msg)
    if shaped and legacy is not False:
        data = bx.migrate_legacy(data, source=_source)
    valid = {f.name for f in fields(cls)}
    known = {k: v for k, v in data.items() if k in valid}
    unknown = {k: v for k, v in data.items() if k not in valid}
    with warnings.catch_warnings():
        if legacy is False:
            warnings.filterwarnings("ignore", message=".*unpacked 0.3.2.x dict.*")
        params = cls(**known)
    if unknown:
        params.extra_kwargs.update(unknown)
    return params

from_legacy_dict classmethod

from_legacy_dict(data: dict[str, Any]) -> MOTBaseConfig

Explicitly migrate a dnt 0.3.2.x mapping (alias of from_dict(data, legacy=True)).

Source code in src/dnt/track/tracker.py
310
311
312
313
@classmethod
def from_legacy_dict(cls, data: dict[str, Any]) -> "MOTBaseConfig":
    """Explicitly migrate a dnt 0.3.2.x mapping (alias of ``from_dict(data, legacy=True)``)."""
    return cls.from_dict(data, legacy=True)

export_yaml

export_yaml(yaml_file: str) -> None

Export parameters to a YAML file.

Source code in src/dnt/track/tracker.py
315
316
317
318
319
320
def export_yaml(self, yaml_file: str) -> None:
    """Export parameters to a YAML file."""
    out_path = Path(yaml_file)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(self.to_dict(), f, sort_keys=False)

import_yaml classmethod

import_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> MOTBaseConfig

Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7).

Source code in src/dnt/track/tracker.py
322
323
324
325
326
327
328
329
330
@classmethod
def import_yaml(cls, yaml_file: str, legacy: bool | str = "auto") -> "MOTBaseConfig":
    """Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7)."""
    with Path(yaml_file).open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        msg = f"Invalid YAML content in {yaml_file}: expected a mapping."
        raise ValueError(msg)
    return cls.from_dict(data, legacy=legacy, _source=str(yaml_file))

BoTSORTConfig dataclass

BoTSORTConfig(
    *,
    model: MOTModels = MOTModels.BOTSORT,
    per_class: bool = False,
    extra_kwargs: dict[str, Any] = dict(),
    dnt_config_version: int = CONFIG_VERSION,
    reid_weights: ReIDWeights
    | str
    | None = ReIDWeights.OSNET_X1_0_MSMT17,
    track_high_thresh: float | None = None,
    track_low_thresh: float | None = None,
    new_track_thresh: float | None = None,
    match_thresh: float | None = None,
    track_buffer: int | None = None,
    with_reid: bool | None = None,
    proximity_thresh: float | None = None,
    appearance_thresh: float | None = None,
    cmc_method: str | None = None,
    frame_rate: int | None = None,
)

Bases: MOTBaseConfig

BoTSORT-specific parameters.

Attributes:

Name Type Description
reid_weights ReIDWeights | str | None

Optional ReID weights path (default: "osnet_x1_0_msmt17.pt"). Options: None, file name (auto-resolved), or absolute path. Built-in downloadable options: 'resnet50_market1501.pt', 'resnet50_dukemtmcreid.pt', 'resnet50_msmt17.pt', 'resnet50_fc512_market1501.pt', 'resnet50_fc512_dukemtmcreid.pt', 'resnet50_fc512_msmt17.pt', 'mlfn_market1501.pt', 'mlfn_dukemtmcreid.pt', 'mlfn_msmt17.pt', 'hacnn_market1501.pt', 'hacnn_dukemtmcreid.pt', 'hacnn_msmt17.pt', 'mobilenetv2_x1_0_market1501.pt', 'mobilenetv2_x1_0_dukemtmcreid.pt', 'mobilenetv2_x1_0_msmt17.pt', 'mobilenetv2_x1_4_market1501.pt', 'mobilenetv2_x1_4_dukemtmcreid.pt', 'mobilenetv2_x1_4_msmt17.pt', 'osnet_x1_0_market1501.pt', 'osnet_x1_0_dukemtmcreid.pt', 'osnet_x1_0_msmt17.pt', 'osnet_x0_75_market1501.pt', 'osnet_x0_75_dukemtmcreid.pt', 'osnet_x0_75_msmt17.pt', 'osnet_x0_5_market1501.pt', 'osnet_x0_5_dukemtmcreid.pt', 'osnet_x0_5_msmt17.pt', 'osnet_x0_25_market1501.pt', 'osnet_x0_25_dukemtmcreid.pt', 'osnet_x0_25_msmt17.pt', 'osnet_ibn_x1_0_msmt17.pt', 'osnet_ain_x1_0_msmt17.pt', 'lmbn_n_duke.pt', 'lmbn_n_market.pt', 'lmbn_n_cuhk03_d.pt', 'clip_market1501.pt', 'clip_duke.pt', 'clip_veri.pt', 'clip_vehicleid.pt'. Suggestions: use "osnet_x1_0_msmt17.pt" for pedestrians or "clip_vehicleid.pt" / "clip_veri.pt" for vehicles.

track_high_thresh float | None

High score threshold for first association (default: None (BoxMOT 16: 0.6)). Increasing this is stricter and may reduce false matches but miss tracks.

track_low_thresh float | None

Lower score threshold for second association (default: None (BoxMOT 16: 0.1)). Increasing this keeps fewer low-confidence detections.

new_track_thresh float | None

Threshold to initialize new tracks (default: None (BoxMOT 16: 0.7)). Increasing this creates fewer new tracks and can reduce false positives.

match_thresh float | None

Matching threshold for association (default: None (BoxMOT 16: 0.8)). Increasing this makes association more permissive.

track_buffer int | None

Number of frames to keep lost tracks (default: None (BoxMOT 16: 30)). Increasing this preserves IDs longer through occlusion, but may cause stale tracks to survive longer.

with_reid bool | None

Whether to enable ReID-assisted association (default: None (BoxMOT 16 constructor default)). Options: True, False. Disabling this speeds up tracking but may increase ID switches.

proximity_thresh float | None

Proximity threshold for ReID matching (default: None (BoxMOT 16: 0.5)). Increasing this requires stronger geometric overlap before ReID is used.

appearance_thresh float | None

Appearance similarity threshold for ReID matching (default: None (BoxMOT 16: 0.25)). Increasing this requires closer appearance match and is more conservative.

cmc_method str | None

Camera motion compensation method (default: None (BoxMOT 16: "ecc")). Typical options: "ecc", "orb", "sift", "sparseOptFlow", "none".

frame_rate int | None

Source video frame rate used by the tracker (default: None (BoxMOT 16 constructor default)). Set this close to real FPS for best temporal behavior.

__post_init__

__post_init__() -> None

Coerce model, check the format version, flag unpacked 0.3.2.x dicts.

Source code in src/dnt/track/tracker.py
200
201
202
203
204
205
206
207
208
209
210
def __post_init__(self) -> None:
    """Coerce `model`, check the format version, flag unpacked 0.3.2.x dicts."""
    if not isinstance(self.model, MOTModels):
        self.model = MOTModels(str(self.model))
    if self.dnt_config_version != CONFIG_VERSION:
        msg = (
            f"Unsupported dnt_config_version {self.dnt_config_version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    self._warn_if_unpacked_legacy()

tuning_values

tuning_values() -> dict[str, Any]

Return the tuning fields the user set (non-None), excluding non-tuning fields.

Source code in src/dnt/track/tracker.py
231
232
233
234
235
236
237
def tuning_values(self) -> dict[str, Any]:
    """Return the tuning fields the user set (non-None), excluding non-tuning fields."""
    return {
        f.name: getattr(self, f.name)
        for f in fields(self)
        if f.name not in self.NON_TUNING and getattr(self, f.name) is not None
    }

to_kwargs

to_kwargs() -> dict[str, Any]

Convert dataclass fields to keyword arguments (kept for compatibility).

Source code in src/dnt/track/tracker.py
239
240
241
242
243
244
245
def to_kwargs(self) -> dict[str, Any]:
    """Convert dataclass fields to keyword arguments (kept for compatibility)."""
    kwargs = asdict(self)
    for key in ("model", "extra_kwargs", "dnt_config_version"):
        kwargs.pop(key, None)
    kwargs.update(self.extra_kwargs)
    return kwargs

to_dict

to_dict() -> dict[str, Any]

Return a serializable mapping that starts with dnt_config_version.

Source code in src/dnt/track/tracker.py
247
248
249
250
def to_dict(self) -> dict[str, Any]:
    """Return a serializable mapping that starts with `dnt_config_version`."""
    data = self._yaml_safe(asdict(self))
    return {"dnt_config_version": data.pop("dnt_config_version"), **data}

from_dict classmethod

from_dict(
    data: dict[str, Any],
    legacy: bool | str = "auto",
    *,
    _source: str = "dict",
) -> MOTBaseConfig

Build a config from a mapping (spec §2.7).

Parameters:

Name Type Description Default
data dict

Mapping from to_dict() (any dnt version) or hand-written.

required
legacy (auto, True, False)

"auto" migrates a mapping only if it has no dnt_config_version and exactly the 0.3.2.4 field set; True requires that shape; False never migrates.

"auto"
Source code in src/dnt/track/tracker.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
@classmethod
def from_dict(
    cls, data: dict[str, Any], legacy: bool | str = "auto", *, _source: str = "dict"
) -> "MOTBaseConfig":
    """Build a config from a mapping (spec §2.7).

    Parameters
    ----------
    data : dict
        Mapping from `to_dict()` (any dnt version) or hand-written.
    legacy : {"auto", True, False}
        "auto" migrates a mapping only if it has no `dnt_config_version` and exactly the
        0.3.2.4 field set; True requires that shape; False never migrates.

    """
    if legacy not in ("auto", True, False):
        raise ValueError("legacy must be 'auto', True or False.")
    data = dict(data)
    version = data.pop("dnt_config_version", None)
    if version is not None and version != CONFIG_VERSION:
        msg = (
            f"{_source}: unsupported dnt_config_version {version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    shaped = version is None and bx.is_legacy_shape(data)
    if legacy is True and not shaped:
        msg = (
            f"{_source}: not a dnt 0.3.2.x config (legacy=True needs the exact 0.3.2.4 field "
            "set and no dnt_config_version)."
        )
        raise ValueError(msg)
    if shaped and legacy is not False:
        data = bx.migrate_legacy(data, source=_source)
    valid = {f.name for f in fields(cls)}
    known = {k: v for k, v in data.items() if k in valid}
    unknown = {k: v for k, v in data.items() if k not in valid}
    with warnings.catch_warnings():
        if legacy is False:
            warnings.filterwarnings("ignore", message=".*unpacked 0.3.2.x dict.*")
        params = cls(**known)
    if unknown:
        params.extra_kwargs.update(unknown)
    return params

from_legacy_dict classmethod

from_legacy_dict(data: dict[str, Any]) -> MOTBaseConfig

Explicitly migrate a dnt 0.3.2.x mapping (alias of from_dict(data, legacy=True)).

Source code in src/dnt/track/tracker.py
310
311
312
313
@classmethod
def from_legacy_dict(cls, data: dict[str, Any]) -> "MOTBaseConfig":
    """Explicitly migrate a dnt 0.3.2.x mapping (alias of ``from_dict(data, legacy=True)``)."""
    return cls.from_dict(data, legacy=True)

export_yaml

export_yaml(yaml_file: str) -> None

Export parameters to a YAML file.

Source code in src/dnt/track/tracker.py
315
316
317
318
319
320
def export_yaml(self, yaml_file: str) -> None:
    """Export parameters to a YAML file."""
    out_path = Path(yaml_file)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(self.to_dict(), f, sort_keys=False)

import_yaml classmethod

import_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> MOTBaseConfig

Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7).

Source code in src/dnt/track/tracker.py
322
323
324
325
326
327
328
329
330
@classmethod
def import_yaml(cls, yaml_file: str, legacy: bool | str = "auto") -> "MOTBaseConfig":
    """Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7)."""
    with Path(yaml_file).open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        msg = f"Invalid YAML content in {yaml_file}: expected a mapping."
        raise ValueError(msg)
    return cls.from_dict(data, legacy=legacy, _source=str(yaml_file))

BoostTrackConfig dataclass

BoostTrackConfig(
    *,
    model: MOTModels = MOTModels.BOOSTTRACK,
    per_class: bool = False,
    extra_kwargs: dict[str, Any] = dict(),
    dnt_config_version: int = CONFIG_VERSION,
    reid_weights: ReIDWeights
    | str
    | None = ReIDWeights.OSNET_X1_0_MSMT17,
    det_thresh: float | None = None,
    max_age: int | None = None,
    min_hits: int | None = None,
    iou_threshold: float | None = None,
    asso_func: str | None = None,
)

Bases: MOTBaseConfig

BoostTrack-specific parameters.

Attributes:

Name Type Description
reid_weights ReIDWeights | str | None

Optional ReID weights path (default: "osnet_x1_0_msmt17.pt"). Options: same built-in .pt names listed in BoTSORTParams.reid_weights.

det_thresh float | None

Detection confidence threshold (default: None (BoxMOT 16: 0.6)). Increasing this keeps only higher-confidence detections.

max_age int | None

Maximum age of unmatched tracks (default: None (BoxMOT 16: 60)). Increasing this keeps tracks alive longer when unmatched.

min_hits int | None

Minimum hits before track confirmation (default: None (BoxMOT 16: 3)). Increasing this delays confirmation and reduces short noisy tracks.

iou_threshold float | None

IoU threshold for association (default: None (BoxMOT 16: 0.3)). Increasing this demands tighter overlap to match detections.

asso_func str | None

Association function name. No effect in BoxMOT 16; raises ValueError if set.

__post_init__

__post_init__() -> None

Coerce model, check the format version, flag unpacked 0.3.2.x dicts.

Source code in src/dnt/track/tracker.py
200
201
202
203
204
205
206
207
208
209
210
def __post_init__(self) -> None:
    """Coerce `model`, check the format version, flag unpacked 0.3.2.x dicts."""
    if not isinstance(self.model, MOTModels):
        self.model = MOTModels(str(self.model))
    if self.dnt_config_version != CONFIG_VERSION:
        msg = (
            f"Unsupported dnt_config_version {self.dnt_config_version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    self._warn_if_unpacked_legacy()

tuning_values

tuning_values() -> dict[str, Any]

Return the tuning fields the user set (non-None), excluding non-tuning fields.

Source code in src/dnt/track/tracker.py
231
232
233
234
235
236
237
def tuning_values(self) -> dict[str, Any]:
    """Return the tuning fields the user set (non-None), excluding non-tuning fields."""
    return {
        f.name: getattr(self, f.name)
        for f in fields(self)
        if f.name not in self.NON_TUNING and getattr(self, f.name) is not None
    }

to_kwargs

to_kwargs() -> dict[str, Any]

Convert dataclass fields to keyword arguments (kept for compatibility).

Source code in src/dnt/track/tracker.py
239
240
241
242
243
244
245
def to_kwargs(self) -> dict[str, Any]:
    """Convert dataclass fields to keyword arguments (kept for compatibility)."""
    kwargs = asdict(self)
    for key in ("model", "extra_kwargs", "dnt_config_version"):
        kwargs.pop(key, None)
    kwargs.update(self.extra_kwargs)
    return kwargs

to_dict

to_dict() -> dict[str, Any]

Return a serializable mapping that starts with dnt_config_version.

Source code in src/dnt/track/tracker.py
247
248
249
250
def to_dict(self) -> dict[str, Any]:
    """Return a serializable mapping that starts with `dnt_config_version`."""
    data = self._yaml_safe(asdict(self))
    return {"dnt_config_version": data.pop("dnt_config_version"), **data}

from_dict classmethod

from_dict(
    data: dict[str, Any],
    legacy: bool | str = "auto",
    *,
    _source: str = "dict",
) -> MOTBaseConfig

Build a config from a mapping (spec §2.7).

Parameters:

Name Type Description Default
data dict

Mapping from to_dict() (any dnt version) or hand-written.

required
legacy (auto, True, False)

"auto" migrates a mapping only if it has no dnt_config_version and exactly the 0.3.2.4 field set; True requires that shape; False never migrates.

"auto"
Source code in src/dnt/track/tracker.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
@classmethod
def from_dict(
    cls, data: dict[str, Any], legacy: bool | str = "auto", *, _source: str = "dict"
) -> "MOTBaseConfig":
    """Build a config from a mapping (spec §2.7).

    Parameters
    ----------
    data : dict
        Mapping from `to_dict()` (any dnt version) or hand-written.
    legacy : {"auto", True, False}
        "auto" migrates a mapping only if it has no `dnt_config_version` and exactly the
        0.3.2.4 field set; True requires that shape; False never migrates.

    """
    if legacy not in ("auto", True, False):
        raise ValueError("legacy must be 'auto', True or False.")
    data = dict(data)
    version = data.pop("dnt_config_version", None)
    if version is not None and version != CONFIG_VERSION:
        msg = (
            f"{_source}: unsupported dnt_config_version {version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    shaped = version is None and bx.is_legacy_shape(data)
    if legacy is True and not shaped:
        msg = (
            f"{_source}: not a dnt 0.3.2.x config (legacy=True needs the exact 0.3.2.4 field "
            "set and no dnt_config_version)."
        )
        raise ValueError(msg)
    if shaped and legacy is not False:
        data = bx.migrate_legacy(data, source=_source)
    valid = {f.name for f in fields(cls)}
    known = {k: v for k, v in data.items() if k in valid}
    unknown = {k: v for k, v in data.items() if k not in valid}
    with warnings.catch_warnings():
        if legacy is False:
            warnings.filterwarnings("ignore", message=".*unpacked 0.3.2.x dict.*")
        params = cls(**known)
    if unknown:
        params.extra_kwargs.update(unknown)
    return params

from_legacy_dict classmethod

from_legacy_dict(data: dict[str, Any]) -> MOTBaseConfig

Explicitly migrate a dnt 0.3.2.x mapping (alias of from_dict(data, legacy=True)).

Source code in src/dnt/track/tracker.py
310
311
312
313
@classmethod
def from_legacy_dict(cls, data: dict[str, Any]) -> "MOTBaseConfig":
    """Explicitly migrate a dnt 0.3.2.x mapping (alias of ``from_dict(data, legacy=True)``)."""
    return cls.from_dict(data, legacy=True)

export_yaml

export_yaml(yaml_file: str) -> None

Export parameters to a YAML file.

Source code in src/dnt/track/tracker.py
315
316
317
318
319
320
def export_yaml(self, yaml_file: str) -> None:
    """Export parameters to a YAML file."""
    out_path = Path(yaml_file)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(self.to_dict(), f, sort_keys=False)

import_yaml classmethod

import_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> MOTBaseConfig

Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7).

Source code in src/dnt/track/tracker.py
322
323
324
325
326
327
328
329
330
@classmethod
def import_yaml(cls, yaml_file: str, legacy: bool | str = "auto") -> "MOTBaseConfig":
    """Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7)."""
    with Path(yaml_file).open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        msg = f"Invalid YAML content in {yaml_file}: expected a mapping."
        raise ValueError(msg)
    return cls.from_dict(data, legacy=legacy, _source=str(yaml_file))

ByteTrackConfig dataclass

ByteTrackConfig(
    *,
    model: MOTModels = MOTModels.BYTE_TRACK,
    per_class: bool = False,
    extra_kwargs: dict[str, Any] = dict(),
    dnt_config_version: int = CONFIG_VERSION,
    track_thresh: float | None = None,
    match_thresh: float | None = None,
    track_buffer: int | None = None,
    frame_rate: int | None = None,
    min_conf: float | None = None,
)

Bases: MOTBaseConfig

ByteTrack-specific parameters.

Attributes:

Name Type Description
track_thresh float | None

Detection confidence threshold (default: None (BoxMOT 16: 0.6)). Increasing this filters more weak detections.

match_thresh float | None

Threshold for matching detections to tracks (default: None (BoxMOT 16: 0.9)). Increasing this generally allows looser matching.

track_buffer int | None

Number of frames to keep lost tracks (default: None (BoxMOT 16: 30)). Increasing this keeps unmatched tracks longer.

frame_rate int | None

Source video frame rate used by the tracker (default: None (BoxMOT 16: 30)). Set this close to real FPS for best temporal behavior.

min_conf float | None

Minimum detection confidence passed through to the tracker (default: None (BoxMOT 16: 0.1)). Increasing this filters out lower-confidence detections before tracking.

__post_init__

__post_init__() -> None

Coerce model, check the format version, flag unpacked 0.3.2.x dicts.

Source code in src/dnt/track/tracker.py
200
201
202
203
204
205
206
207
208
209
210
def __post_init__(self) -> None:
    """Coerce `model`, check the format version, flag unpacked 0.3.2.x dicts."""
    if not isinstance(self.model, MOTModels):
        self.model = MOTModels(str(self.model))
    if self.dnt_config_version != CONFIG_VERSION:
        msg = (
            f"Unsupported dnt_config_version {self.dnt_config_version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    self._warn_if_unpacked_legacy()

tuning_values

tuning_values() -> dict[str, Any]

Return the tuning fields the user set (non-None), excluding non-tuning fields.

Source code in src/dnt/track/tracker.py
231
232
233
234
235
236
237
def tuning_values(self) -> dict[str, Any]:
    """Return the tuning fields the user set (non-None), excluding non-tuning fields."""
    return {
        f.name: getattr(self, f.name)
        for f in fields(self)
        if f.name not in self.NON_TUNING and getattr(self, f.name) is not None
    }

to_kwargs

to_kwargs() -> dict[str, Any]

Convert dataclass fields to keyword arguments (kept for compatibility).

Source code in src/dnt/track/tracker.py
239
240
241
242
243
244
245
def to_kwargs(self) -> dict[str, Any]:
    """Convert dataclass fields to keyword arguments (kept for compatibility)."""
    kwargs = asdict(self)
    for key in ("model", "extra_kwargs", "dnt_config_version"):
        kwargs.pop(key, None)
    kwargs.update(self.extra_kwargs)
    return kwargs

to_dict

to_dict() -> dict[str, Any]

Return a serializable mapping that starts with dnt_config_version.

Source code in src/dnt/track/tracker.py
247
248
249
250
def to_dict(self) -> dict[str, Any]:
    """Return a serializable mapping that starts with `dnt_config_version`."""
    data = self._yaml_safe(asdict(self))
    return {"dnt_config_version": data.pop("dnt_config_version"), **data}

from_dict classmethod

from_dict(
    data: dict[str, Any],
    legacy: bool | str = "auto",
    *,
    _source: str = "dict",
) -> MOTBaseConfig

Build a config from a mapping (spec §2.7).

Parameters:

Name Type Description Default
data dict

Mapping from to_dict() (any dnt version) or hand-written.

required
legacy (auto, True, False)

"auto" migrates a mapping only if it has no dnt_config_version and exactly the 0.3.2.4 field set; True requires that shape; False never migrates.

"auto"
Source code in src/dnt/track/tracker.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
@classmethod
def from_dict(
    cls, data: dict[str, Any], legacy: bool | str = "auto", *, _source: str = "dict"
) -> "MOTBaseConfig":
    """Build a config from a mapping (spec §2.7).

    Parameters
    ----------
    data : dict
        Mapping from `to_dict()` (any dnt version) or hand-written.
    legacy : {"auto", True, False}
        "auto" migrates a mapping only if it has no `dnt_config_version` and exactly the
        0.3.2.4 field set; True requires that shape; False never migrates.

    """
    if legacy not in ("auto", True, False):
        raise ValueError("legacy must be 'auto', True or False.")
    data = dict(data)
    version = data.pop("dnt_config_version", None)
    if version is not None and version != CONFIG_VERSION:
        msg = (
            f"{_source}: unsupported dnt_config_version {version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    shaped = version is None and bx.is_legacy_shape(data)
    if legacy is True and not shaped:
        msg = (
            f"{_source}: not a dnt 0.3.2.x config (legacy=True needs the exact 0.3.2.4 field "
            "set and no dnt_config_version)."
        )
        raise ValueError(msg)
    if shaped and legacy is not False:
        data = bx.migrate_legacy(data, source=_source)
    valid = {f.name for f in fields(cls)}
    known = {k: v for k, v in data.items() if k in valid}
    unknown = {k: v for k, v in data.items() if k not in valid}
    with warnings.catch_warnings():
        if legacy is False:
            warnings.filterwarnings("ignore", message=".*unpacked 0.3.2.x dict.*")
        params = cls(**known)
    if unknown:
        params.extra_kwargs.update(unknown)
    return params

from_legacy_dict classmethod

from_legacy_dict(data: dict[str, Any]) -> MOTBaseConfig

Explicitly migrate a dnt 0.3.2.x mapping (alias of from_dict(data, legacy=True)).

Source code in src/dnt/track/tracker.py
310
311
312
313
@classmethod
def from_legacy_dict(cls, data: dict[str, Any]) -> "MOTBaseConfig":
    """Explicitly migrate a dnt 0.3.2.x mapping (alias of ``from_dict(data, legacy=True)``)."""
    return cls.from_dict(data, legacy=True)

export_yaml

export_yaml(yaml_file: str) -> None

Export parameters to a YAML file.

Source code in src/dnt/track/tracker.py
315
316
317
318
319
320
def export_yaml(self, yaml_file: str) -> None:
    """Export parameters to a YAML file."""
    out_path = Path(yaml_file)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(self.to_dict(), f, sort_keys=False)

import_yaml classmethod

import_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> MOTBaseConfig

Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7).

Source code in src/dnt/track/tracker.py
322
323
324
325
326
327
328
329
330
@classmethod
def import_yaml(cls, yaml_file: str, legacy: bool | str = "auto") -> "MOTBaseConfig":
    """Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7)."""
    with Path(yaml_file).open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        msg = f"Invalid YAML content in {yaml_file}: expected a mapping."
        raise ValueError(msg)
    return cls.from_dict(data, legacy=legacy, _source=str(yaml_file))

OCSORTConfig dataclass

OCSORTConfig(
    *,
    model: MOTModels = MOTModels.OCSORT,
    per_class: bool = False,
    extra_kwargs: dict[str, Any] = dict(),
    dnt_config_version: int = CONFIG_VERSION,
    det_thresh: float | None = None,
    max_age: int | None = None,
    min_hits: int | None = None,
    iou_threshold: float | None = None,
    asso_func: str | None = None,
    delta_t: int | None = None,
    inertia: float | None = None,
)

Bases: MOTBaseConfig

OCSORT-specific parameters.

Attributes:

Name Type Description
det_thresh float | None

Detection confidence threshold (default: None (BoxMOT 16: 0.6)). Increasing this reduces low-confidence detections.

max_age int | None

Maximum age of unmatched tracks (default: None (BoxMOT 16: 30)). Increasing this keeps tracks alive through longer gaps.

min_hits int | None

Minimum hits before track confirmation (default: None (BoxMOT 16: 3)). Increasing this reduces short-lived false tracks.

iou_threshold float | None

IoU threshold for association (default: None (BoxMOT 16 constructor default)). Increasing this makes matching stricter.

asso_func str | None

Association function name (default: None (BoxMOT 16: "iou")). Typical options: "iou", "giou", "diou", "ciou", "centroid".

delta_t int | None

Time gap used by motion compensation (default: None (BoxMOT 16: 3)). Increasing this smooths longer motion history, but may lag quick turns.

inertia float | None

Motion inertia weight (default: None (BoxMOT 16: 0.1)). Increasing this trusts previous velocity more.

__post_init__

__post_init__() -> None

Coerce model, check the format version, flag unpacked 0.3.2.x dicts.

Source code in src/dnt/track/tracker.py
200
201
202
203
204
205
206
207
208
209
210
def __post_init__(self) -> None:
    """Coerce `model`, check the format version, flag unpacked 0.3.2.x dicts."""
    if not isinstance(self.model, MOTModels):
        self.model = MOTModels(str(self.model))
    if self.dnt_config_version != CONFIG_VERSION:
        msg = (
            f"Unsupported dnt_config_version {self.dnt_config_version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    self._warn_if_unpacked_legacy()

tuning_values

tuning_values() -> dict[str, Any]

Return the tuning fields the user set (non-None), excluding non-tuning fields.

Source code in src/dnt/track/tracker.py
231
232
233
234
235
236
237
def tuning_values(self) -> dict[str, Any]:
    """Return the tuning fields the user set (non-None), excluding non-tuning fields."""
    return {
        f.name: getattr(self, f.name)
        for f in fields(self)
        if f.name not in self.NON_TUNING and getattr(self, f.name) is not None
    }

to_kwargs

to_kwargs() -> dict[str, Any]

Convert dataclass fields to keyword arguments (kept for compatibility).

Source code in src/dnt/track/tracker.py
239
240
241
242
243
244
245
def to_kwargs(self) -> dict[str, Any]:
    """Convert dataclass fields to keyword arguments (kept for compatibility)."""
    kwargs = asdict(self)
    for key in ("model", "extra_kwargs", "dnt_config_version"):
        kwargs.pop(key, None)
    kwargs.update(self.extra_kwargs)
    return kwargs

to_dict

to_dict() -> dict[str, Any]

Return a serializable mapping that starts with dnt_config_version.

Source code in src/dnt/track/tracker.py
247
248
249
250
def to_dict(self) -> dict[str, Any]:
    """Return a serializable mapping that starts with `dnt_config_version`."""
    data = self._yaml_safe(asdict(self))
    return {"dnt_config_version": data.pop("dnt_config_version"), **data}

from_dict classmethod

from_dict(
    data: dict[str, Any],
    legacy: bool | str = "auto",
    *,
    _source: str = "dict",
) -> MOTBaseConfig

Build a config from a mapping (spec §2.7).

Parameters:

Name Type Description Default
data dict

Mapping from to_dict() (any dnt version) or hand-written.

required
legacy (auto, True, False)

"auto" migrates a mapping only if it has no dnt_config_version and exactly the 0.3.2.4 field set; True requires that shape; False never migrates.

"auto"
Source code in src/dnt/track/tracker.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
@classmethod
def from_dict(
    cls, data: dict[str, Any], legacy: bool | str = "auto", *, _source: str = "dict"
) -> "MOTBaseConfig":
    """Build a config from a mapping (spec §2.7).

    Parameters
    ----------
    data : dict
        Mapping from `to_dict()` (any dnt version) or hand-written.
    legacy : {"auto", True, False}
        "auto" migrates a mapping only if it has no `dnt_config_version` and exactly the
        0.3.2.4 field set; True requires that shape; False never migrates.

    """
    if legacy not in ("auto", True, False):
        raise ValueError("legacy must be 'auto', True or False.")
    data = dict(data)
    version = data.pop("dnt_config_version", None)
    if version is not None and version != CONFIG_VERSION:
        msg = (
            f"{_source}: unsupported dnt_config_version {version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    shaped = version is None and bx.is_legacy_shape(data)
    if legacy is True and not shaped:
        msg = (
            f"{_source}: not a dnt 0.3.2.x config (legacy=True needs the exact 0.3.2.4 field "
            "set and no dnt_config_version)."
        )
        raise ValueError(msg)
    if shaped and legacy is not False:
        data = bx.migrate_legacy(data, source=_source)
    valid = {f.name for f in fields(cls)}
    known = {k: v for k, v in data.items() if k in valid}
    unknown = {k: v for k, v in data.items() if k not in valid}
    with warnings.catch_warnings():
        if legacy is False:
            warnings.filterwarnings("ignore", message=".*unpacked 0.3.2.x dict.*")
        params = cls(**known)
    if unknown:
        params.extra_kwargs.update(unknown)
    return params

from_legacy_dict classmethod

from_legacy_dict(data: dict[str, Any]) -> MOTBaseConfig

Explicitly migrate a dnt 0.3.2.x mapping (alias of from_dict(data, legacy=True)).

Source code in src/dnt/track/tracker.py
310
311
312
313
@classmethod
def from_legacy_dict(cls, data: dict[str, Any]) -> "MOTBaseConfig":
    """Explicitly migrate a dnt 0.3.2.x mapping (alias of ``from_dict(data, legacy=True)``)."""
    return cls.from_dict(data, legacy=True)

export_yaml

export_yaml(yaml_file: str) -> None

Export parameters to a YAML file.

Source code in src/dnt/track/tracker.py
315
316
317
318
319
320
def export_yaml(self, yaml_file: str) -> None:
    """Export parameters to a YAML file."""
    out_path = Path(yaml_file)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(self.to_dict(), f, sort_keys=False)

import_yaml classmethod

import_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> MOTBaseConfig

Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7).

Source code in src/dnt/track/tracker.py
322
323
324
325
326
327
328
329
330
@classmethod
def import_yaml(cls, yaml_file: str, legacy: bool | str = "auto") -> "MOTBaseConfig":
    """Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7)."""
    with Path(yaml_file).open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        msg = f"Invalid YAML content in {yaml_file}: expected a mapping."
        raise ValueError(msg)
    return cls.from_dict(data, legacy=legacy, _source=str(yaml_file))

StrongSORTConfig dataclass

StrongSORTConfig(
    *,
    model: MOTModels = MOTModels.STRONGSORT,
    per_class: bool = False,
    extra_kwargs: dict[str, Any] = dict(),
    dnt_config_version: int = CONFIG_VERSION,
    reid_weights: ReIDWeights
    | str
    | None = ReIDWeights.OSNET_X1_0_MSMT17,
    max_cos_dist: float | None = None,
    max_dist: float | None = None,
    max_iou_dist: float | None = None,
    max_age: int | None = None,
    n_init: int | None = None,
    nn_budget: int | None = None,
    ema_alpha: float | None = None,
    mc_lambda: float | None = None,
    min_conf: float | None = None,
)

Bases: MOTBaseConfig

StrongSORT-specific parameters.

Attributes:

Name Type Description
reid_weights ReIDWeights | str | None

Optional ReID weights path (default: "osnet_x1_0_msmt17.pt"). Options: same built-in .pt names listed in BoTSORTParams.reid_weights.

max_cos_dist float | None

Maximum cosine distance for appearance matching (default: None (BoxMOT 16: 0.4)). Increasing this allows less similar appearance matches.

max_dist float | None

Deprecated alias of max_cos_dist (default: None). Setting this emits a DeprecationWarning and moves the value into max_cos_dist; setting both raises ValueError.

max_iou_dist float | None

Maximum IoU distance for geometric matching (default: None (BoxMOT 16: 0.7)). Increasing this allows looser geometric matches.

max_age int | None

Maximum age of unmatched tracks (default: None (BoxMOT 16: 30)). Increasing this retains tracks through longer occlusions.

n_init int | None

Minimum hits before track confirmation (default: None (BoxMOT 16: 3)). Increasing this delays confirmation and reduces unstable IDs.

nn_budget int | None

Maximum size of appearance feature gallery (default: None (BoxMOT 16: 100)). Increasing this improves long-term matching memory at higher memory cost.

ema_alpha float | None

EMA factor for appearance embeddings (default: None (BoxMOT 16: 0.9)). Increasing this smooths features more and reduces noise.

mc_lambda float | None

Motion compensation blending factor (default: None (BoxMOT 16: 0.98)). Increasing this gives more weight to motion compensation.

min_conf float | None

Minimum detection confidence; lower-scored detections are dropped before association (default: None (BoxMOT 16: 0.6)). StrongSORT has no low-score second stage, so this is a hard cut: lower it to track weaker detections.

__post_init__

__post_init__() -> None

Map the deprecated max_dist alias onto max_cos_dist.

Source code in src/dnt/track/tracker.py
574
575
576
577
578
579
580
581
582
583
584
585
586
def __post_init__(self) -> None:
    """Map the deprecated `max_dist` alias onto `max_cos_dist`."""
    if self.max_dist is not None:
        warnings.warn(
            "StrongSORTConfig(max_dist=...) is deprecated; use max_cos_dist.",
            DeprecationWarning,
            stacklevel=3,
        )
        if self.max_cos_dist is not None:
            msg = "StrongSORTConfig: set max_cos_dist or the deprecated max_dist, not both."
            raise ValueError(msg)
        self.max_cos_dist, self.max_dist = self.max_dist, None
    super().__post_init__()

tuning_values

tuning_values() -> dict[str, Any]

Fold a post-construction max_dist into max_cos_dist (it bypasses __post_init__).

Source code in src/dnt/track/tracker.py
588
589
590
591
592
593
594
595
596
597
598
599
600
601
def tuning_values(self) -> dict[str, Any]:
    """Fold a post-construction `max_dist` into `max_cos_dist` (it bypasses `__post_init__`)."""
    values = super().tuning_values()
    if self.max_dist is not None:
        warnings.warn(
            "StrongSORTConfig(max_dist=...) is deprecated; use max_cos_dist.",
            DeprecationWarning,
            stacklevel=3,
        )
        if self.max_cos_dist is not None:
            msg = "StrongSORTConfig: set max_cos_dist or the deprecated max_dist, not both."
            raise ValueError(msg)
        values["max_cos_dist"] = self.max_dist
    return values

to_kwargs

to_kwargs() -> dict[str, Any]

Convert dataclass fields to keyword arguments (kept for compatibility).

Source code in src/dnt/track/tracker.py
239
240
241
242
243
244
245
def to_kwargs(self) -> dict[str, Any]:
    """Convert dataclass fields to keyword arguments (kept for compatibility)."""
    kwargs = asdict(self)
    for key in ("model", "extra_kwargs", "dnt_config_version"):
        kwargs.pop(key, None)
    kwargs.update(self.extra_kwargs)
    return kwargs

to_dict

to_dict() -> dict[str, Any]

Return a serializable mapping that starts with dnt_config_version.

Source code in src/dnt/track/tracker.py
247
248
249
250
def to_dict(self) -> dict[str, Any]:
    """Return a serializable mapping that starts with `dnt_config_version`."""
    data = self._yaml_safe(asdict(self))
    return {"dnt_config_version": data.pop("dnt_config_version"), **data}

from_dict classmethod

from_dict(
    data: dict[str, Any],
    legacy: bool | str = "auto",
    *,
    _source: str = "dict",
) -> MOTBaseConfig

Build a config from a mapping (spec §2.7).

Parameters:

Name Type Description Default
data dict

Mapping from to_dict() (any dnt version) or hand-written.

required
legacy (auto, True, False)

"auto" migrates a mapping only if it has no dnt_config_version and exactly the 0.3.2.4 field set; True requires that shape; False never migrates.

"auto"
Source code in src/dnt/track/tracker.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
@classmethod
def from_dict(
    cls, data: dict[str, Any], legacy: bool | str = "auto", *, _source: str = "dict"
) -> "MOTBaseConfig":
    """Build a config from a mapping (spec §2.7).

    Parameters
    ----------
    data : dict
        Mapping from `to_dict()` (any dnt version) or hand-written.
    legacy : {"auto", True, False}
        "auto" migrates a mapping only if it has no `dnt_config_version` and exactly the
        0.3.2.4 field set; True requires that shape; False never migrates.

    """
    if legacy not in ("auto", True, False):
        raise ValueError("legacy must be 'auto', True or False.")
    data = dict(data)
    version = data.pop("dnt_config_version", None)
    if version is not None and version != CONFIG_VERSION:
        msg = (
            f"{_source}: unsupported dnt_config_version {version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    shaped = version is None and bx.is_legacy_shape(data)
    if legacy is True and not shaped:
        msg = (
            f"{_source}: not a dnt 0.3.2.x config (legacy=True needs the exact 0.3.2.4 field "
            "set and no dnt_config_version)."
        )
        raise ValueError(msg)
    if shaped and legacy is not False:
        data = bx.migrate_legacy(data, source=_source)
    valid = {f.name for f in fields(cls)}
    known = {k: v for k, v in data.items() if k in valid}
    unknown = {k: v for k, v in data.items() if k not in valid}
    with warnings.catch_warnings():
        if legacy is False:
            warnings.filterwarnings("ignore", message=".*unpacked 0.3.2.x dict.*")
        params = cls(**known)
    if unknown:
        params.extra_kwargs.update(unknown)
    return params

from_legacy_dict classmethod

from_legacy_dict(data: dict[str, Any]) -> MOTBaseConfig

Explicitly migrate a dnt 0.3.2.x mapping (alias of from_dict(data, legacy=True)).

Source code in src/dnt/track/tracker.py
310
311
312
313
@classmethod
def from_legacy_dict(cls, data: dict[str, Any]) -> "MOTBaseConfig":
    """Explicitly migrate a dnt 0.3.2.x mapping (alias of ``from_dict(data, legacy=True)``)."""
    return cls.from_dict(data, legacy=True)

export_yaml

export_yaml(yaml_file: str) -> None

Export parameters to a YAML file.

Source code in src/dnt/track/tracker.py
315
316
317
318
319
320
def export_yaml(self, yaml_file: str) -> None:
    """Export parameters to a YAML file."""
    out_path = Path(yaml_file)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(self.to_dict(), f, sort_keys=False)

import_yaml classmethod

import_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> MOTBaseConfig

Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7).

Source code in src/dnt/track/tracker.py
322
323
324
325
326
327
328
329
330
@classmethod
def import_yaml(cls, yaml_file: str, legacy: bool | str = "auto") -> "MOTBaseConfig":
    """Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7)."""
    with Path(yaml_file).open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        msg = f"Invalid YAML content in {yaml_file}: expected a mapping."
        raise ValueError(msg)
    return cls.from_dict(data, legacy=legacy, _source=str(yaml_file))

DeepOCSORTConfig dataclass

DeepOCSORTConfig(
    *,
    model: MOTModels = MOTModels.DEEPOCSORT,
    per_class: bool = False,
    extra_kwargs: dict[str, Any] = dict(),
    dnt_config_version: int = CONFIG_VERSION,
    reid_weights: ReIDWeights
    | str
    | None = ReIDWeights.OSNET_X1_0_MSMT17,
    det_thresh: float | None = None,
    max_age: int | None = None,
    min_hits: int | None = None,
    iou_threshold: float | None = None,
    asso_func: str | None = None,
    delta_t: int | None = None,
    inertia: float | None = None,
)

Bases: MOTBaseConfig

DeepOCSORT-specific parameters.

Attributes:

Name Type Description
reid_weights ReIDWeights | str | None

Optional ReID weights path (default: "osnet_x1_0_msmt17.pt"). Options: same built-in .pt names listed in BoTSORTParams.reid_weights.

det_thresh float | None

Detection confidence threshold (default: None (BoxMOT 16: 0.5)). Increasing this keeps fewer low-confidence detections.

max_age int | None

Maximum age of unmatched tracks (default: None (BoxMOT 16: 30)). Increasing this keeps unmatched tracks alive longer.

min_hits int | None

Minimum hits before track confirmation (default: None (BoxMOT 16: 3)). Increasing this delays track confirmation.

iou_threshold float | None

IoU threshold for association (default: None (BoxMOT 16 constructor default)). Increasing this requires tighter overlap.

asso_func str | None

Association function name (default: None (BoxMOT 16: "iou")). Typical options: "iou", "giou", "diou", "ciou", "centroid".

delta_t int | None

Time gap used by motion compensation (default: None (BoxMOT 16: 3)). Increasing this smooths over longer temporal windows.

inertia float | None

Motion inertia weight (default: None (BoxMOT 16: 0.2)). Increasing this emphasizes velocity continuity.

__post_init__

__post_init__() -> None

Coerce model, check the format version, flag unpacked 0.3.2.x dicts.

Source code in src/dnt/track/tracker.py
200
201
202
203
204
205
206
207
208
209
210
def __post_init__(self) -> None:
    """Coerce `model`, check the format version, flag unpacked 0.3.2.x dicts."""
    if not isinstance(self.model, MOTModels):
        self.model = MOTModels(str(self.model))
    if self.dnt_config_version != CONFIG_VERSION:
        msg = (
            f"Unsupported dnt_config_version {self.dnt_config_version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    self._warn_if_unpacked_legacy()

tuning_values

tuning_values() -> dict[str, Any]

Return the tuning fields the user set (non-None), excluding non-tuning fields.

Source code in src/dnt/track/tracker.py
231
232
233
234
235
236
237
def tuning_values(self) -> dict[str, Any]:
    """Return the tuning fields the user set (non-None), excluding non-tuning fields."""
    return {
        f.name: getattr(self, f.name)
        for f in fields(self)
        if f.name not in self.NON_TUNING and getattr(self, f.name) is not None
    }

to_kwargs

to_kwargs() -> dict[str, Any]

Convert dataclass fields to keyword arguments (kept for compatibility).

Source code in src/dnt/track/tracker.py
239
240
241
242
243
244
245
def to_kwargs(self) -> dict[str, Any]:
    """Convert dataclass fields to keyword arguments (kept for compatibility)."""
    kwargs = asdict(self)
    for key in ("model", "extra_kwargs", "dnt_config_version"):
        kwargs.pop(key, None)
    kwargs.update(self.extra_kwargs)
    return kwargs

to_dict

to_dict() -> dict[str, Any]

Return a serializable mapping that starts with dnt_config_version.

Source code in src/dnt/track/tracker.py
247
248
249
250
def to_dict(self) -> dict[str, Any]:
    """Return a serializable mapping that starts with `dnt_config_version`."""
    data = self._yaml_safe(asdict(self))
    return {"dnt_config_version": data.pop("dnt_config_version"), **data}

from_dict classmethod

from_dict(
    data: dict[str, Any],
    legacy: bool | str = "auto",
    *,
    _source: str = "dict",
) -> MOTBaseConfig

Build a config from a mapping (spec §2.7).

Parameters:

Name Type Description Default
data dict

Mapping from to_dict() (any dnt version) or hand-written.

required
legacy (auto, True, False)

"auto" migrates a mapping only if it has no dnt_config_version and exactly the 0.3.2.4 field set; True requires that shape; False never migrates.

"auto"
Source code in src/dnt/track/tracker.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
@classmethod
def from_dict(
    cls, data: dict[str, Any], legacy: bool | str = "auto", *, _source: str = "dict"
) -> "MOTBaseConfig":
    """Build a config from a mapping (spec §2.7).

    Parameters
    ----------
    data : dict
        Mapping from `to_dict()` (any dnt version) or hand-written.
    legacy : {"auto", True, False}
        "auto" migrates a mapping only if it has no `dnt_config_version` and exactly the
        0.3.2.4 field set; True requires that shape; False never migrates.

    """
    if legacy not in ("auto", True, False):
        raise ValueError("legacy must be 'auto', True or False.")
    data = dict(data)
    version = data.pop("dnt_config_version", None)
    if version is not None and version != CONFIG_VERSION:
        msg = (
            f"{_source}: unsupported dnt_config_version {version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    shaped = version is None and bx.is_legacy_shape(data)
    if legacy is True and not shaped:
        msg = (
            f"{_source}: not a dnt 0.3.2.x config (legacy=True needs the exact 0.3.2.4 field "
            "set and no dnt_config_version)."
        )
        raise ValueError(msg)
    if shaped and legacy is not False:
        data = bx.migrate_legacy(data, source=_source)
    valid = {f.name for f in fields(cls)}
    known = {k: v for k, v in data.items() if k in valid}
    unknown = {k: v for k, v in data.items() if k not in valid}
    with warnings.catch_warnings():
        if legacy is False:
            warnings.filterwarnings("ignore", message=".*unpacked 0.3.2.x dict.*")
        params = cls(**known)
    if unknown:
        params.extra_kwargs.update(unknown)
    return params

from_legacy_dict classmethod

from_legacy_dict(data: dict[str, Any]) -> MOTBaseConfig

Explicitly migrate a dnt 0.3.2.x mapping (alias of from_dict(data, legacy=True)).

Source code in src/dnt/track/tracker.py
310
311
312
313
@classmethod
def from_legacy_dict(cls, data: dict[str, Any]) -> "MOTBaseConfig":
    """Explicitly migrate a dnt 0.3.2.x mapping (alias of ``from_dict(data, legacy=True)``)."""
    return cls.from_dict(data, legacy=True)

export_yaml

export_yaml(yaml_file: str) -> None

Export parameters to a YAML file.

Source code in src/dnt/track/tracker.py
315
316
317
318
319
320
def export_yaml(self, yaml_file: str) -> None:
    """Export parameters to a YAML file."""
    out_path = Path(yaml_file)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(self.to_dict(), f, sort_keys=False)

import_yaml classmethod

import_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> MOTBaseConfig

Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7).

Source code in src/dnt/track/tracker.py
322
323
324
325
326
327
328
329
330
@classmethod
def import_yaml(cls, yaml_file: str, legacy: bool | str = "auto") -> "MOTBaseConfig":
    """Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7)."""
    with Path(yaml_file).open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        msg = f"Invalid YAML content in {yaml_file}: expected a mapping."
        raise ValueError(msg)
    return cls.from_dict(data, legacy=legacy, _source=str(yaml_file))

HybridSORTConfig dataclass

HybridSORTConfig(
    *,
    model: MOTModels = MOTModels.HYBRIDSORT,
    per_class: bool = False,
    extra_kwargs: dict[str, Any] = dict(),
    dnt_config_version: int = CONFIG_VERSION,
    reid_weights: ReIDWeights
    | str
    | None = ReIDWeights.OSNET_X1_0_MSMT17,
    det_thresh: float | None = None,
    max_age: int | None = None,
    min_hits: int | None = None,
    iou_threshold: float | None = None,
    asso_func: str | None = None,
)

Bases: MOTBaseConfig

HybridSORT-specific parameters.

Attributes:

Name Type Description
reid_weights ReIDWeights | str | None

Optional ReID weights path (default: "osnet_x1_0_msmt17.pt"). Options: same built-in .pt names listed in BoTSORTParams.reid_weights.

det_thresh float | None

Detection confidence threshold (default: None (BoxMOT 16 constructor default)). Increasing this reduces weak detections.

max_age int | None

Maximum age of unmatched tracks (default: None (BoxMOT 16 constructor default)). Increasing this keeps tracks longer during occlusion.

min_hits int | None

Minimum hits before track confirmation (default: None (BoxMOT 16 constructor default)). Increasing this reduces early noisy tracks.

iou_threshold float | None

IoU threshold for association (default: None (BoxMOT 16 constructor default)). Increasing this makes IoU matching stricter.

asso_func str | None

Association function name (default: None (BoxMOT 16 constructor default)). Typical options: "iou", "giou", "diou", "ciou", "centroid".

__post_init__

__post_init__() -> None

Coerce model, check the format version, flag unpacked 0.3.2.x dicts.

Source code in src/dnt/track/tracker.py
200
201
202
203
204
205
206
207
208
209
210
def __post_init__(self) -> None:
    """Coerce `model`, check the format version, flag unpacked 0.3.2.x dicts."""
    if not isinstance(self.model, MOTModels):
        self.model = MOTModels(str(self.model))
    if self.dnt_config_version != CONFIG_VERSION:
        msg = (
            f"Unsupported dnt_config_version {self.dnt_config_version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    self._warn_if_unpacked_legacy()

tuning_values

tuning_values() -> dict[str, Any]

Return the tuning fields the user set (non-None), excluding non-tuning fields.

Source code in src/dnt/track/tracker.py
231
232
233
234
235
236
237
def tuning_values(self) -> dict[str, Any]:
    """Return the tuning fields the user set (non-None), excluding non-tuning fields."""
    return {
        f.name: getattr(self, f.name)
        for f in fields(self)
        if f.name not in self.NON_TUNING and getattr(self, f.name) is not None
    }

to_kwargs

to_kwargs() -> dict[str, Any]

Convert dataclass fields to keyword arguments (kept for compatibility).

Source code in src/dnt/track/tracker.py
239
240
241
242
243
244
245
def to_kwargs(self) -> dict[str, Any]:
    """Convert dataclass fields to keyword arguments (kept for compatibility)."""
    kwargs = asdict(self)
    for key in ("model", "extra_kwargs", "dnt_config_version"):
        kwargs.pop(key, None)
    kwargs.update(self.extra_kwargs)
    return kwargs

to_dict

to_dict() -> dict[str, Any]

Return a serializable mapping that starts with dnt_config_version.

Source code in src/dnt/track/tracker.py
247
248
249
250
def to_dict(self) -> dict[str, Any]:
    """Return a serializable mapping that starts with `dnt_config_version`."""
    data = self._yaml_safe(asdict(self))
    return {"dnt_config_version": data.pop("dnt_config_version"), **data}

from_dict classmethod

from_dict(
    data: dict[str, Any],
    legacy: bool | str = "auto",
    *,
    _source: str = "dict",
) -> MOTBaseConfig

Build a config from a mapping (spec §2.7).

Parameters:

Name Type Description Default
data dict

Mapping from to_dict() (any dnt version) or hand-written.

required
legacy (auto, True, False)

"auto" migrates a mapping only if it has no dnt_config_version and exactly the 0.3.2.4 field set; True requires that shape; False never migrates.

"auto"
Source code in src/dnt/track/tracker.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
@classmethod
def from_dict(
    cls, data: dict[str, Any], legacy: bool | str = "auto", *, _source: str = "dict"
) -> "MOTBaseConfig":
    """Build a config from a mapping (spec §2.7).

    Parameters
    ----------
    data : dict
        Mapping from `to_dict()` (any dnt version) or hand-written.
    legacy : {"auto", True, False}
        "auto" migrates a mapping only if it has no `dnt_config_version` and exactly the
        0.3.2.4 field set; True requires that shape; False never migrates.

    """
    if legacy not in ("auto", True, False):
        raise ValueError("legacy must be 'auto', True or False.")
    data = dict(data)
    version = data.pop("dnt_config_version", None)
    if version is not None and version != CONFIG_VERSION:
        msg = (
            f"{_source}: unsupported dnt_config_version {version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    shaped = version is None and bx.is_legacy_shape(data)
    if legacy is True and not shaped:
        msg = (
            f"{_source}: not a dnt 0.3.2.x config (legacy=True needs the exact 0.3.2.4 field "
            "set and no dnt_config_version)."
        )
        raise ValueError(msg)
    if shaped and legacy is not False:
        data = bx.migrate_legacy(data, source=_source)
    valid = {f.name for f in fields(cls)}
    known = {k: v for k, v in data.items() if k in valid}
    unknown = {k: v for k, v in data.items() if k not in valid}
    with warnings.catch_warnings():
        if legacy is False:
            warnings.filterwarnings("ignore", message=".*unpacked 0.3.2.x dict.*")
        params = cls(**known)
    if unknown:
        params.extra_kwargs.update(unknown)
    return params

from_legacy_dict classmethod

from_legacy_dict(data: dict[str, Any]) -> MOTBaseConfig

Explicitly migrate a dnt 0.3.2.x mapping (alias of from_dict(data, legacy=True)).

Source code in src/dnt/track/tracker.py
310
311
312
313
@classmethod
def from_legacy_dict(cls, data: dict[str, Any]) -> "MOTBaseConfig":
    """Explicitly migrate a dnt 0.3.2.x mapping (alias of ``from_dict(data, legacy=True)``)."""
    return cls.from_dict(data, legacy=True)

export_yaml

export_yaml(yaml_file: str) -> None

Export parameters to a YAML file.

Source code in src/dnt/track/tracker.py
315
316
317
318
319
320
def export_yaml(self, yaml_file: str) -> None:
    """Export parameters to a YAML file."""
    out_path = Path(yaml_file)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(self.to_dict(), f, sort_keys=False)

import_yaml classmethod

import_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> MOTBaseConfig

Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7).

Source code in src/dnt/track/tracker.py
322
323
324
325
326
327
328
329
330
@classmethod
def import_yaml(cls, yaml_file: str, legacy: bool | str = "auto") -> "MOTBaseConfig":
    """Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7)."""
    with Path(yaml_file).open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        msg = f"Invalid YAML content in {yaml_file}: expected a mapping."
        raise ValueError(msg)
    return cls.from_dict(data, legacy=legacy, _source=str(yaml_file))

SFSORTConfig dataclass

SFSORTConfig(
    *,
    model: MOTModels = MOTModels.SFSORT,
    per_class: bool = False,
    extra_kwargs: dict[str, Any] = dict(),
    dnt_config_version: int = CONFIG_VERSION,
    high_th: float | None = None,
    low_th: float | None = None,
    new_track_th: float | None = None,
    match_th_first: float | None = None,
    match_th_second: float | None = None,
    det_thresh: float | None = None,
    max_age: int | None = None,
    min_hits: int | None = None,
    iou_threshold: float | None = None,
    asso_func: str | None = None,
)

Bases: MOTBaseConfig

SFSORT-specific parameters.

Attributes:

Name Type Description
high_th float | None

High score threshold for first-stage association (default: None (BoxMOT 16: 0.6)). Increasing this is stricter and may reduce false matches but miss tracks.

low_th float | None

Low score threshold for second-stage association (default: None (BoxMOT 16: 0.1)). Increasing this keeps fewer low-confidence detections.

new_track_th float | None

Threshold to initialize new tracks (default: None (BoxMOT 16: 0.7)). Increasing this creates fewer new tracks and can reduce false positives.

match_th_first float | None

Matching threshold for first-stage association (default: None (BoxMOT 16: 0.67)). Increasing this makes first-stage association more permissive.

match_th_second float | None

Matching threshold for second-stage association (default: None (BoxMOT 16: 0.3)). Increasing this makes second-stage association more permissive.

det_thresh float | None

Detection confidence threshold. No effect in BoxMOT 16; raises ValueError if set.

max_age int | None

Maximum age of unmatched tracks. No effect in BoxMOT 16; raises ValueError if set.

min_hits int | None

Minimum hits before track confirmation. No effect in BoxMOT 16; raises ValueError if set.

iou_threshold float | None

IoU threshold for association. No effect in BoxMOT 16; raises ValueError if set.

asso_func str | None

Association function name. No effect in BoxMOT 16; raises ValueError if set.

__post_init__

__post_init__() -> None

Coerce model, check the format version, flag unpacked 0.3.2.x dicts.

Source code in src/dnt/track/tracker.py
200
201
202
203
204
205
206
207
208
209
210
def __post_init__(self) -> None:
    """Coerce `model`, check the format version, flag unpacked 0.3.2.x dicts."""
    if not isinstance(self.model, MOTModels):
        self.model = MOTModels(str(self.model))
    if self.dnt_config_version != CONFIG_VERSION:
        msg = (
            f"Unsupported dnt_config_version {self.dnt_config_version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    self._warn_if_unpacked_legacy()

tuning_values

tuning_values() -> dict[str, Any]

Return the tuning fields the user set (non-None), excluding non-tuning fields.

Source code in src/dnt/track/tracker.py
231
232
233
234
235
236
237
def tuning_values(self) -> dict[str, Any]:
    """Return the tuning fields the user set (non-None), excluding non-tuning fields."""
    return {
        f.name: getattr(self, f.name)
        for f in fields(self)
        if f.name not in self.NON_TUNING and getattr(self, f.name) is not None
    }

to_kwargs

to_kwargs() -> dict[str, Any]

Convert dataclass fields to keyword arguments (kept for compatibility).

Source code in src/dnt/track/tracker.py
239
240
241
242
243
244
245
def to_kwargs(self) -> dict[str, Any]:
    """Convert dataclass fields to keyword arguments (kept for compatibility)."""
    kwargs = asdict(self)
    for key in ("model", "extra_kwargs", "dnt_config_version"):
        kwargs.pop(key, None)
    kwargs.update(self.extra_kwargs)
    return kwargs

to_dict

to_dict() -> dict[str, Any]

Return a serializable mapping that starts with dnt_config_version.

Source code in src/dnt/track/tracker.py
247
248
249
250
def to_dict(self) -> dict[str, Any]:
    """Return a serializable mapping that starts with `dnt_config_version`."""
    data = self._yaml_safe(asdict(self))
    return {"dnt_config_version": data.pop("dnt_config_version"), **data}

from_dict classmethod

from_dict(
    data: dict[str, Any],
    legacy: bool | str = "auto",
    *,
    _source: str = "dict",
) -> MOTBaseConfig

Build a config from a mapping (spec §2.7).

Parameters:

Name Type Description Default
data dict

Mapping from to_dict() (any dnt version) or hand-written.

required
legacy (auto, True, False)

"auto" migrates a mapping only if it has no dnt_config_version and exactly the 0.3.2.4 field set; True requires that shape; False never migrates.

"auto"
Source code in src/dnt/track/tracker.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
@classmethod
def from_dict(
    cls, data: dict[str, Any], legacy: bool | str = "auto", *, _source: str = "dict"
) -> "MOTBaseConfig":
    """Build a config from a mapping (spec §2.7).

    Parameters
    ----------
    data : dict
        Mapping from `to_dict()` (any dnt version) or hand-written.
    legacy : {"auto", True, False}
        "auto" migrates a mapping only if it has no `dnt_config_version` and exactly the
        0.3.2.4 field set; True requires that shape; False never migrates.

    """
    if legacy not in ("auto", True, False):
        raise ValueError("legacy must be 'auto', True or False.")
    data = dict(data)
    version = data.pop("dnt_config_version", None)
    if version is not None and version != CONFIG_VERSION:
        msg = (
            f"{_source}: unsupported dnt_config_version {version!r}; "
            f"this dnt reads {CONFIG_VERSION}."
        )
        raise ValueError(msg)
    shaped = version is None and bx.is_legacy_shape(data)
    if legacy is True and not shaped:
        msg = (
            f"{_source}: not a dnt 0.3.2.x config (legacy=True needs the exact 0.3.2.4 field "
            "set and no dnt_config_version)."
        )
        raise ValueError(msg)
    if shaped and legacy is not False:
        data = bx.migrate_legacy(data, source=_source)
    valid = {f.name for f in fields(cls)}
    known = {k: v for k, v in data.items() if k in valid}
    unknown = {k: v for k, v in data.items() if k not in valid}
    with warnings.catch_warnings():
        if legacy is False:
            warnings.filterwarnings("ignore", message=".*unpacked 0.3.2.x dict.*")
        params = cls(**known)
    if unknown:
        params.extra_kwargs.update(unknown)
    return params

from_legacy_dict classmethod

from_legacy_dict(data: dict[str, Any]) -> MOTBaseConfig

Explicitly migrate a dnt 0.3.2.x mapping (alias of from_dict(data, legacy=True)).

Source code in src/dnt/track/tracker.py
310
311
312
313
@classmethod
def from_legacy_dict(cls, data: dict[str, Any]) -> "MOTBaseConfig":
    """Explicitly migrate a dnt 0.3.2.x mapping (alias of ``from_dict(data, legacy=True)``)."""
    return cls.from_dict(data, legacy=True)

export_yaml

export_yaml(yaml_file: str) -> None

Export parameters to a YAML file.

Source code in src/dnt/track/tracker.py
315
316
317
318
319
320
def export_yaml(self, yaml_file: str) -> None:
    """Export parameters to a YAML file."""
    out_path = Path(yaml_file)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(self.to_dict(), f, sort_keys=False)

import_yaml classmethod

import_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> MOTBaseConfig

Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7).

Source code in src/dnt/track/tracker.py
322
323
324
325
326
327
328
329
330
@classmethod
def import_yaml(cls, yaml_file: str, legacy: bool | str = "auto") -> "MOTBaseConfig":
    """Import parameters from a YAML file (0.3.2.x files are migrated; spec §2.7)."""
    with Path(yaml_file).open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        msg = f"Invalid YAML content in {yaml_file}: expected a mapping."
        raise ValueError(msg)
    return cls.from_dict(data, legacy=legacy, _source=str(yaml_file))

Tracker

Tracker(
    config: BoxMOTModelParams | None = None,
    config_yaml: str | None = None,
    device: str = "auto",
    half: bool = False,
    output_score_cls: bool = True,
    boxmot_verbose: bool = False,
)

Unified interface for BoxMOT tracking and track post-processing.

This class runs BoxMOT tracking given a detection file and source video. It also provides post-processing utilities to infill missing frames, split tracks by large gaps, and drop short tracks.

Attributes:

Name Type Description
TRACK_FIELDS list[str]

Standard output columns for tracking and post-processing utilities (default: class constant).

device str

Device string used by deep trackers (default: "auto"). Options: "auto", "cpu", "cuda", "mps".

half bool

Whether half precision is enabled for deep trackers (default: False). Options: True, False. Enabling can improve speed on supported GPUs.

boxmot_model MOTModels

Selected BoxMOT tracker backend (default: MOTModels.BOTSORT). Options: MOTModels.BOTSORT, MOTModels.BOOSTTRACK, MOTModels.BYTE_TRACK, MOTModels.OCSORT, MOTModels.STRONGSORT, MOTModels.DEEPOCSORT, MOTModels.HYBRIDSORT, MOTModels.SFSORT.

boxmot_config BoxMOTModelConfig

Configuration dataclass instance for BoxMOT tracker creation (default: model-specific defaults).

boxmot_verbose bool

If False, suppress BoxMOT INFO/SUCCESS logging output.

output_score_cls bool

Whether to include tracker score and cls values in outputs. If False, both fields are exported as -1 to keep file schema stable.

REID_WEIGHTS_DIR Path

Directory where relative ReID weights are resolved and stored.

DEFAULT_REID_WEIGHT str

Fallback ReID weight file name used when a model expects ReID and no weight is explicitly set.

Initialize the tracker.

Parameters:

Name Type Description Default
config BoxMOTModelConfig

Configuration bundle for BoxMOT tracker creation. Tracker backend is selected from config.model.

None
config_yaml str

YAML file containing model-aware config. When provided, values loaded from YAML override config input.

None
device str

Device string used by deep trackers (default: "auto", "cpu", "cuda", "mps").

'auto'
half bool

Whether half precision is enabled for deep trackers (default: False).

False
output_score_cls bool

If True, output tracker confidence and class values in score and cls columns. If False, export -1 for both fields.

True
boxmot_verbose bool

If False, suppress BoxMOT INFO/SUCCESS logging output.

False
Source code in src/dnt/track/tracker.py
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
def __init__(
    self,
    config: BoxMOTModelParams | None = None,
    config_yaml: str | None = None,
    device: str = "auto",
    half: bool = False,
    output_score_cls: bool = True,
    boxmot_verbose: bool = False,
) -> None:
    """Initialize the tracker.

    Parameters
    ----------
    config : BoxMOTModelConfig, optional
        Configuration bundle for BoxMOT tracker creation. Tracker backend
        is selected from `config.model`.
    config_yaml : str, optional
        YAML file containing model-aware config. When provided,
        values loaded from YAML override `config` input.
    device : str, optional
        Device string used by deep trackers (default: `"auto"`, "cpu", "cuda", "mps").
    half : bool, optional
        Whether half precision is enabled for deep trackers (default: `False`).
    output_score_cls : bool, optional
        If True, output tracker confidence and class values in `score` and
        `cls` columns. If False, export `-1` for both fields.
    boxmot_verbose : bool, optional
        If False, suppress BoxMOT INFO/SUCCESS logging output.

    """
    self.device = device
    self.half = half
    self.boxmot_verbose = boxmot_verbose
    self.output_score_cls = output_score_cls
    yaml_path = config_yaml
    resolved_config = config
    self.model_config_yaml = yaml_path

    if yaml_path:
        resolved_config = self.import_config_from_yaml(yaml_path)

    if resolved_config is None:
        resolved_config = self._default_boxmot_config()

    self.boxmot_model = resolved_config.model
    self.boxmot_config = resolved_config

track

track(
    det_file: str,
    out_file: str,
    video_file: str | None = None,
    show: bool = False,
    video_index: int | None = None,
    video_tot: int | None = None,
    message: str | None = "",
    verbose: bool = True,
) -> pd.DataFrame

Run tracking on a single detection file using BoxMOT.

Parameters:

Name Type Description Default
det_file str

Path to detection file in DNT detection format (frame, -, x, y, width, height, confidence, class_id).

required
out_file str

Path to write tracking results. If empty string, results are not saved.

required
video_file str

Path to source video file. Required for BoxMOT tracker.

None
show bool

If True (default: False), display live tracking preview with bounding boxes and track IDs. Press 's' to toggle preview, 'ESC' to hide, 'q' to stop tracking early.

False
video_index int

Index of current video in batch (for progress bar display).

None
video_tot int

Total number of videos in batch (for complete progress context).

None
message str | None

Progress text shown in the progress bar. Default is "" (no text); pass None to show the video file name.

''
verbose bool

Whether to show a progress bar. Default is True.

True

Returns:

Type Description
DataFrame

Tracking results with columns: frame, track, x, y, w, h, score, cls, r3, r4 Each row represents one detected object per frame.

Raises:

Type Description
FileNotFoundError

If det_file or video_file does not exist.

ValueError

If video_file is None.

Notes

The tracker processes detections frame-by-frame, maintaining track IDs across frames. Detection coordinates are converted from (x1, y1, x2, y2) to (x, y, width, height) format for BoxMOT.

Track IDs are persistent across frame sequences and reused if tracks are lost and then re-acquired within track_buffer frames.

Source code in src/dnt/track/tracker.py
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
def track(
    self,
    det_file: str,
    out_file: str,
    video_file: str | None = None,
    show: bool = False,
    video_index: int | None = None,
    video_tot: int | None = None,
    message: str | None = "",
    verbose: bool = True,
) -> pd.DataFrame:
    """Run tracking on a single detection file using BoxMOT.

    Parameters
    ----------
    det_file : str
        Path to detection file in DNT detection format
        (frame, -, x, y, width, height, confidence, class_id).
    out_file : str
        Path to write tracking results. If empty string, results are not saved.
    video_file : str, optional
        Path to source video file. Required for BoxMOT tracker.
    show : bool, optional
        If True (default: False), display live tracking preview with bounding
        boxes and track IDs. Press 's' to toggle preview, 'ESC' to hide,
        'q' to stop tracking early.
    video_index : int, optional
        Index of current video in batch (for progress bar display).
    video_tot : int, optional
        Total number of videos in batch (for complete progress context).
    message : str | None, optional
        Progress text shown in the progress bar. Default is "" (no text);
        pass None to show the video file name.
    verbose : bool, optional
        Whether to show a progress bar. Default is True.

    Returns
    -------
    pd.DataFrame
        Tracking results with columns: frame, track, x, y, w, h, score, cls, r3, r4
        Each row represents one detected object per frame.

    Raises
    ------
    FileNotFoundError
        If det_file or video_file does not exist.
    ValueError
        If video_file is None.

    Notes
    -----
    The tracker processes detections frame-by-frame, maintaining track IDs
    across frames. Detection coordinates are converted from (x1, y1, x2, y2)
    to (x, y, width, height) format for BoxMOT.

    Track IDs are persistent across frame sequences and reused if tracks
    are lost and then re-acquired within track_buffer frames.

    """
    if not Path(det_file).exists():
        msg = f"Detection file not found: {det_file}"
        raise FileNotFoundError(msg)

    if video_file is None:
        msg = "Video file required for BoxMOT tracking but not provided."
        raise ValueError(msg)
    if not Path(video_file).exists():
        msg = f"Video file not found: {video_file}"
        raise FileNotFoundError(msg)

    return self._track_boxmot(
        video_file=video_file,
        det_file=det_file,
        out_file=out_file,
        show=show,
        video_index=video_index,
        video_tot=video_tot,
        message=message,
        verbose=verbose,
    )

track_batch

track_batch(
    det_files: list[str] | None = None,
    video_files: list[str] | None = None,
    output_path: str | None = None,
    is_overwrite: bool = False,
    is_report: bool = True,
    message: str | None = "",
    verbose: bool = True,
) -> list[str]

Run tracking on multiple detection files sequentially.

Parameters:

Name Type Description Default
det_files list[str] | None

List of detection file paths. Each file should contain frame-level detections in CSV format. If None (default), returns empty list.

None
video_files list[str] | None

List of corresponding source video file paths for each detection file. Length should match det_files. Required for BoxMOT tracking.

None
output_path str | None

Directory to save tracking results. Track files are named based on input filename with '_track.txt' suffix. If None (default), tracking still runs but results are not persisted.

None
is_overwrite bool

If False (default), skip tracking for videos with existing output files.

False
is_report bool

If True (default), include skipped files in returned list.

True
message str | None

Progress text shown in each tracking progress bar. Default is "" (no text); pass None to show each video's file name.

''
verbose bool

Whether to show a progress bar for each video. Default is True.

True

Returns:

Type Description
list[str]

List of output track file paths. Includes both newly created and existing files (if is_report=True). Empty list if det_files is None.

Notes

Processing is sequential (not parallel). Each detection file is tracked in order with progress display showing "Tracking X of Y".

Files matching between det_files and video_files by index position. If video_files is shorter than det_files, missing videos are left None and those detections are skipped.

Source code in src/dnt/track/tracker.py
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
def track_batch(
    self,
    det_files: list[str] | None = None,
    video_files: list[str] | None = None,
    output_path: str | None = None,
    is_overwrite: bool = False,
    is_report: bool = True,
    message: str | None = "",
    verbose: bool = True,
) -> list[str]:
    """Run tracking on multiple detection files sequentially.

    Parameters
    ----------
    det_files : list[str] | None, optional
        List of detection file paths. Each file should contain frame-level
        detections in CSV format. If None (default), returns empty list.
    video_files : list[str] | None, optional
        List of corresponding source video file paths for each detection file.
        Length should match det_files. Required for BoxMOT tracking.
    output_path : str | None, optional
        Directory to save tracking results. Track files are named based on
        input filename with '_track.txt' suffix. If None (default),
        tracking still runs but results are not persisted.
    is_overwrite : bool, optional
        If False (default), skip tracking for videos with existing output files.
    is_report : bool, optional
        If True (default), include skipped files in returned list.
    message : str | None, optional
        Progress text shown in each tracking progress bar. Default is ""
        (no text); pass None to show each video's file name.
    verbose : bool, optional
        Whether to show a progress bar for each video. Default is True.

    Returns
    -------
    list[str]
        List of output track file paths. Includes both newly created and
        existing files (if is_report=True). Empty list if det_files is None.

    Notes
    -----
    Processing is sequential (not parallel). Each detection file is tracked
    in order with progress display showing "Tracking X of Y".

    Files matching between det_files and video_files by index position.
    If video_files is shorter than det_files, missing videos are left None
    and those detections are skipped.

    """
    if det_files is None:
        return []

    results: list[str] = []
    total_videos = len(det_files)

    for idx, det_file in enumerate(det_files, start=1):
        base_filename = re.sub(r"_iou$", "", Path(det_file).stem)

        track_file = None
        if output_path:
            os.makedirs(output_path, exist_ok=True)
            track_file = os.path.join(output_path, base_filename + "_track.txt")

        if track_file and not is_overwrite and os.path.exists(track_file):
            if is_report:
                results.append(track_file)
            continue

        # BoxMOT requires a matching source video.
        video_file = None
        if video_files is not None:  # noqa: SIM102
            if idx - 1 < len(video_files):
                video_file = video_files[idx - 1]

        # run tracking
        self.track(
            det_file=det_file,
            out_file=track_file if track_file else "",  # track() expects a path
            video_file=video_file,
            video_index=idx,
            video_tot=total_videos,
            message=message,
            verbose=verbose,
        )

        if track_file:
            results.append(track_file)

    return results

export_config_to_yaml staticmethod

export_config_to_yaml(
    yaml_file: str, config: BoxMOTModelParams
) -> None

Export model-aware BoxMOT config to a YAML file.

Source code in src/dnt/track/tracker.py
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
@staticmethod
def export_config_to_yaml(
    yaml_file: str,
    config: BoxMOTModelParams,
) -> None:
    """Export model-aware BoxMOT config to a YAML file."""
    out_path = Path(yaml_file)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    with out_path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(config.to_dict(), f, sort_keys=False)

import_config_from_yaml staticmethod

import_config_from_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> BoxMOTModelParams

Import model-aware BoxMOT config from a YAML file (0.3.2.x files are migrated; §2.7).

Source code in src/dnt/track/tracker.py
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
@staticmethod
def import_config_from_yaml(yaml_file: str, legacy: bool | str = "auto") -> BoxMOTModelParams:
    """Import model-aware BoxMOT config from a YAML file (0.3.2.x files are migrated; §2.7)."""
    with Path(yaml_file).open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        msg = f"Invalid YAML content in {yaml_file}: expected a mapping."
        raise ValueError(msg)

    model = MOTModels(str(data.get("model", MOTModels.BOTSORT.value)))
    param_cls = Tracker._params_class_for_model(model)
    return param_cls.from_dict(data, legacy=legacy, _source=str(yaml_file))

export_params_to_yaml staticmethod

export_params_to_yaml(
    yaml_file: str, params: BoxMOTModelParams
) -> None

Export model-aware BoxMOT params to a YAML file (backward-compatible wrapper).

Source code in src/dnt/track/tracker.py
1164
1165
1166
1167
1168
1169
1170
@staticmethod
def export_params_to_yaml(
    yaml_file: str,
    params: BoxMOTModelParams,
) -> None:
    """Export model-aware BoxMOT params to a YAML file (backward-compatible wrapper)."""
    Tracker.export_config_to_yaml(yaml_file=yaml_file, config=params)

import_params_from_yaml staticmethod

import_params_from_yaml(
    yaml_file: str, legacy: bool | str = "auto"
) -> BoxMOTModelParams

Backward-compatible wrapper for import_config_from_yaml.

Source code in src/dnt/track/tracker.py
1172
1173
1174
1175
@staticmethod
def import_params_from_yaml(yaml_file: str, legacy: bool | str = "auto") -> BoxMOTModelParams:
    """Backward-compatible wrapper for `import_config_from_yaml`."""
    return Tracker.import_config_from_yaml(yaml_file=yaml_file, legacy=legacy)

export_current_config_to_yaml

export_current_config_to_yaml(yaml_file: str) -> None

Export this tracker's active model and config to YAML.

Source code in src/dnt/track/tracker.py
1177
1178
1179
1180
1181
1182
def export_current_config_to_yaml(self, yaml_file: str) -> None:
    """Export this tracker's active model and config to YAML."""
    self.export_config_to_yaml(
        yaml_file=yaml_file,
        config=self.boxmot_config,
    )

export_current_params_to_yaml

export_current_params_to_yaml(yaml_file: str) -> None

Export this tracker's active model and config to YAML (backward-compatible wrapper).

Source code in src/dnt/track/tracker.py
1184
1185
1186
def export_current_params_to_yaml(self, yaml_file: str) -> None:
    """Export this tracker's active model and config to YAML (backward-compatible wrapper)."""
    self.export_current_config_to_yaml(yaml_file)