车辆计数

DeepSort学习笔记

2020-09-07  本文已影响0人  _从前从前_

DeepSort学习笔记

deepsort作为多目标跟踪的经典算法,相信每个入门MOT领域的人都是从deepsort开始,网上有大量的学习教程,但是相比别人喂我还是更喜欢自己吃。deepsort的代码是典型的面向对象的编程思想,代码优雅简洁,注释多,可以精读学习。为了防止以后遗忘,特地将自己的学习感悟记录下来。

需要掌握的先验知识

deepsort的综合性很强,涉及的相关算法很多,以下列出一些主要的算法,由于其中的一些公式太难编辑了,后续自己会专门结合代码实现写一下自己的理解。

主要使用到的类

Pipeline

DeepSort将检测器输出的predict box作为输入,输出不同的track的运动状态u,v,γ,h,x ̇,y ̇,γ ̇,h ̇,不同的track以不同的track id标识。主要是用Tracker类的predictupdate完成整个流程。千言万语不如一张图。

image.png

1、Input

将检测器产生的predict box转化为Detection对象。

2、tracker.predict

通过流程图我们可以知道,tracker.predict主要干了三件事:

3、tracker.update

通过流程图我们可以知道,tracker.update主要干了六件事:

(1)track和detection的match

这部分是deepsort流程中最重要的一个环节。tracker中会保存所有的track,每一次的检测结果得到的detections都需要和tracker中的track进行匹配,完成detection的分配问题。

需要额外注意的是

(2)track.update

track的mean表示运动学状态(u,v,γ,h,x ̇,y ̇,γ ̇,h ̇),track的state表示track是否属性状态(deleted,tentative, confirmed),需要更新track的五个部分。

(3)track.mark_missed

将符合条件的track的state标记为deleted,主要有两种情况。

(4)_initiate_track

初始化新的track。主要有两个部分:

(5)删除track

tracker.tracks删除state为deleted的track。

(6)self.metric.partial_fit

更新在级联匹配中,用于和新的detection的外观特征向量计算余弦距离的track的外观特征向量(self.budget,默认最新的100个)。

4、Output

state为confirmed的track的location及其track id。源码中是Track对象是不包含类别的,因此输出的track也是没有类别的,在deepsort看来不同的track就是不同的目标对象,不区分类别。

需要注意
输出的是confirmed的track,track转换为confirmed条件是需要连续_n_init使用iou匹配策略匹配上detection。

卡尔曼滤波过程理论结合代码

KF精髓在于Kalman gain. Kalman gain本质上是weighted average 的 weight。你越相信你的prediction,uncertainty越小,observation的weight就越小;反之,你越不相信你的prediction,uncertainty越大,observation的weight越大。举个例子:在一个陌生地方开车,你越不自信的时候,越信赖你的观察(路标、问路等等)你在熟悉的地方开车时越信赖自己的直觉。而观测噪声和测量噪声分别是对模型和测量不确定性的定量描述。

1、流程

image.png

2、Predict过程

返回的mean, covariance分别对应流程图中Prediction中的X_{k+1}P_{k+1}

def predict(self, mean, covariance):
    """Run Kalman filter prediction step.

    Parameters
    ----------
    mean : ndarray
        The 8 dimensional mean vector of the object state at the previous
        time step.
    covariance : ndarray
        The 8x8 dimensional covariance matrix of the object state at the
        previous time step.

    Returns
    -------
    (ndarray, ndarray)
        Returns the mean vector and covariance matrix of the predicted
        state. Unobserved velocities are initialized to 0 mean.

    """
    std_pos = [
        self._std_weight_position * mean[3],
        self._std_weight_position * mean[3],
        1e-2,
        self._std_weight_position * mean[3]]
    std_vel = [
        self._std_weight_velocity * mean[3],
        self._std_weight_velocity * mean[3],
        1e-5,
        self._std_weight_velocity * mean[3]]
    motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))
    
    # 求到流程图中的Xk+1
    mean = np.dot(self._motion_mat, mean)
    # 求到流程图中的Pk+1
    covariance = np.linalg.multi_dot((
        self._motion_mat, covariance, self._motion_mat.T)) + motion_cov

    return mean, covariance

3、Update过程

(1)project函数

project函数完成了状态转移的过程,在流程图Correction的中H就是状态转移方程。返回的mean, covariance + innovation_cov分别是Hx_kHP_kH^T+R

def project(self, mean, covariance):
    """Project state distribution to measurement space.

    Parameters
    ----------
    mean : ndarray
        The state's mean vector (8 dimensional array).
    covariance : ndarray
        The state's covariance matrix (8x8 dimensional).

    Returns
    -------
    (ndarray, ndarray)
        Returns the projected mean and covariance matrix of the given state
        estimate.

    """
    std = [
        self._std_weight_position * mean[3],
        self._std_weight_position * mean[3],
        1e-1,
        self._std_weight_position * mean[3]]
    innovation_cov = np.diag(np.square(std))

    mean = np.dot(self._update_mat, mean)
    covariance = np.linalg.multi_dot((
        self._update_mat, covariance, self._update_mat.T))
    return mean, covariance + innovation_cov

(2)update函数

这里提一下cholesky分解,在求逆矩阵很复杂时可以使用此方法简化,在计算卡尔曼增益和马氏距离时都有应用。由于本文中提到的协方差矩阵A都是实对称正定矩阵,所以可以应用cholesky分解成下三角矩阵,然后转化为求非齐次线性方程组的问题:
A= LL^T
计算马氏距离时
D(x,y)=\sqrt{ (x-y)^TA^{-1}(x-y)} = \sqrt{ [ L^{-1}(x-y)]^T [L^{-1}(x-y)]}
Z= (L^{T})^{-1}*(x-y)^{T} =>L^{T}Z=(x-y)^{T}

    # 求LT
    cholesky_factor = np.linalg.cholesky(covariance)
    # x-y
    d = measurements - mean
    # 解非齐次线性方程组求Z
    z = scipy.linalg.solve_triangular(
        cholesky_factor, d.T, lower=True, check_finite=False,
        overwrite_b=True)
    squared_maha = np.sum(z * z, axis=0)

计算卡尔曼增益时

def update(self, mean, covariance, measurement):
    """Run Kalman filter correction step.

    Parameters
    ----------
    mean : ndarray
        The predicted state's mean vector (8 dimensional).
    covariance : ndarray
        The state's covariance matrix (8x8 dimensional).
    measurement : ndarray
        The 4 dimensional measurement vector (x, y, a, h), where (x, y)
        is the center position, a the aspect ratio, and h the height of the
        bounding box.

    Returns
    -------
    (ndarray, ndarray)
        Returns the measurement-corrected state distribution.

    """
    # 状态转移,由测量空间转换到观测空间
    projected_mean, projected_cov = self.project(mean, covariance)

    chol_factor, lower = scipy.linalg.cho_factor(
        projected_cov, lower=True, check_finite=False)
    kalman_gain = scipy.linalg.cho_solve(
        (chol_factor, lower), np.dot(covariance, self._update_mat.T).T,
        check_finite=False).T
    # 测量变量和预测值之差,称为测量过程的革新或者残余
    innovation = measurement - projected_mean

    new_mean = mean + np.dot(innovation, kalman_gain.T)
    new_covariance = covariance - np.linalg.multi_dot((
        kalman_gain, projected_cov, kalman_gain.T))
    return new_mean, new_covariance
上一篇 下一篇

猜你喜欢

热点阅读