Safemotion Lib
Loading...
Searching...
No Matches
kalman_filter.py
Go to the documentation of this file.
1import numpy as np
2import scipy.linalg
3
4class KalmanFilter(object):
5 """A simple Kalman filter for tracking bounding boxes in image space.
6
7 The implementation is referred to https://github.com/nwojke/deep_sort.
8 """
9 # chi2inv95 = {
10 # 1: 3.8415,
11 # 2: 5.9915,
12 # 3: 7.8147,
13 # 4: 9.4877,
14 # 5: 11.070,
15 # 6: 12.592,
16 # 7: 14.067,
17 # 8: 15.507,
18 # 9: 16.919
19 # }
20
21 def __init__(self,):
22 # self.center_only = center_only
23 # if self.center_only:
24 # self.gating_threshold = self.chi2inv95[2]
25 # else:
26 # self.gating_threshold = self.chi2inv95[4]
27
28 ndim, dt = 4, 1.
29
30 # Create Kalman filter model matrices.
31 self._motion_mat = np.eye(2 * ndim, 2 * ndim)
32 for i in range(ndim):
33 self._motion_mat[i, ndim + i] = dt
34 self._update_mat = np.eye(ndim, 2 * ndim)
35
36 # Motion and observation uncertainty are chosen relative to the current
37 # state estimate. These weights control the amount of uncertainty in
38 # the model. This is a bit hacky.
39 self._std_weight_position = 1. / 20
40 self._std_weight_velocity = 1. / 160
41
42 def initiate(self, measurement):
43 """Create track from unassociated measurement.
44
45 Args:
46 measurement (ndarray): Bounding box coordinates (x, y, a, h) with
47 center position (x, y), aspect ratio a, and height h.
48
49 Returns:
50 (ndarray, ndarray): Returns the mean vector (8 dimensional) and
51 covariance matrix (8x8 dimensional) of the new track.
52 Unobserved velocities are initialized to 0 mean.
53 """
54 mean_pos = measurement
55 mean_vel = np.zeros_like(mean_pos)
56 mean = np.r_[mean_pos, mean_vel]
57
58 std = [
59 2 * self._std_weight_position * measurement[3],
60 2 * self._std_weight_position * measurement[3], 1e-2,
61 2 * self._std_weight_position * measurement[3],
62 10 * self._std_weight_velocity * measurement[3],
63 10 * self._std_weight_velocity * measurement[3], 1e-5,
64 10 * self._std_weight_velocity * measurement[3]
65 ]
66 covariance = np.diag(np.square(std))
67 return mean, covariance
68
69 def predict(self, mean, covariance):
70 """Run Kalman filter prediction step.
71
72 Args:
73 mean (ndarray): The 8 dimensional mean vector of the object
74 state at the previous time step.
75
76 covariance (ndarray): The 8x8 dimensional covariance matrix
77 of the object state at the previous time step.
78
79 Returns:
80 (ndarray, ndarray): Returns the mean vector and covariance
81 matrix of the predicted state. Unobserved velocities are
82 initialized to 0 mean.
83 """
84 std_pos = [
85 self._std_weight_position * mean[3],
86 self._std_weight_position * mean[3], 1e-2,
87 self._std_weight_position * mean[3]
88 ]
89 std_vel = [
90 self._std_weight_velocity * mean[3],
91 self._std_weight_velocity * mean[3], 1e-5,
92 self._std_weight_velocity * mean[3]
93 ]
94 motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))
95
96 mean = np.dot(self._motion_mat, mean)
97 covariance = np.linalg.multi_dot(
98 (self._motion_mat, covariance, self._motion_mat.T)) + motion_cov
99
100 return mean, covariance
101
102 def project(self, mean, covariance):
103 """Project state distribution to measurement space.
104
105 Args:
106 mean (ndarray): The state's mean vector (8 dimensional array).
107 covariance (ndarray): The state's covariance matrix (8x8
108 dimensional).
109
110 Returns:
111 (ndarray, ndarray): Returns the projected mean and covariance
112 matrix of the given state estimate.
113 """
114 std = [
115 self._std_weight_position * mean[3],
116 self._std_weight_position * mean[3], 1e-1,
117 self._std_weight_position * mean[3]
118 ]
119 innovation_cov = np.diag(np.square(std))
120
121 mean = np.dot(self._update_mat, mean)
122 covariance = np.linalg.multi_dot(
123 (self._update_mat, covariance, self._update_mat.T))
124 return mean, covariance + innovation_cov
125
126 def update(self, mean, covariance, measurement):
127 """Run Kalman filter correction step.
128
129 Args:
130 mean (ndarray): The predicted state's mean vector (8 dimensional).
131 covariance (ndarray): The state's covariance matrix (8x8
132 dimensional).
133 measurement (ndarray): The 4 dimensional measurement vector
134 (x, y, a, h), where (x, y) is the center position, a the
135 aspect ratio, and h the height of the bounding box.
136
137
138 Returns:
139 (ndarray, ndarray): Returns the measurement-corrected state
140 distribution.
141 """
142 projected_mean, projected_cov = self.project(mean, covariance)
143
144 chol_factor, lower = scipy.linalg.cho_factor(
145 projected_cov, lower=True, check_finite=False)
146 kalman_gain = scipy.linalg.cho_solve((chol_factor, lower),
147 np.dot(covariance,
148 self._update_mat.T).T,
149 check_finite=False).T
150 innovation = measurement - projected_mean
151
152 new_mean = mean + np.dot(innovation, kalman_gain.T)
153 new_covariance = covariance - np.linalg.multi_dot(
154 (kalman_gain, projected_cov, kalman_gain.T))
155 return new_mean, new_covariance
update(self, mean, covariance, measurement)
project(self, mean, covariance)
predict(self, mean, covariance)
initiate(self, measurement)