Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code Quality Improvements #4

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.idea
.coverage
htmlcov/
MOT17Labels/
*.zip
outputs/
MOT17/
venv/
17 changes: 7 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,19 @@ See the [arXiv preprint](http://arxiv.org/abs/2103.04147) for more information.
<img align="center" width="48%" src="https://github.com/mhnasseri/sort_oh/blob/main/Video_MOT17-09-SDP.gif">
</p>

## Dependencies

The code is compatible with Python 3. The following dependencies are
needed to run the tracker:

* NumPy
* sklearn
* OpenCV
* filterpy

## Installation

First, clone the repository:
```
git clone https://github.com/mhnasseri/sort_oh.git
```

Install the dependencies using

```
pip install -r requirements.txt
```

Then, download the MOT17 dataset from [here](https://motchallenge.net/data/MOT17/).

In order to results on MOT16 be comparable with the results of SORT and DeepSORT algorithms, the private detection taken from the following paper:
Expand Down
315 changes: 200 additions & 115 deletions libs/association.py

Large diffs are not rendered by default.

26 changes: 12 additions & 14 deletions libs/calculate_cost.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
import numpy as np


@jit
# @jit
def iou(bb_det, bb_trk):
"""
Computes IOU (Intersection Over Union) between two bounding boxes in the form [x1,y1,x2,y2]
"""
Computes IOU (Intersection Over Union) between two bounding boxes in the form [x1,y1,x2,y2]
"""
xx1 = np.maximum(bb_det[0], bb_trk[0])
xx2 = np.minimum(bb_det[2], bb_trk[2])
w = np.maximum(0., xx2 - xx1)
Expand Down Expand Up @@ -72,7 +72,7 @@ def iou_ext_sep(bb_det, bb_trk, ext_w, ext_h):
return o


@jit
# @jit
def outside(trk, img_s):
"""
Computes how many percent of trk is placed outside of img_s
Expand All @@ -92,7 +92,7 @@ def outside(trk, img_s):
return out_a / area


@jit
# @jit
def area_cost(bb_det, bb_trk):
"""
This cost compute the difference between bounding box sizes
Expand Down Expand Up @@ -124,13 +124,13 @@ def area_cost(bb_det, bb_trk):
return ratio - 1


@jit
# @jit
# intersection over union with limit on area
def iou_la(bb_det, bb_trk):
"""
Computes IOU (Intersection Over Union) between two bounding boxes in the form [x1,y1,x2,y2]
with limitation on percentage of change of area
"""
Computes IOU (Intersection Over Union) between two bounding boxes in the form [x1,y1,x2,y2]
with limitation on percentage of change of area
"""
xx1 = np.maximum(bb_det[0], bb_trk[0])
xx2 = np.minimum(bb_det[2], bb_trk[2])
w = np.maximum(0., xx2 - xx1)
Expand All @@ -153,11 +153,11 @@ def iou_la(bb_det, bb_trk):
return o


@jit
# @jit
def ios(bb_first, bb_second):
"""
Computes IOS (Intersection Over Second Bounding Box) between two bounding boxes in the form [x1,y1,x2,y2]
"""
Computes IOS (Intersection Over Second Bounding Box) between two bounding boxes in the form [x1,y1,x2,y2]
"""
xx1 = np.maximum(bb_first[0], bb_second[0])
yy1 = np.maximum(bb_first[1], bb_second[1])
xx2 = np.minimum(bb_first[2], bb_second[2])
Expand Down Expand Up @@ -208,5 +208,3 @@ def cal_ios_matrix(trackers):
if t2 != t1:
ios_matrix[t1, t2] = ios(trk1, trk2)
return ios_matrix


8 changes: 4 additions & 4 deletions libs/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

def bbox_to_z(bbox):
"""
Takes a bounding box in the form [x1,y1,x2,y2] and returns z in the form
Takes a bounding box in the form [x1,y1,x2,y2] and returns z in the form
[x,y,s,r] where x,y is the centre of the box and s is the scale/area and r is
the aspect ratio
"""
"""
w = bbox[2] - bbox[0]
h = bbox[3] - bbox[1]
x = bbox[0] + w / 2.
Expand All @@ -18,9 +18,9 @@ def bbox_to_z(bbox):

def x_to_bbox(x, score=None):
"""
Takes a bounding box in the centre form [x,y,s,r] and returns it in the form
Takes a bounding box in the centre form [x,y,s,r] and returns it in the form
[x1,y1,x2,y2] where x1,y1 is the top left and x2,y2 is the bottom right
"""
"""
w = np.sqrt(x[2] * x[3])
h = x[2] / w
if score is None:
Expand Down
68 changes: 55 additions & 13 deletions libs/kalman_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,66 @@

class KalmanBoxTracker(object):
"""
This class represents the internel state of individual tracked objects observed as bbox.
"""
This class represents the internal state of individual tracked objects observed as bbox.
"""

count = 0

def __init__(self, bbox, init_mode, bbox_before):
"""
Initialises a tracker using initial bounding box.
"""
Initialises a tracker using initial bounding box.
"""
# define constant velocity model
# (u, v, s, r, u_dot, v_dot, s_dot) -> (u,v): location center, s: area, r: aspect ratio
# dim_x: Number of state variables for the Kalman filter
# dim_z: Number of of measurement inputs a.k.a observations
self.kf = KalmanFilter(dim_x=7, dim_z=4)
# state transition matrix
self.kf.F = np.array(
[[1, 0, 0, 0, 1, 0, 0], [0, 1, 0, 0, 0, 1, 0], [0, 0, 1, 0, 0, 0, 1], [0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]])
[[1, 0, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 0, 1],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 1]])
# measurement function a.k.a stateProjection
self.kf.H = np.array(
[[1, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0]])
[[1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0]])

if init_mode == 0:
# Measurement noise matrix
self.kf.R[2:, 2:] *= 1. # 10.

# covariance matrix
self.kf.P[4:, 4:] *= 10. # 1000. # give high uncertainty to the unobservable initial velocities
self.kf.P *= 10.

# Process uncertainty/noise
self.kf.Q[-1, -1] *= 0.01
self.kf.Q[4:, 4:] *= 0.01

# filter state estimate
self.kf.x[:4] = convert.bbox_to_z(bbox)

elif init_mode == 1:
# Measurement noise matrix
self.kf.R[2:, 2:] *= 1.

# covariance matrix
self.kf.P[4:, 4:] *= 10. # give high uncertainty to the unobservable initial velocities
# self.kf.P *= 10.

# Process uncertainty/noise
self.kf.Q[-1, -1] *= 0.01
self.kf.Q[4:, 4:] *= 0.01

state_before = convert.bbox_to_z(bbox_before)
state = convert.bbox_to_z(bbox)
# filter state estimate
self.kf.x[:4] = state
self.kf.x[4:] = state[0:3] - state_before[0:3]

Expand All @@ -51,8 +78,8 @@ def __init__(self, bbox, init_mode, bbox_before):

def update(self, bbox, isz):
"""
Updates the state vector with observed bbox.
"""
Updates the state vector with observed bbox.
"""
self.time_since_update = 0
if isz == 0:
# decrease area change ratio
Expand All @@ -64,18 +91,33 @@ def update(self, bbox, isz):

def predict(self):
"""
Advances the state vector and returns the predicted bounding box estimate.
"""
Advances the state vector and returns the predicted bounding box estimate.
"""
# to prevent area become negative after prediction, make zero the rate of area change
if (self.kf.x[6] + self.kf.x[2]) <= 0:
self.kf.x[6] *= 0.0
self.kf.predict()
self.age += 1
self.time_since_update += 1

return convert.x_to_bbox(self.kf.x)

def get_state(self):
"""
Returns the current bounding box estimate.
"""
Returns the current bounding box estimate.
"""
return convert.x_to_bbox(self.kf.x)

def to_json(self):
return {
"time_since_observed": self.time_since_observed,
"confidence": self.confidence if isinstance(self.confidence, float) or isinstance(self.confidence, int) else float(self.confidence.tolist()[0]),
"age": self.age,
"get_state": self.get_state().tolist(),
"time_since_update": self.time_since_update,
"id": self.id,
"kf": {
"x": self.kf.x.tolist(),
"covariance": self.kf.P.tolist()
}
}
Loading