Multi object tracking
This page contains advanced examples for the tno.quantum.problems.mot package.
Requirements
Install the following dependencies to run the examples below:
pip install tno.quantum.problems.mot
pip install ultralytics
Example: getting detections with ultralytics
Starting from a video file, first generate a detection file compatible with ultralytics. This can be done, for example, with a pre-trained YOLO model, as shown below
1import csv
2from ultralytics import YOLO
3
4model = YOLO("path/to/model")
5video_path = "path/to/video"
6detections_csv_path = "path/to/output.csv"
7
8# Run inference frame-by-frame
9results = model(
10 video_path,
11 stream=True, # important for video
12 conf=0.25,
13)
14
15with open(detections_csv_path, mode="w", newline="") as f:
16 writer = csv.writer(f)
17 for frame_idx, r in enumerate(results):
18 if r.boxes is None:
19 continue
20
21 for box in r.boxes:
22 cls_id = int(box.cls[0])
23 conf = float(box.conf[0])
24 x, y, w, h = box.xywhn[0].tolist()
25
26 writer.writerow(
27 [
28 frame_idx,
29 cls_id,
30 f"{x:.6f}",
31 f"{y:.6f}",
32 f"{w:.6f}",
33 f"{h:.6f}",
34 f"{conf:.6f}",
35 ]
36 )
Example: re-id module
The following example shows how to run the tracking algorithm of ultralytics and the re-id module on top to fix an ID switch.
1import importlib.resources
2import pandas as pd
3
4from ultralytics.trackers import BOTSORT
5from ultralytics.utils import YAML, IterableSimpleNamespace
6
7from tno.quantum.problems.mot import (
8 DetectionSequence,
9 ultralytics_track,
10 FlowReID,
11)
12from tno.quantum.problems.mot.dataset import (
13 make_gif_with_detections,
14)
15
16# Load detections from CSV file
17detections_csv_path = "path/to/detections.csv"
18detections = pd.read_csv(detections_csv_path, header=None)
19detections = DetectionSequence.from_dataframe(detections)
20
21# Run ultralytics tracking algorithm
22tracker_path = str(
23 importlib.resources.files("ultralytics.cfg") / "trackers" / "botsort.yaml"
24)
25cfg = IterableSimpleNamespace(**YAML.load(tracker_path))
26tracker = BOTSORT(cfg)
27detections = ultralytics_track(detections, tracker)
28
29# Select a snippet that contains an ID loss
30flow_reid_obj = FlowReID()
31first_frame, last_frame = flow_reid_obj.pick_sequences(detections)[0]
32detections_snippet = detections[first_frame:last_frame]
33reid_detections_snippet = flow_reid_obj.run_classic(detections_snippet)
34
35# Create visualization
36video_path = "path/to/video"
37make_gif_with_detections(
38 detections_snippet,
39 input_filename=video_path,
40 output_filename="before.gif",
41 fps=20,
42 first_frame=first_frame,
43)
44make_gif_with_detections(
45 reid_detections_snippet,
46 input_filename=video_path,
47 output_filename="after.gif",
48 fps=20,
49 first_frame=first_frame,
50)
This results in the following video snippets.
Instead of selecting a frame sequence manually, use the pick_sequences method to find frame sequences where an ID loss or ID switch is suspected.
1import importlib.resources
2
3import pandas as pd
4from ultralytics.trackers import BOTSORT
5from ultralytics.utils import YAML, IterableSimpleNamespace
6
7from tno.quantum.problems.mot import (
8 DetectionSequence,
9 FlowReID,
10 ultralytics_track,
11)
12from tno.quantum.problems.mot.dataset import (
13 make_video_with_detections,
14)
15
16# Load detections from CSV file
17detections_csv_path = "path/to/detections.csv"
18detections = pd.read_csv(detections_csv_path, header=None)
19detections = DetectionSequence.from_dataframe(detections)
20
21# Run ultralytics tracking algorithm; pick_sequences needs track IDs
22tracker_path = str(
23 importlib.resources.files("ultralytics.cfg") / "trackers" / "botsort.yaml"
24)
25cfg = IterableSimpleNamespace(**YAML.load(tracker_path))
26detections = ultralytics_track(detections, BOTSORT(cfg))
27
28# Pick sequences
29flow_reid_obj = FlowReID()
30sequences = flow_reid_obj.pick_sequences(detections)
31print(sequences)
32print(f"Found {len(sequences)} frame sequences for re-id.")
33
34# To run re-id continuously on each of the detected sequences, use
35# run_continuous_reid.
36reid_detections = flow_reid_obj.run_continuous_reid(detections)
37
38# Save the video after re-id
39make_video_with_detections(
40 reid_detections,
41 input_filename="path/to/video",
42 output_filename="after.avi",
43 fps=50,
44)