Skip to content

Commit 04be838

Browse files
committed
release 0.0.7
1 parent 45becda commit 04be838

File tree

9 files changed

+55
-36
lines changed

9 files changed

+55
-36
lines changed

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ clean:
2121
autoflake --in-place --remove-unused-variables ./motpy/*.py ./tests/*.py
2222

2323
check:
24-
mypy --ignore-missing-imports motpy
24+
mypy --ignore-missing-imports motpy
25+
26+
demo-mot16:
27+
# note it requires downloading MOT16 dataset before running
28+
python examples/mot16_challange.py --dataset_root=~/Downloads/MOT16 --seq_id=11

README.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,6 @@ for step in range(10):
6161

6262
## Things to do
6363

64-
TODO temporary:
65-
- allow passing model_kwargs??
66-
- model_mapping enable autocompletion,
67-
- add example on the highway, vehicles maybe pedestrians
68-
69-
70-
7164
- [x] Initial version
7265
- [ ] Documentation
7366
- [ ] Performance optimization

examples/2d_multi_object_tracking.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import cv2
33

44
import motpy
5-
from motpy import MultiObjectTracker
5+
from motpy import MultiObjectTracker, ModelPreset
66
from motpy.testing_viz import draw_rectangle, draw_text, image_generator
77

88
motpy.set_log_level('DEBUG')
@@ -20,7 +20,7 @@ def demo_tracking_visualization(num_steps: int = 1000, num_objects: int = 10):
2020
dt = 1 / 24
2121
tracker = MultiObjectTracker(
2222
dt=dt,
23-
model_spec={'order_pos': 2, 'dim_pos': 2, 'order_size': 0, 'dim_size': 2},
23+
model_spec=ModelPreset.constant_acceleration_and_static_box_size_2d.value,
2424
active_tracks_kwargs={'min_steps_alive': 2, 'max_staleness': 6},
2525
tracker_kwargs={'max_staleness': 12})
2626

examples/mot16_challange.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@
1717
MOT16 tracking demo
1818
1919
Usage:
20-
python examples/mot16_challange.py --dataset_root ~/Downloads/MOT16 --seq_id 11
20+
python examples/mot16_challange.py --dataset_root=~/Downloads/MOT16 --seq_id=11
2121
2222
Note: this is just a demo, the script does not evaluate the tracking on MOT16 dataset.
23+
Also, since provided by MOT16 `predictions` do not represent (IMO) the current state
24+
of modern detectors, the demo utilizes ground truth + noise as input to the tracker;
25+
feel free to use `sel=det` to check the 'real' MOT16 predictions, but keep in mind that
26+
tracker is not optimized at all for such noisy predictions.
2327
2428
"""
2529

@@ -37,6 +41,7 @@ def read_video_frame(directory, frame_idx):
3741

3842

3943
def read_detections(path, drop_detection_prob: float = 0.0, add_detection_noise: float = 0.0):
44+
""" parses and converts MOT16 benchmark annotations to known [xmin, ymin, xmax, ymax] format """
4045
path = os.path.expanduser(path)
4146
logger.debug('reading detections from %s' % path)
4247
if not os.path.isfile(path):
@@ -70,13 +75,15 @@ def get_miliseconds():
7075

7176
def run(
7277
dataset_root: str,
73-
fps=30,
78+
fps: float = 30.0,
7479
split: str = 'train',
75-
seq_id='04',
76-
sel='gt',
80+
seq_id: str = '04',
81+
sel: str = 'gt',
7782
drop_detection_prob: float = 0.1,
7883
add_detection_noise: float = 5.0):
84+
""" parses detections, loads frames, runs tracking and visualizes the tracked objects """
7985

86+
dataset_root = os.path.expanduser(dataset_root)
8087
if not os.path.isdir(dataset_root):
8188
logger.error('%s does not exist' % dataset_root)
8289
exit(-1)
@@ -97,32 +104,43 @@ def run(
97104

98105
tracker = MultiObjectTracker(
99106
dt=1 / fps, tracker_kwargs={'max_staleness': 15},
100-
model_spec='2d_constant_acceleration+static_box_size')
101-
102-
# TODO cleanup
103-
tracker.matching_fn.min_iou = 0.25
107+
model_spec='constant_acceleration_and_static_box_size_2d',
108+
matching_fn_kwargs={'min_iou': 0.25})
104109

105110
# tracking loop
106111
while True:
107-
frame_idx, detections = next(dets_gen)
112+
# read detections for a given frame
113+
try:
114+
frame_idx, detections = next(dets_gen)
115+
except Exception as e:
116+
logger.warning('finished reading the sequence')
117+
logger.trace(f'exception: {e}')
118+
break
119+
120+
# read the frame for a given index
108121
frame = read_video_frame(frames_dir, frame_idx)
109122
if frame is None:
110123
continue
111124

125+
# provide the MOT tracker with predicted detections
112126
t1 = get_miliseconds()
113127
active_tracks = tracker.step(detections)
114128
ms_elapsed = get_miliseconds() - t1
115129
logger.debug('step duration: %dms' % ms_elapsed)
116130

131+
# visualize predictions and tracklets
117132
for det in detections:
118133
draw_detection(frame, det)
119134

120135
for track in active_tracks:
121136
draw_track(frame, track)
122137

123138
cv2.imshow('preview', frame)
139+
140+
# stop execution on q
124141
key = cv2.waitKey(int(1000 / fps))
125142
if key == ord('q'):
143+
logger.info('early stopping')
126144
break
127145

128146

motpy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
from .tracker import MultiObjectTracker, MatchingFunction, BasicMatchingFunction
2-
from .model import Model, MODELS_MAPPING
2+
from .model import Model, ModelPreset
33
from .core import Box, Detection, Track, set_log_level

motpy/model.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2+
from enum import Enum
3+
24
import numpy as np
35
from filterpy.common import Q_discrete_white_noise
46
from filterpy.kalman import KalmanFilter
@@ -8,17 +10,17 @@
810
from motpy.core import Box, Detection, Track, Vector
911
from motpy.metrics import angular_similarity, calculate_iou
1012

13+
1114
""" The list of model presets below is not complete, more reasonable
1215
options will be added in the future """
1316

14-
MODELS_MAPPING = {
15-
'2d_constant_velocity+static_box_size':
16-
{'order_pos': 1, 'dim_pos': 2,
17-
'order_size': 0, 'dim_size': 2},
18-
'2d_constant_acceleration+static_box_size':
19-
{'order_pos': 2, 'dim_pos': 2,
20-
'order_size': 0, 'dim_size': 2}
21-
}
17+
18+
class ModelPreset(Enum):
19+
constant_velocity_and_static_box_size_2d = {'order_pos': 1, 'dim_pos': 2,
20+
'order_size': 0, 'dim_size': 2}
21+
22+
constant_acceleration_and_static_box_size_2d = {'order_pos': 2, 'dim_pos': 2,
23+
'order_size': 0, 'dim_size': 2}
2224

2325

2426
def _base_dim_block(dt: float, order: int = 1):

motpy/tracker.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from motpy.core import Box, Detection, Track, Vector
1010
from motpy.metrics import angular_similarity, calculate_iou
11-
from motpy.model import MODELS_MAPPING, Model
11+
from motpy.model import ModelPreset, Model
1212

1313

1414
def get_object_tracker(dt: float, model: Model, x0: Optional[Vector] = None):
@@ -34,7 +34,7 @@ def get_object_tracker(dt: float, model: Model, x0: Optional[Vector] = None):
3434
return tracker
3535

3636

37-
DEFAULT_MODEL_SPEC = MODELS_MAPPING['2d_constant_velocity+static_box_size']
37+
DEFAULT_MODEL_SPEC = ModelPreset.constant_velocity_and_static_box_size_2d.value
3838

3939

4040
class Tracker:
@@ -210,6 +210,7 @@ def __init__(self, dt: float,
210210
model_spec: Union[str, dict] = DEFAULT_MODEL_SPEC,
211211
matching_fn: Optional[MatchingFunction] = None,
212212
tracker_kwargs: dict = None,
213+
matching_fn_kwargs: dict = None,
213214
active_tracks_kwargs: dict = None):
214215
"""
215216
model_spec specifies the dimension and order for position and size of the object
@@ -224,15 +225,16 @@ def __init__(self, dt: float,
224225

225226
if isinstance(model_spec, dict):
226227
self.model_spec = model_spec
227-
elif isinstance(model_spec, str) and model_spec in MODELS_MAPPING:
228-
self.model_spec = MODELS_MAPPING[model_spec]
228+
elif isinstance(model_spec, str) and model_spec in ModelPreset.__members__:
229+
self.model_spec = ModelPreset[model_spec].value
229230
else:
230231
raise NotImplementedError('unsupported motion model %s' % str(model_spec))
231232
logger.trace('using model spec: %s' % str(self.model_spec))
232233

233234
self.matching_fn = matching_fn
235+
self.matching_fn_kwargs = matching_fn_kwargs if matching_fn_kwargs is not None else {}
234236
if self.matching_fn is None:
235-
self.matching_fn = BasicMatchingFunction()
237+
self.matching_fn = BasicMatchingFunction(**self.matching_fn_kwargs)
236238

237239
# kwargs to be passed to each single object tracker
238240
self.tracker_kwargs = tracker_kwargs if tracker_kwargs is not None else {}

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ autoflake
99
mypy
1010
# for testing and demo requirements below are necessary
1111
pytest
12+
fire
1213
opencv-python
13-
1414
# installation of opencv-python might be troublesome on Raspbian, hence I've left it out
1515
# from package requirements. If you really need demos, refer to link below for installation
1616
# instractions: https://blog.piwheels.org/new-opencv-builds-including-opencv-4-x/

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
setup(
44
name='motpy',
5-
version='0.0.6',
5+
version='0.0.7',
66
url='https://github.com/wmuron/motpy.git',
7-
download_url='https://github.com/wmuron/motpy/releases/tag/v0.0.6-alpha',
7+
download_url='https://github.com/wmuron/motpy/releases/tag/v0.0.7-alpha',
88
author='Wiktor Muron',
99
author_email='[email protected]',
1010
description='Library for track-by-detection multi object tracking implemented in python',

0 commit comments

Comments
 (0)