def __init__(self, model_spec: dict = DEFAULT_MODEL_SPEC, dt: float = 1 / 24, x0: Optional[Vector] = None, box0: Optional[Box] = None, max_staleness: float = 12.0, smooth_score_gamma: float = 0.8, smooth_feature_gamma: float = 0.9): self.id = str(uuid.uuid4()) self.model_spec = model_spec self.steps_alive = 1 self.steps_positive = 1 self.staleness = 0.0 self.max_staleness = max_staleness self.update_score_fn = exponential_moving_average_fn( smooth_score_gamma) self.update_feature_fn = exponential_moving_average_fn( smooth_feature_gamma) self.score = None self.feature = None logger.debug('creating new object tracker with %s and id %s' % (self.model_spec, self.id)) self.model = Model(dt=dt, **self.model_spec) if x0 is None: x0 = self.model.box_to_x(box0) self._tracker = get_single_object_tracker(model=self.model, x0=x0)
def __init__(self, model_spec: dict = DEFAULT_MODEL_SPEC, dt: float = 1 / 24, x0: Optional[Vector] = None, box0: Optional[Box] = None, max_staleness: float = 12.0): self.id = str(uuid.uuid4()) self.status = 'unconfirmed' self.model_spec = model_spec self.steps_alive = 1 self.steps_positive = 1 self.staleness = 0.0 self.max_staleness = max_staleness self.feature = None logger.debug('creating new object tracker with %s and id %s' % (self.model_spec, self.id)) self.model = Model(dt=dt, **self.model_spec) if x0 is None: x0 = self.model.box_to_x(box0) self._tracker = get_object_tracker(dt=dt, x0=x0, model=self.model)
def test_builders(): """ model 1 """ m1 = Model(0.1, 1, 2, 0, 2, r_var_pos=0.1, r_var_size=0.3, p_cov_p0=100.) assert m1.state_length == 6 assert m1.measurement_length == 4 F1 = m1.build_F() F1_exp = np.array([[1., 0.1, 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0.], [0., 0., 1., 0.1, 0., 0.], [0., 0., 0., 1., 0., 0.], [0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 0., 1.]]) assert_almost_equal(F1_exp, F1) H1 = m1.build_H() H1_exp = 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, 1]]) assert_almost_equal(H1_exp, H1) _ = m1.build_Q() R1 = m1.build_R() R1_exp = np.array([[0.1, 0, 0, 0], [0, 0.1, 0, 0.], [0, 0, 0.3, 0.], [0, 0, 0, 0.3]]) assert_almost_equal(R1, R1_exp) _ = m1.build_P() """ model 2 """ m2 = Model(0.1, 2, 1, 1, 1) F2 = m2.build_F() F2_exp = np.array([[1., 0.1, 0.005, 0., 0.], [0., 1., 0.1, 0., 0.], [0., 0., 1., 0., 0.], [0., 0., 0., 1., 0.1], [0., 0., 0., 0., 1.]]) assert_almost_equal(F2_exp, F2)
def __init__(self, model_kwargs: dict = DEFAULT_MODEL_SPEC, x0: Optional[Vector] = None, box0: Optional[Box] = None, **kwargs) -> None: super(KalmanTracker, self).__init__(**kwargs) self.model_kwargs: dict = model_kwargs self.model = Model(**self.model_kwargs) if x0 is None: x0 = self.model.box_to_x(box0) self._tracker: KalmanFilter = get_kalman_object_tracker( model=self.model, x0=x0)
def get_object_tracker(dt: float, model: Model, x0: Optional[Vector] = None): """ returns Kalman-based tracker based on a specified motion model spec. e.g. for spec = {'order_pos': 1, 'dim_pos': 2, 'order_size': 0, 'dim_size': 1} we expect the following setup: state x, x', y, y', w, h where x and y are centers of boxes w and h are width and height """ tracker = KalmanFilter(dim_x=model.state_length, dim_z=model.measurement_length) tracker.F = model.build_F() tracker.Q = model.build_Q() tracker.H = model.build_H() tracker.R = model.build_R() tracker.P = model.build_P() if x0 is not None: tracker.x = x0 return tracker
class KalmanTracker(SingleObjectTracker): """ A single object tracker using Kalman filter with specified motion model specification """ def __init__(self, model_kwargs: dict = DEFAULT_MODEL_SPEC, x0: Optional[Vector] = None, box0: Optional[Box] = None, **kwargs) -> None: super(KalmanTracker, self).__init__(**kwargs) self.model_kwargs: dict = model_kwargs self.model = Model(**self.model_kwargs) if x0 is None: x0 = self.model.box_to_x(box0) self._tracker: KalmanFilter = get_kalman_object_tracker( model=self.model, x0=x0) def _predict(self) -> None: self._tracker.predict() def _update_box(self, detection: Detection) -> None: z = self.model.box_to_z(detection.box) self._tracker.update(z) def box(self) -> Box: return self.model.x_to_box(self._tracker.x) def is_invalid(self) -> bool: try: has_nans = any(np.isnan(self._tracker.x)) return has_nans except Exception as e: logger.warning(f'invalid tracker - exception: {e}') return True
def test_box_to_z(): model = Model(0.1, 1, 2, 0, 2) box = [10, 10, 20, 20] z_exp = [15, 15, 10, 10] assert_almost_equal(model.box_to_z(box=box), z_exp) # size not matching dimensions box = [10, 10, 10, 20, 20, 20] try: # TODO cleanup model.box_to_z(box=box) raise except AssertionError: pass except Exception: raise # 3d position, 2d size model = Model(0.1, 1, 3, 1, 2) box = [10, 10, 0, 20, 20, 50] z = model.box_to_z(box) z_exp = [15, 15, 25, 10, 10] assert_almost_equal(z, z_exp)
class Tracker: def __init__(self, model_spec: dict = DEFAULT_MODEL_SPEC, dt: float = 1 / 24, x0: Optional[Vector] = None, box0: Optional[Box] = None, max_staleness: float = 12.0, smooth_score_gamma: float = 0.8, smooth_feature_gamma: float = 0.9): self.id = str(uuid.uuid4()) self.model_spec = model_spec self.steps_alive = 1 self.steps_positive = 1 self.staleness = 0.0 self.max_staleness = max_staleness self.update_score_fn = exponential_moving_average_fn( smooth_score_gamma) self.update_feature_fn = exponential_moving_average_fn( smooth_feature_gamma) self.score = None self.feature = None logger.debug('creating new object tracker with %s and id %s' % (self.model_spec, self.id)) self.model = Model(dt=dt, **self.model_spec) if x0 is None: x0 = self.model.box_to_x(box0) self._tracker = get_single_object_tracker(model=self.model, x0=x0) def predict(self): self.steps_alive += 1 self._tracker.predict() def update(self, detection: Detection): self.steps_positive += 1 # KF tracker update for position and size z = self.model.box_to_z(detection.box) self._tracker.update(z) self.score = self.update_score_fn(old=self.score, new=detection.score) self.feature = self.update_feature_fn(old=self.feature, new=detection.feature) # reduce the staleness of a tracker, faster than growth rate self.unstale(rate=3) def stale(self, rate: float = 1.0): self.staleness += 1 return self.staleness def unstale(self, rate: float = 2.0): self.staleness = max(0, self.staleness - rate) return self.staleness @property def is_stale(self) -> bool: return self.staleness >= self.max_staleness @property def is_invalid(self) -> bool: try: has_nans = any(np.isnan(self._tracker.x)) return has_nans except Exception as e: logger.warning('invalid tracker, exception: %s' % str(e)) return True @property def box(self): return self.model.x_to_box(self._tracker.x) def __repr__(self): fmt = "box: %s\tstaleness: %d" return fmt % (self.box, self.staleness)
class Tracker: def __init__(self, model_spec: dict = DEFAULT_MODEL_SPEC, dt: float = 1 / 24, x0: Optional[Vector] = None, box0: Optional[Box] = None, max_staleness: float = 12.0): self.id = str(uuid.uuid4()) self.status = 'unconfirmed' self.model_spec = model_spec self.steps_alive = 1 self.steps_positive = 1 self.staleness = 0.0 self.max_staleness = max_staleness self.feature = None logger.debug('creating new object tracker with %s and id %s' % (self.model_spec, self.id)) self.model = Model(dt=dt, **self.model_spec) if x0 is None: x0 = self.model.box_to_x(box0) self._tracker = get_object_tracker(dt=dt, x0=x0, model=self.model) def predict(self): self.steps_alive += 1 self._tracker.predict() def update(self, detection: Detection): self.steps_positive += 1 # KF tracker update for position and size z = self.model.box_to_z(detection.box) self._tracker.update(z) if detection.feature is not None: self.update_feature(detection.feature) # reduce the staleness of a tracker, faster than growth rate self.unstale(rate=3) def update_feature(self, feature: Vector, alpha: float = 0.1): if self.feature is None: self.feature = np.array(feature) else: self.feature = alpha * np.array(feature) + (1 - alpha) * self.feature def stale(self, rate: float = 1.0): self.staleness += 1 return self.staleness def unstale(self, rate: float = 2.0): self.staleness = max(0, self.staleness - rate) return self.staleness @property def is_stale(self): return self.staleness >= self.max_staleness @property def is_invalid(self): try: has_nans = any(np.isnan(self._tracker.x)) return has_nans except Exception as e: logger.trace('invalid tracker, exception: %s' % str(e)) return True @property def box(self): return self.model.x_to_box(self._tracker.x) def __repr__(self): fmt = "(box) %s\n (status) %s\n(staleness) %d" return fmt % (self.box, self.status, self.staleness)
def test_state_to_observation_converters(): # 2d boxes model = Model(0.1, 1, 2, 0, 2) # xmin ymin xmax ymax box = [10, 10, 20, 30] x = model.box_to_x(box) assert_almost_equal(np.array([15., 0., 20., 0., 10., 20.]), x) box_ret = model.x_to_box(x) assert_almost_equal(box_ret, box) # 3d boxes model = Model(0.1, 1, 3, 0, 3) # xmin ymin zmin xmax ymax zmax box = [10, 10, 10, 20, 30, 40] x = model.box_to_x(box) assert_almost_equal(np.array([15., 0., 20., 0., 25., 0., 10., 20., 30.]), x) box_ret = model.x_to_box(x) assert_almost_equal(box_ret, box) # 2d position, 3d boxes (z dimension is only about length) model = Model(0.1, 1, 2, 0, 3) box = [10, 10, -25, 20, 30, 25] x = model.box_to_x(box) x_exp = np.array([15., 0., 20., 0., 10., 20., 50.]) assert_almost_equal(x_exp, x) box_ret = model.x_to_box(x) assert_almost_equal(box_ret, box)