Skip to content

Commit

Permalink
remove status, add track score, v0.0.9
Browse files Browse the repository at this point in the history
  • Loading branch information
wmuron committed Feb 28, 2021
1 parent 54604b7 commit bdace1c
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 67 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,4 @@ Feel free to tune the parameter of Q and R matrix builders to better fit your us
## References, papers, ideas and acknowledgements
- https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python/
- http://elvera.nue.tu-berlin.de/files/1517Bochinski2017.pdf
- https://arxiv.org/abs/1602.00763
- https://arxiv.org/abs/1602.00763
5 changes: 3 additions & 2 deletions examples/2d_multi_object_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ def demo_tracking_visualization(num_steps: int = 1000, num_objects: int = 10):
active_tracks = tracker.step(detections=detections)

for track in active_tracks:
score = track.score if track.score is not None else -1
img = draw_rectangle(img, track.box, color=(10, 10, 220), thickness=5)
img = draw_text(img, track.id, above_box=track.box)
img = draw_text(img, f'{track.id[:8]}... ({score:.2f})', above_box=track.box)

for det in detections:
img = draw_rectangle(img, det.box, color=(10, 220, 20), thickness=2)
img = draw_rectangle(img, det.box, color=(10, 220, 20), thickness=1)

cv2.imshow('preview', img)
# stop the demo by pressing q
Expand Down
19 changes: 9 additions & 10 deletions examples/webcam_face_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from urllib.request import urlretrieve

import cv2
from motpy import Detection, MultiObjectTracker, NpImage
from motpy import Detection, MultiObjectTracker, NpImage, Box
from motpy.core import setup_logger
from motpy.detector import BaseObjectDetector
from motpy.testing_viz import draw_detection, draw_track
Expand All @@ -15,7 +15,7 @@
"""

logger = setup_logger(__name__, is_main=True)
logger = setup_logger(__name__, 'DEBUG', is_main=True)


WEIGHTS_URL = 'https://github.com/opencv/opencv_3rdparty/raw/dnn_samples_face_detector_20170830/res10_300x300_ssd_iter_140000.caffemodel'
Expand All @@ -30,7 +30,7 @@ def __init__(self,
weights_path: str = WEIGHTS_PATH,
config_url: str = CONFIG_URL,
config_path: str = CONFIG_PATH,
conf_threshold: float = 0.5):
conf_threshold: float = 0.5) -> None:
super(FaceDetector, self).__init__()

if not os.path.isfile(weights_path) or not os.path.isfile(config_path):
Expand All @@ -43,23 +43,23 @@ def __init__(self,
# specify detector hparams
self.conf_threshold = conf_threshold

def process_image(self, image: NpImage) -> Sequence[NpImage]:
def process_image(self, image: NpImage) -> Sequence[Detection]:
blob = cv2.dnn.blobFromImage(image, 1.0, (300, 300), [104, 117, 123], False, False)
self.net.setInput(blob)
detections = self.net.forward()

# convert output from OpenCV detector to tracker expected format [xmin, ymin, xmax, ymax]
bboxes = []
out_detections = []
for i in range(detections.shape[2]):
confidence = detections[0, 0, i, 2]
if confidence > self.conf_threshold:
xmin = int(detections[0, 0, i, 3] * image.shape[1])
ymin = int(detections[0, 0, i, 4] * image.shape[0])
xmax = int(detections[0, 0, i, 5] * image.shape[1])
ymax = int(detections[0, 0, i, 6] * image.shape[0])
bboxes.append([xmin, ymin, xmax, ymax])

return bboxes
out_detections.append(Detection(box=[xmin, ymin, xmax, ymax], score=confidence))
return out_detections


def run():
Expand All @@ -84,8 +84,7 @@ def run():
frame = cv2.resize(frame, dsize=None, fx=0.5, fy=0.5)

# run face detector on current frame
bboxes = face_detector.process_image(frame)
detections = [Detection(box=bbox) for bbox in bboxes]
detections = face_detector.process_image(frame)
logger.debug(f'detections: {detections}')

tracker.step(detections)
Expand Down
16 changes: 6 additions & 10 deletions motpy/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@
Vector = np.ndarray

# Track is meant as an output from the object tracker
Track = collections.namedtuple('Track', 'id box')
Track = collections.namedtuple('Track', 'id box score')

# numpy/opencv image alias
NpImage = np.ndarray


class Detection:
# Detection is to be an input the the tracker
def __init__(
self,
box: Box,
Expand All @@ -33,10 +32,7 @@ def __init__(
self.feature = feature

def __repr__(self):
fmt = "(detection: box=%s, score=%s, feature=%s)"
return fmt % (str(self.box),
str(self.score) or 'none',
str(self.feature) or 'none')
return f'Detection(box={self.box}, score={self.score:.5f}, feature={self.feature})'


""" utils """
Expand All @@ -51,17 +47,17 @@ def setup_logger(name: str,
if level is None:
level = os.getenv(envvar_name)
if level is None:
print(f'[{name}] fallback to INFO log_level; set {envvar_name} envvar to override')
level = 'INFO'
else:
print(f'[{name}] envvar {envvar_name} sets log level to {level}')

level_val = logging.getLevelName(level)

if is_main:
logging.basicConfig(stream=sys.stdout, level=level_val, format=LOG_FORMAT)

logger = logging.getLogger(name)
logger.setLevel(level_val)
logger.addHandler(logging.NullHandler())

if is_main:
logging.basicConfig(stream=sys.stdout, level=level_val, format=LOG_FORMAT)

return logger
1 change: 0 additions & 1 deletion motpy/detector.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from typing import Sequence

import numpy as np
from motpy.core import NpImage
from motpy.tracker import Detection

Expand Down
8 changes: 4 additions & 4 deletions motpy/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ def calculate_iou(bboxes1, bboxes2, dim: int = 2):
coords_b1 = np.split(bboxes1, 2 * dim, axis=1)
coords_b2 = np.split(bboxes2, 2 * dim, axis=1)

coords_tl, coords_br = dict(), dict() # tl and br points
coords = np.zeros(shape=(2, dim, bboxes1.shape[0], bboxes2.shape[0]))
val_inter, val_b1, val_b2 = 1.0, 1.0, 1.0
for d in range(dim):
coords_tl[d] = np.maximum(coords_b1[d], np.transpose(coords_b2[d]))
coords_br[d] = np.minimum(coords_b1[d + dim], np.transpose(coords_b2[d + dim]))
coords[0, d] = np.maximum(coords_b1[d], np.transpose(coords_b2[d])) # top-left
coords[1, d] = np.minimum(coords_b1[d + dim], np.transpose(coords_b2[d + dim])) # bottom-right

val_inter *= np.maximum(coords_br[d] - coords_tl[d], 0)
val_inter *= np.maximum(coords[1, d] - coords[0, d], 0)
val_b1 *= coords_b1[d + dim] - coords_b1[d]
val_b2 *= coords_b2[d + dim] - coords_b2[d]

Expand Down
7 changes: 2 additions & 5 deletions motpy/model.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@

from enum import Enum

import numpy as np
from filterpy.common import Q_discrete_white_noise
from filterpy.kalman import KalmanFilter
from motpy.core import Box, Detection, Track, Vector
from motpy.metrics import angular_similarity, calculate_iou
from scipy.linalg import block_diag

from motpy.core import Box, Vector

""" The list of model presets below is not complete, more reasonable
options will be added in the future """
Expand Down Expand Up @@ -140,7 +137,7 @@ def box_to_z(self, box: Box) -> Vector:

def box_to_x(self, box: Box) -> Vector:
""" box is expected to be in [xmin, ymin, zmin, ..., xmax, ymax, zmax, ...] format
for 2d1ord+2d0ord case returns np.array([cx, 0, 0, cy, 0, 0, w, h]) """
for 2d-1ord+2d-0ord case returns np.array([cx, 0, 0, cy, 0, 0, w, h]) """
x = np.zeros((self.state_length,))
x[self.z_in_x_idxs] = self.box_to_z(box)
return x
Expand Down
6 changes: 2 additions & 4 deletions motpy/testing.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import math
import random

import numpy as np

from motpy.core import Detection

CANVAS_SIZE = 1000
Expand Down Expand Up @@ -73,11 +71,11 @@ def detections(self, step: int):
self.disappear_steps -= 1

# wrap boxes and features as detections
det_gt = Detection(box=box_gt, score=1.0, feature=self.color)
det_gt = Detection(box=box_gt, score=1., feature=self.color)

feature_pred = [random.gauss(0, 5) + v for v in self.color]
det_pred = Detection(box=box_pred,
score=random.random() / 2 + 0.5,
score=random.uniform(0.5, 1.),
feature=feature_pred)

return det_gt, det_pred
Expand Down
Loading

0 comments on commit bdace1c

Please sign in to comment.