目标跟踪--卡尔曼滤波 与 匈牙利算法

news2024/11/14 9:05:05

目前主流的目标跟踪算法都是基于Tracking-by-Detecton策略,即基于目标检测的结果来进行目标跟踪。

跟踪结果中,每个bbox左上角的数字是用来标识某个人的唯一ID号。那么问题就来了,视频中不同时刻的同一个人,位置发生了变化,是如何关联上的呢?答案就是匈牙利算法和卡尔曼滤波

  • 匈牙利算法可以判断当前帧的某个目标,是否与前一帧的某个目标相同。
  • 卡尔曼滤波可以基于目标前一时刻的位置,来预测当前时刻的位置,并且可以比传感器(在目标跟踪中即目标检测器,比如Yolo等)更准确的估计目标的位置。

目录

匈牙利算法(Hungarian Algorithm)

卡尔曼滤波(Kalman Filter)

DeepSort工作流程

三、个人总结


匈牙利算法(Hungarian Algorithm)

匈牙利算法,就是可以将分配问题的代价最小化。

例如现在有三个人A、B、C出现在视频中,目标检测器也检测出来了,但是目标检测器只能判定A、B、C三个目标都是人,不能判定A、B、C谁是谁。在DeepSORT中,匈牙利算法将前一帧的跟踪tracks与当前帧中的检测框detections进行关联,外观信息(appearance information)马氏距离(Mahalanobis distance),或者IOU来计算代价矩阵,并得出代价最小的分配结果。

源码解读:

#  linear_assignment.py
def min_cost_matching(distance_metric, max_distance, tracks, detections, 
                      track_indices=None, detection_indices=None):
    ...
    
    # 计算代价矩阵
    cost_matrix = distance_metric(tracks, detections, track_indices, detection_indices)
    cost_matrix[cost_matrix > max_distance] = max_distance + 1e-5
    
    # 执行匈牙利算法,得到匹配成功的索引对,行索引为tracks的索引,列索引为detections的索引
    row_indices, col_indices = linear_assignment(cost_matrix)
 
    matches, unmatched_tracks, unmatched_detections = [], [], []
 
    # 找出未匹配的detections
    for col, detection_idx in enumerate(detection_indices):
        if col not in col_indices:
            unmatched_detections.append(detection_idx)
     
    # 找出未匹配的tracks
    for row, track_idx in enumerate(track_indices):
        if row not in row_indices:
            unmatched_tracks.append(track_idx)
    
    # 遍历匹配的(track, detection)索引对
    for row, col in zip(row_indices, col_indices):
        track_idx = track_indices[row]
        detection_idx = detection_indices[col]
        # 如果相应的cost大于阈值max_distance,也视为未匹配成功
        if cost_matrix[row, col] > max_distance:
            unmatched_tracks.append(track_idx)
            unmatched_detections.append(detection_idx)
        else:
            matches.append((track_idx, detection_idx))
 
    return matches, unmatched_tracks, unmatched_detections

如DeepSORT源码所示:

用上一帧的tracks、当前帧的detections、计算出代价矩阵 cost_matrix

执行匈牙利算法,得到匹配成功的索引对,行索引为tracks的索引,列索引为detections的索引

找出未匹配的detections,未匹配的tracks

遍历匹配的(track, detection)索引对,如相应的cost大于阈值max_distance,也视为未匹配成功,筛过后便是匹配成功的

卡尔曼滤波(Kalman Filter)

在目标跟踪中,需要估计track的两个状态:

  • 均值(Mean):表示目标的位置信息,由bbox的中心坐标 (cx, cy),宽高比r,高h,以及各自的速度变化值组成,由8维向量表示为 x = [cx, cy, r, h, vx, vy, vr, vh],各个速度值初始化为0。
  • 协方差(Covariance ):表示目标位置信息的不确定性,由8x8的对角矩阵表示,矩阵中数字越大则表明不确定性越大,可以以任意值初始化。

卡尔曼滤波分为两个阶段:(1)预测track在下一时刻的位置,(2)基于detection来更新预测的位置

预测:

基于track在t-1时刻的状态来预测其在t时刻的状态。

式(1)中,F为状态转移矩阵,x为t-1时刻的均值,x为t时刻的均值。可以把这个理解为新位置=旧位置*状态=旧位置 * (速度*单位时间)。

公式(2)中,P为track在t-1时刻的协方差,Q为系统的噪声矩阵,代表整个系统的可靠程度,一般初始化为很小的值,该公式预测t时刻的P'

源码:

#  kalman_filter.py
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), 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]))  # 初始化噪声矩阵Q
    mean = np.dot(self._motion_mat, mean)  # x' = Fx
    covariance = np.linalg.multi_dot((self._motion_mat, covariance, self._motion_mat.T)) + motion_cov  # P' = FPF(T) + Q
 
    return mean, covariance

更新:

基于t时刻检测到的detection,校正与其关联的track的状态,得到一个更精确的结果。

式(3)计算detection和track的均值误差。

式(4)

式(5)计算卡尔曼增益K,卡尔曼增益用于估计误差的重要程度

式(6)和式(7)得到更新后的均值向量x和协方差矩阵P

源码解读:

#  kalman_filter.py
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), 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))  # 初始化噪声矩阵R
    mean = np.dot(self._update_mat, mean)  # 将均值向量映射到检测空间,即Hx'
    covariance = np.linalg.multi_dot((
        self._update_mat, covariance, self._update_mat.T))  # 将协方差矩阵映射到检测空间,即HP'H^T
    return mean, covariance + innovation_cov


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

    Parameters
    ----------
    mean: ndarra, 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), the measurement-corrected state distribution.
    """
    # 将mean和covariance映射到检测空间,得到Hx'和S
    projected_mean, projected_cov = self.project(mean, covariance)
    # 矩阵分解(这一步没看懂)
    chol_factor, lower = scipy.linalg.cho_factor(projected_cov, lower=True, check_finite=False)
    # 计算卡尔曼增益K
    kalman_gain = scipy.linalg.cho_solve(
            (chol_factor, lower), np.dot(covariance, self._update_mat.T).T,
            check_finite=False).T
    # z - Hx'
    innovation = measurement - projected_mean
    # x = x' + Ky
    new_mean = mean + np.dot(innovation, kalman_gain.T)
    # P = (I - KH)P'
    new_covariance = covariance - np.linalg.multi_dot((kalman_gain, projected_cov, kalman_gain.T))
        
    return new_mean, new_covariance

DeepSort工作流程

DeepSORT对每一帧的处理流程:

检测器得到bbox 

 生成detections :

卡尔曼滤波预测:依据前一帧的位置信息以及速度预测当前目标所在位置

使用匈牙利算法将预测后的tracks和当前帧的detections进行匹配(级联和IOU匹配):这样卡尔曼滤波才有的更新

卡尔曼滤波更新:更新协方差以及两帧之间位置信息的差值?

个人总结

卡尔曼滤波 :根据t-1帧的目标位置信息以及速度信息预测当前帧的目标位置

匈牙利算法:给bbox分配唯一ID

ps:本来想好好深入了解下,但是网上的资料读得一知半解,还是简单了解下,拿来会用就行吧

本来系以下参考的理解,基础好的同学可以细细读原文

参考:

目标跟踪初探(DeepSORT) - 知乎

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/480352.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

西瓜书读书笔记整理(三)—— 第二章 模型评估与选择

第二章 模型评估与选择 第 2 章 模型评估与选择2.1 经验误差与过拟合1. 错误率 / 精度 / 误差2. 训练误差 / 经验误差 / 泛化误差3. 过拟合 / 欠拟合4. 学习能力5. 模型选择 2.2 评估方法1. 评估方法概述2. 留出法3. 交叉验证法4. 自助法5. 调参 / 最终模型 2.3 性能度量1. 回归…

【JavaEE】UDP数据报套接字—实现回显服务器(网络编程)

博主简介:想进大厂的打工人博主主页:xyk:所属专栏: JavaEE初阶 本篇文章将带你了解什么是网络编程? 网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输&am…

中断-STM32

中断-STM32 中断:在主程序运行过程中,出现了特定的中断触发条件 (中断源),使得CPU暂停当前正在运行的程序转而去处理中断程序处理完成后又返回原来被暂停的位置继续运行。 中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓…

Java程序猿搬砖笔记(十一)

文章目录 Hexo博客 Next主题图片防盗链问题Springboot Druid数据库密码加密配置步骤Java统计字符串出现的次数Java获取某个字符在字符串中出现第N次的位置Maven激活指定profileMaven中resources标签的用法详解MySQL 字符集不一致报错EasyExcel日期格式化Configuration、Compone…

gradle Task 详解

Task定义和配置 查看工程下所有的task,使用如下命令 gradle tasks 定义一个task task创建的源码 参数分别是 task 名称,和一个 closure。groovy语法的closure可以写在小括号外面,小括号可以省略 task的源码 public interface Task extends…

【Java笔试强训 25】

🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一、选择题 二、编程题 🔥星际密码…

RabbitMQ死信队列延迟交换机

RabbitMQ死信队列&延迟交换机 1.什么是死信 死信&死信队列 死信队列的应用: 基于死信队列在队列消息已满的情况下,消息也不会丢失实现延迟消费的效果。比如:下订单时,有15分钟的付款时间 2. 实现死信队列 2.1 准备E…

网络编程代码实例:IO复用版

文章目录 前言代码仓库内容代码(有详细注释)server.cclient_select.cclient_poll.cclient_epoll.c 结果总结参考资料作者的话 前言 网络编程代码实例:IO复用版。 代码仓库 yezhening/Environment-and-network-programming-examples: 环境和…

[Linux]网络连接、资源共享

​⭐作者介绍:大二本科网络工程专业在读,持续学习Java,输出优质文章 ⭐作者主页:逐梦苍穹 ⭐所属专栏:Linux基础操作。本文主要是分享一些Linux系统常用操作,内容主要来源是学校作业,分享出来的…

详解c++---vector模拟实现

目录标题 准备工作构造函数迭代器的完善性质相关的函数实现reservepush_back[ ]emptyresizeinserteraseerase后迭代器失效问题swapclear~vector老式拷贝构造迭代器构造新式拷贝构造老式赋值重载新式赋值重载N个数据的构造vector的浅拷贝问题 准备工作 首先我们知道vector是一个…

HTB靶机06-Beep-WP

beep 靶机IP:10.10.10.7 攻击机IP:10.10.14.6 web RCE漏洞利用、nmap提权 扫描 nmap 常规扫描: ┌──(xavier㉿xavier)-[~/HTB/005-Beep] └─$ sudo nmap -sSV -sC 10.10.10.7 -oN nmap1.out Starting Nmap 7.91 ( https://nmap.org …

《道德经》

《道德经》是春秋时期老子(李耳)的哲学作品,又称《道德真经》、《老子》、《五千言》、《老子五千文》,是中国古代先秦诸子分家前的一部著作,是道家哲学思想的重要来源。 道德经分上下两篇,原文上篇《德经…

网络安全: CIDR无类别路由

网络安全: CIDR无类别路由 CIDR是无类别路由,出现CIDR的原因是因为ipv4的地址被使用完客,CIDR的出现暂缓了ipv4用完的速度。 原本的ipv4很刻板,网络号分成8位,16位,24位作为掩码,也就是 xxx.0…

DRY编码原则

基本情况 DRY,Don’t repeat yourself,就是不要重复你自己的意思。 不要重复,是多么简单的意思了,重复就是多了一个一样的东西,为什么多一个呢,一个就可以了,这样才简单,这是一个常…

【报错】arXiv上传文章出现XXX.sty not found

笔者在overleaf上编译文章一切正常,但上传文章到arxiv时出现类似于如下报错: 一般情况下观察arxiv的编译log,不通过的原因,很多时候都是由于某一行导入了啥package,引起的报错;但是如果没有任何一个具体的…

AppSmith(安装与练习4套)

AppSmith官网文档: https://docs.appsmith.com/getting-started/setup/installation-guides/docker安装前需要已经安装好docker,需要版本如下: Docker ( 20.10.7或者更高) Docker-Compose ( 1.29.2或者更高) 安装Appsmith: 准备…

【Linux】第二站:Linux基本指令(一)

文章目录 一、操作系统OS概念1.OS是什么?2.为什么要有OS?1.一个好的操作系统,他的衡量指标是什么?2.操作系统的核心工作 3.理解我们在计算机上的操作4.Linux和Windows的特点 二、Linux基本指令1. 指令概述2.ls指令1> ls -l2> ls -a3&g…

ChatGPT其实并不想让开发人员做这5件事情

前言 ChatGPT已经火爆了快半年了吧,紧接着国内也开始推出了各种仿制品,我甚至一度怀疑,如果人家没有推出ChatGPT,这些仿制品会不会出现。而很多人也嗨皮得不行,利用各种方法开始科学上网,用ChatGPT做各种觉…

不得不说的行为型模式-解释器模式

解释器模式: 解释器模式(Interpreter Pattern)是一种行为型设计模式,它定义了一种语言,用于解释执行特定的操作,例如正则表达式、查询语言、数学表达式等。该模式通过定义一个解释器来解释语言中的表达式…

分治与减治算法实验:题目6 淘汰赛冠军问题

目录 前言 实验内容 实验流程 实验分析 实验过程 流程演示 写出伪代码 实验代码 运行结果 改进算法 总结 前言 淘汰赛冠军问题是一个经典的算法设计与分析的问题,它要求我们在给定的n个参赛者中,通过一系列的比赛,找出最终的冠军…