A comprehensive Python package for multi-target tracking algorithms, designed with a modular architecture that separates tracking components for flexibility and extensibility.
The MTT package implements a modular framework for multi-target tracking algorithms. The tracking problem is decomposed into distinct, interchangeable components:
- Gating: Filters out unlikely measurement-to-track associations
- Association: Assigns measurements to existing tracks using different algorithms
- Filtering: Provides single target state estimation (Kalman filters)
- Track Management: Handles track creation, confirmation, and deletion logic
This modular design allows for easy experimentation with different combinations of algorithms and makes the codebase highly maintainable and extensible. This project was developed as part of the WildCap project.
ROS Integration: For ROS integration and deployment as ROS nodes for real-time multi-target tracking in robotic systems, please see the separate ROS wrapper repository: ROS MTT Repository
- Python 3.8+
- NumPy ≥ 1.24.0
- Pandas ≥ 2.0.0
- SciPy ≥ 1.10.0
- pyehm ≥ 2.0a1 (for EHM algorithm)
Optional dependencies:
- Murty algorithm (only for
MultiHypothesisTracker
) - see murty repository
# Clone the multi_target_tracking repository from GitHub
git clone https://github.com/robot-perception-group/multi_target_tracking.git
# Change directory to the cloned repository
cd multi_target_tracking
# Install the package (recommended for most users)
pip install .
If you want to make changes to the code and have them reflected without reinstalling, use editable mode:
# Install the package in editable mode (for development)
pip install -e .
To enable the Multi-Hypothesis Tracker (MHT), you need to install the Murty algorithm package in the root
folder:
# Navigate to the root directory
cd path/to/multi_target_tracking
# Clone the murty repository
git clone https://github.com/robot-perception-group/murty.git
# Navigate to the murty directory
cd murty
# Install the murty package
pip install -e .
Note: The Murty algorithm is only required for MultiHypothesisTracker
. Other trackers (SingleTargetTracker
, JPDATracker
) work without this dependency.
# Test basic installation
from multi_target_tracking.trackers import SingleTargetTracker, JPDATracker
print("✓ Basic tracking functionality available")
# Test Murty algorithm (if installed)
try:
from multi_target_tracking.trackers import MultiHypothesisTracker
print("✓ Murty algorithm and MHT available (Note: MHT currently not working)")
except ImportError:
print("ℹ Murty algorithm not installed")
from multi_target_tracking.trackers import JPDATracker
from multi_target_tracking.filters import KFTrack
from multi_target_tracking.gaters import MahalanobisGater
from multi_target_tracking.likelihoods import MahalanobisLikelihood
from multi_target_tracking.track import MNLogic
# Initialize JPDA tracker
tracker = JPDATracker(
filter_obj=KFTrack(),
gater=MahalanobisGater(),
likelihood=MahalanobisLikelihood(),
track_logic=MNLogic(),
)
# Process measurements
for timestamp, measurements, source_id in measurement_data:
tracker.evaluate((timestamp, measurements, source_id))
# Get confirmed tracks
from multi_target_tracking.track import TrackStage
confirmed_tracks = [track for track in tracker.tracks
if track.stage == TrackStage.CONFIRMED]
multi_target_tracking/
├── cfg/mtt_config.yaml # Configuration parameters
├── distributed_trackers/ # Distributed tracking algorithms
├── filters/ # State estimation filters (Kalman filters)
├── gaters/ # Measurement gating algorithms
├── likelihoods/ # Likelihood calculation methods
├── track/ # Track management and scoring logic
├── trackers/ # Single and multi-target trackers
├── measurement.py # Measurement data structures
└── parameterManager.py # Parameter management
SingleTargetTracker
: Basic single-target tracker for testingJPDATracker
: Joint Probabilistic Data Association trackerMultiHypothesisTracker
: Multi-Hypothesis Tracker (⚠️ Currently not working)
The package provides two different approaches for multi-robot tracking:
-
DistributedJPDA
: Reprocessing approach - Uses a specialized distributed implementation of JPDA that reprocesses measurements when out-of-sequence measurements (OOSMs) arrive. This approach is specific to JPDA and handles temporal synchronization by recomputing association probabilities when late measurements are received. -
SynchronizedDistributedTracker
: Buffering approach - A generic wrapper that can work with any single-robot tracker (JPDA, MHT, etc.). It buffers measurements from multiple drones until all expected measurements for a time window arrive, then processes them synchronously. This approach is compatible with all tracker types but may introduce latency.
KFTrack
: Kalman filter for track state estimationKF3D_standalone
: Standalone 3D Kalman filter implementation
Configure tracking parameters in mtt_config.yaml
:
# Detection probabilities
PD: 0.6 # Probability of detection
PG: 1 # Probability of gating
FAR: 0.01 # False alarm rate
# Gating parameters
thresholdMahalanobis: 1.5 # Threshold for Mahalanobis gating
thresholdID: 0.1 # Threshold for ID gating
# Filter parameters
velocityDecayTime: 20.0 # Time constant for velocity decay in filter
offsetDecayTime: 30.0 # Time constant for offset decay in filter
# Track management
maximumTrackLength: None # Maximum track length kept (None = unlimited)
MN_del_tentative: 10 # Deletions to remove tentative track
MN_confirm_tentative: 15 # Detections to confirm tentative track
MN_del_confirmed: 18 # Deletions to remove confirmed track
MN_intervall: 20 # Total updates considered for M/N logic
# Score logic parameters
lambda: 0.90 # Forgetting factor (0-1, closer to 1 = slower forgetting)
score_del_confirmed: 0.05 # Score threshold for deletion
Tracker | Use Case | Computational Cost | Status |
---|---|---|---|
SingleTargetTracker |
Single target, testing | Low | ✅ Working |
JPDATracker |
Multiple targets | Medium | ✅ Working |
MultiHypothesisTracker |
Complex scenarios | High |
from multi_target_tracking.trackers import MultiHypothesisTracker
from multi_target_tracking.filters import KFTrack
from multi_target_tracking.gaters import MahalanobisGater
from multi_target_tracking.likelihoods import IdLikelihood
from multi_target_tracking.track import MNLogic
# Requires murty algorithm from: https://github.com/robot-perception-group/murty
# WARNING: Currently not functional
tracker = MultiHypothesisTracker(
filter_obj=KFTrack(),
gater=MahalanobisGater(),
likelihood=IdLikelihood(),
track_logic=MNLogic(),
max_hypotheses=30,
pruning_threshold=0.95
)
from multi_target_tracking.distributed_trackers import DistributedJPDA
from multi_target_tracking.filters import KFTrack
from multi_target_tracking.gaters import MahalanobisGater
from multi_target_tracking.likelihoods import MahalanobisLikelihood
from multi_target_tracking.track import MNLogic
# Reprocessing approach - handles OOSMs by recomputing associations
distributed_tracker = DistributedJPDA(
filter_obj=KFTrack(),
gater=MahalanobisGater(),
likelihood=MahalanobisLikelihood(),
track_logic=MNLogic(),
drone_id=1
)
# Process measurements from multiple drones
for timestamp, measurements, drone_id in measurement_data:
distributed_tracker.add_measurements(timestamp, measurements, drone_id)
tracks = distributed_tracker.tracks
from multi_target_tracking.distributed_trackers import SynchronizedDistributedTracker
from multi_target_tracking.trackers import JPDATracker
from multi_target_tracking.filters import KFTrack
from multi_target_tracking.gaters import MahalanobisGater
from multi_target_tracking.likelihoods import MahalanobisLikelihood
from multi_target_tracking.track import MNLogic
# Create base tracker (can be any tracker type)
base_tracker = JPDATracker(
filter_obj=KFTrack(),
gater=MahalanobisGater(),
likelihood=MahalanobisLikelihood(),
track_logic=MNLogic(),
drone_id=None # No specific drone ID for multi-drone processing
)
# Buffering approach - waits for measurements from all drones
num_drones = 3
synchronized_tracker = SynchronizedDistributedTracker(base_tracker, num_drones)
# Process measurements (will buffer until all drones report for time window)
for timestamp, measurements, drone_id in measurement_data:
synchronized_tracker.add_measurements(timestamp, measurements, drone_id)
tracks = synchronized_tracker.tracks
from multi_target_tracking import PosMeasurement
import numpy as np
# Position-only measurement
pos_meas = PosMeasurement(
timestamp=time,
position=np.array([x, y, z]),
covariance=cov_matrix,
id=measurement_id
)
Inherit from the appropriate base class:
- Filter:
BasicFilter
infilters/basic_filter.py
- Gater:
BasicGater
ingaters/basic_gater.py
- Likelihood:
BasicLikelihood
inlikelihoods/basic_likelihood.py
- Tracker:
BasicTracker
intrackers/basic_tracker.py
- Distributed Tracker:
BasicDistributedTracker
indistributed_trackers/basic_distributed_tracker.py
- Murty Algorithm: Integrates Jonatan Olofsson's C++ implementation via pybind11
- EHM Algorithm: Uses pyehm by Lyudmil Vladimirov as a dependency
GNU General Public License v3.0 - see the LICENSE file for details.
Current version: 0.1.0