DeepSORT多目标跟踪——算法流程与源码解析

一、目标检测与目标追踪

1. 目标检测

在目标检测任务中,主要目标是识别图像或视频帧中存在的物体的位置和类别信息。这意味着目标检测算法需要定位物体的边界框(Bounding Box)并确定每个边界框内的物体属于哪个类别(如人、汽车、狗等)。目标检测通常独立地处理每一帧图像,不考虑目标在不同帧之间的连续性。它通常用于静态图像的物体识别,也可以用于处理视频流中的每一帧以实现实时检测。

主流的目标检测算法:

  1. YOLO(You Only Look Once):YOLO是一种非常流行的目标检测算法,它具有快速的实时检测能力。YOLO将图像分成网格,并在每个网格上进行预测,以同时获得多个边界框和它们的类别概率。YOLO的特点是快速、准确,适用于实时应用。

  2. Faster R-CNN:Faster R-CNN采用了两阶段检测方法,其中第一阶段生成候选边界框,第二阶段对候选边界框进行分类和回归以获得最终检测结果。它的准确性较高,但速度相对较慢。

  3. SSD(Single Shot MultiBox Detector):SSD是一种单阶段检测算法,它在每个位置上使用多个不同尺度的卷积层来预测边界框和类别。它具有良好的平衡性能,既准确又相对快速。

  4. RetinaNet:RetinaNet结合了两阶段和单阶段方法的优点,使用了特殊的损失函数来解决类别不平衡问题,从而实现高效且准确的目标检测。

  5. Mask R-CNN:Mask R-CNN是Faster R-CNN的扩展版本,它不仅可以检测目标的边界框,还可以生成目标的精确掩模,用于实现实例分割任务,即将不同实例的像素分离开来。

  6. EfficientDet:EfficientDet是一种高效的目标检测算法,它基于EfficientNet的架构,并在目标检测中取得了很好的性能。它通过改进网络结构和训练策略来实现高效的目标检测。

目标检测示例:

目标检测

2. 目标追踪

与目标检测不同,目标跟踪的任务是在视频序列中跟踪特定物体的运动,即在不同的帧之间识别和跟踪同一物体。目标跟踪需要处理物体在时间上的连续性,通常涉及到将不同帧中的物体关联起来,以确保它们被正确标识为同一个物体。目标跟踪算法通常会分配唯一的ID给每个被跟踪的物体,以区分它们,并跟踪它们的位置随时间的变化。目标跟踪广泛用于视频监控、自动驾驶、人机互动等领域。

主流目标追踪算法:

  1. Kalman滤波器:Kalman滤波器是一个常用于目标追踪的线性动态系统估计方法。它可以预测目标的位置和速度,然后通过观测来不断更新估计。

  2. Particle Filter:粒子滤波器是一种用于非线性和非高斯问题的目标追踪方法。它通过随机粒子的采样来估计目标的状态。

  3. Mean-Shift:均值漂移算法是一种非参数化方法,它通过寻找目标在颜色空间中的密度峰值来进行目标追踪。

  4. KLT跟踪器:KLT(Kanade-Lucas-Tomasi)跟踪器是一种用于光流估计和目标追踪的方法,它可以用于跟踪特征点或区域。

  5. MIL(多实例学习):MIL是一种多目标追踪方法,它在每帧中检测多个候选目标并使用学习算法确定目标的状态。

  6. DeepSORT:DeepSORT是一种结合了深度学习和目标追踪的方法,它使用深度学习模型来提取目标特征,并使用关联算法来跟踪目标在视频中的位置。

  7. SORT:SORT(Simple Online and Realtime Tracking)是一种实时目标追踪方法,它通过匹配边界框和跟踪目标来实现目标追踪。

目标追踪示例:

目标追踪

从上面的视频示例中可以看到,检测到的每个目标都有一个指定的唯一的ID,当目标追踪出现遮挡或者丢失的之后,再次检测,还能匹配到原本的ID。

二. DeepSORT目标追踪

1.算法简介

目前,主流的目标跟踪算法大多采用"Tracking-by-Detection"策略,即依赖目标检测的结果来进行目标跟踪。DeepSORT是一个代表性的算法,它也采用了这一策略。DeepSORT对目标进行跟踪,每个边界框(bbox)的左上角数字用于标识唯一的目标ID。
DeepSORT的前身是SORT(Simple Online and Realtime Tracking)算法,SORT是一种目标跟踪器,由目标检测器和跟踪器组成。在SORT中,跟踪器的核心是卡尔曼滤波算法和匈牙利算法。它利用卡尔曼滤波来预测目标在下一帧的状态,然后使用匈牙利算法将这一状态与下一帧的检测结果进行匹配,以实现目标跟踪。如果目标在下一帧未被检测到,例如因受到遮挡或其他原因,卡尔曼滤波预测的状态信息将无法与检测结果匹配,导致跟踪片段提前结束。

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

2.追踪流程

DeepSORT引入了深度学习中的重识别算法,以提取被检测物体的外观特征(低维向量表示)。在每一次检测和追踪后,它会执行外观特征提取,并将这些特征保存起来。随后的每一步,它都会计算当前帧中被检测物体的外观特征与先前存储的特征之间的相似度,这有助于避免漏检和身份丢失的情况。因此,DeepSORT不仅仅依赖于物体的速度和方向趋势来进行目标跟踪,还利用物体的外观特征来加强对是否为同一物体的判断。

这个过程有点像在每一帧中为每个被检测的物体创建一个独特的ID,并在后续帧中使用这些ID来识别和跟踪物体。这种方法提高了目标追踪的鲁棒性,因为即使目标在某些帧中被遮挡或重新出现,根据外观特征的相似性,DeepSORT仍能够正确地将其与之前的跟踪关联起来,从而保持目标的身份标识。

DeepSORT跟踪算法归纳为以下几个步骤:
在这里插入图片描述

3.算法实现

当使用DeepSORT进行目标跟踪时,正常分两个步骤:

3.1 目标检测

首先,使用常规的目标检测模型(比如YOLO)对单帧图像进行分析,检测到感觉兴趣的目标的坐标位置 ,如果上面的示例视频,首先要使用目标检测算法对图像的中的行人做检测。

3.2目标预测

在这一步中,使用卡尔曼滤波算法。它基于当前的一系列运动变量来预测下一时刻的运动变量。首次检测结果用于初始化卡尔曼滤波的运动变量。预测结果被分为两种状态:确认态(confirmed)和不确认态(unconfirmed)。新生成的跟踪对象处于不确认态,只有在与检测结果连续匹配一定次数后才能转化为确认态。而处于确认态的跟踪对象需要与检测结果连续匹配一定次数才会被删除。

接下来,需要将检测到的物体与预测的物体进行关联。DeepSORT使用匈牙利算法,并根据不同的代价函数来找到最佳匹配。如果卡尔曼滤波输出了确认态的预测结果,DeepSORT将使用马氏距离和余弦距离的级联方法来关联相关信息。马氏距离提供了不同状态下物体之间的距离信息。如果某次关联的马氏距离低于指定的阈值,那么运动状态的关联成功。但DeepSORT不仅考虑帧与帧之间框的距离,还考虑框内的外观特征以更好地进行关联匹配。因此,DeepSORT引入了外观特征余弦距离度量,通过一个重识别模型获取不同物体的特征向量,然后构建余弦距离代价函数,计算预测对象与检测对象的相似度。当两个预测框的马氏距离和外观特征余弦距离都小于一定阈值时,它们被认为是同一个物体。
在这里插入图片描述

DeepSORT之所以引入这种级联方法,是因为在物体运动状态变化较剧烈的情况下,基于目标状态之间的关联可能不可靠。例如,当一个人在奔跑时,如果相机是静止的或与人的运动方向相反,相机中的人在每帧之间的运动状态会有很大的差异。这种情况下,运动的不确定性增加,先验状态与目标检测之间的匹配差异较大。为了弥补这一缺陷,DeepSORT采用特征相似距离关联。然而,在目标的运动状态变化不剧烈的情况下,马氏距离成为更好的数据关联度量选择。

在数据关联的第二步,DeepSORT计算了不确认态下的预测框和未被上一步级联方法匹配的检测框之间的IOU交并比。然后,使用匈牙利算法来找到最佳匹配的IOU结果。如果预测框和检测框的IOU低于阈值,它们的关联将被删除。
最后,利用当前帧的关联结果来更新所有分配了ID的跟踪对象的状态。这有助于保持跟踪对象的准确性和一致性。

三、源码解析

DeepSORT在每一帧的处理流程如下:

1.检测

在每一帧中,目标检测器识别并提取出边界框(bbox),这些边界框表示在当前帧中检测到的目标物体。

 def detect(self,cv_src):boxes, scores, class_ids = self.detector(cv_src)pred_boxes = []for i in range(len(boxes)):x1,y1 = int(boxes[i][0]),int(boxes[i][1])x2,y2 = int(boxes[i][2]),int(boxes[i][3])lbl = class_names[class_ids[i]]# print(class_ids[i])# if lbl in ['person','sack','elec','bag','box','caron']:#     continuepred_boxes.append((x1,y1,x2,y2,lbl,class_ids[i]))return cv_src,pred_boxes

2. 生成detections

从这些检测到的边界框中,生成称为"detections"的目标检测结果。每个detection通常包含有关目标的信息,如边界框坐标和可信度分数。

#  deep_sort.py
def update(self, bbox_xywh, confidences, ori_img):self.height, self.width = ori_img.shape[:2]# 提取每个bbox的featurefeatures = self._get_features(bbox_xywh, ori_img)# [cx,cy,w,h] -> [x1,y1,w,h]bbox_tlwh = self._xywh_to_tlwh(bbox_xywh)# 过滤掉置信度小于self.min_confidence的bbox,生成detectionsdetections = [Detection(bbox_tlwh[i], conf, features[i]) for i,conf in enumerate(confidences) if conf > self.min_confidence]# NMS (这里self.nms_max_overlap的值为1,即保留了所有的detections)boxes = np.array([d.tlwh for d in detections])scores = np.array([d.confidence for d in detections])indices = non_max_suppression(boxes, self.nms_max_overlap, scores)detections = [detections[i] for i in indices]...

3. 卡尔曼滤波预测

对于已知的跟踪对象(“tracks”),在下一帧中进行卡尔曼滤波预测,以估计其新的位置和速度。

#  track.py
def predict(self, kf):"""Propagate the state distribution to the current time step using a Kalman filter prediction step.Parameters----------kf: The Kalman filter."""self.mean, self.covariance = kf.predict(self.mean, self.covariance)  # 预测self.age += 1  # 该track自出现以来的总帧数加1self.time_since_update += 1  # 该track自最近一次更新以来的总帧数加1

4.使用匈牙利算法将预测后的tracks和当前帧中的detections进行匹配

这是DeepSORT中的核心步骤。DeepSORT使用匈牙利算法来将预测的tracks和当前帧的detections进行匹配。这个匹配可以采用两种级联方法:首先,通过计算马氏距离来估算预测对象与检测对象之间的关联,如果马氏距离小于指定的阈值,则将它们匹配为同一目标。其次,DeepSORT还使用外观特征余弦距离度量,通过一个重识别模型获得不同物体的特征向量,然后构建余弦距离代价函数,以计算预测对象与检测对象的相似度。这两个代价函数的结果都趋向于小,如果边界框接近且特征相似,则将它们匹配为同一目标。

#  tracker.py
def _match(self, detections):def gated_metric(racks, dets, track_indices, detection_indices):"""基于外观信息和马氏距离,计算卡尔曼滤波预测的tracks和当前时刻检测到的detections的代价矩阵"""features = np.array([dets[i].feature for i in detection_indices])targets = np.array([tracks[i].track_id for i in track_indices]# 基于外观信息,计算tracks和detections的余弦距离代价矩阵cost_matrix = self.metric.distance(features, targets)# 基于马氏距离,过滤掉代价矩阵中一些不合适的项 (将其设置为一个较大的值)cost_matrix = linear_assignment.gate_cost_matrix(self.kf, cost_matrix, tracks, dets, track_indices, detection_indices)return cost_matrix# 区分开confirmed tracks和unconfirmed tracksconfirmed_tracks = [i for i, t in enumerate(self.tracks) if t.is_confirmed()]unconfirmed_tracks = [i for i, t in enumerate(self.tracks) if not t.is_confirmed()]# 对confirmd tracks进行级联匹配matches_a, unmatched_tracks_a, unmatched_detections = \linear_assignment.matching_cascade(gated_metric, self.metric.matching_threshold, self.max_age,self.tracks, detections, confirmed_tracks)# 对级联匹配中未匹配的tracks和unconfirmed tracks中time_since_update为1的tracks进行IOU匹配iou_track_candidates = unconfirmed_tracks + [k for k in unmatched_tracks_a ifself.tracks[k].time_since_update == 1]unmatched_tracks_a = [k for k in unmatched_tracks_a ifself.tracks[k].time_since_update != 1]matches_b, unmatched_tracks_b, unmatched_detections = \linear_assignment.min_cost_matching(iou_matching.iou_cost, self.max_iou_distance, self.tracks,detections, iou_track_candidates, unmatched_detections)# 整合所有的匹配对和未匹配的tracksmatches = matches_a + matches_bunmatched_tracks = list(set(unmatched_tracks_a + unmatched_tracks_b))return matches, unmatched_tracks, unmatched_detections# 级联匹配源码  linear_assignment.py
def matching_cascade(distance_metric, max_distance, cascade_depth, tracks, detections, track_indices=None, detection_indices=None):...unmatched_detections = detection_indicematches = []# 由小到大依次对每个level的tracks做匹配for level in range(cascade_depth):# 如果没有detections,退出循环if len(unmatched_detections) == 0:  break# 当前level的所有tracks索引track_indices_l = [k for k in track_indices if tracks[k].time_since_update == 1 + level]# 如果当前level没有track,继续if len(track_indices_l) == 0: continue# 匈牙利匹配matches_l, _, unmatched_detections = min_cost_matching(distance_metric, max_distance, tracks, detections, track_indices_l, unmatched_detections)matches += matches_lunmatched_tracks = list(set(track_indices) - set(k for k, _ in matches))return matches, unmatched_tracks, unmatched_detections

5. 卡尔曼滤波更新

匹配后,DeepSORT使用检测到的detections来更新每个已知的跟踪对象的状态,例如位置和速度。这有助于保持跟踪对象的准确性和连续性。

def update(self, detections):"""Perform measurement update and track management.Parameters----------detections: List[deep_sort.detection.Detection]A list of detections at the current time step."""# 得到匹配对、未匹配的tracks、未匹配的dectectionsmatches, unmatched_tracks, unmatched_detections = self._match(detections)# 对于每个匹配成功的track,用其对应的detection进行更新for track_idx, detection_idx in matches:self.tracks[track_idx].update(self.kf, detections[detection_idx])# 对于未匹配的成功的track,将其标记为丢失for track_idx in unmatched_tracks:self.tracks[track_idx].mark_missed()# 对于未匹配成功的detection,初始化为新的trackfor detection_idx in unmatched_detections:self._initiate_track(detections[detection_idx])...

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Panda3d 相机控制

Panda3d 相机控制 文章目录 Panda3d 相机控制Panda3d中的透视镜头和垂直镜头透视镜头垂直镜头 Panda3d 中用代码控制相机的移动用键盘控制相机的移动用鼠标控制相机的移动 Panda3d 把相机也当做是一个 PandaNode,因此可以向操作其他节点对其进行操作。 真正的相机是…

(自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载

(自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载 带后台系统PbootCMS内核开发的网站模板,该模板适用于新闻博客网站、自媒体运营网站等企业,当然其他行业也可以做,只需要把文字图片换成其他行业的即可&#…

怎样做好金融投资翻译

我们知道, 金融投资翻译所需的译文往往是会议文献、年终报表、信贷审批等重要企业金融资料,其准确性事关整个企业在今后一段时期内的发展战略与经营成效。尤其像年报,对于上市公司来说更是至关重要的。那么,怎样做好金融投资翻译&…

Linux shell编程学习笔记21:用select in循环语句打造菜单

一、select in循环语句的功能 Linux shell脚本编程提供了select in语句,这是 Shell 独有的一种循环语句,非常适合终端(Terminal)这样的交互场景,它可以根据用户的设置显示出带编号的菜单,用户通过输入不同…

七月论文审稿GPT第二版:从Meta Nougat、GPT4审稿到Mistral、LLaMA LongLora

前言 如此前这篇文章《学术论文GPT的源码解读与微调:从chatpaper、gpt_academic到七月论文审稿GPT》中的第三部分所述,对于论文的摘要/总结、对话、翻译、语法检查而言,市面上的学术论文GPT的效果虽暂未有多好,可至少还过得去&am…

vue中的rules表单校验规则使用方法 :rules=“rules“

一、el-form里面必写属性值 :ref"dataForm" // 提交表单时进行校验 :rules"rules" // return 下的校验规则 :model"userForm" // 绑定表单的值 <el-formref"dataForm" // 必写属性值:rules"rules"…

服务器搭建:从零开始创建自己的Spring Boot应用【含登录、注册功能】

当然&#xff0c;你可以先按照IDEA搭建SSM框架【配置类、新手向】完成基础框架的搭建 步骤 1&#xff1a;设计并实现服务器端的用户数据库 在这个示例中&#xff0c;我们将使用MySQL数据库。首先&#xff0c;你需要安装MySQL并创建一个数据库以存储用户信息。以下是一些基本步…

creating server tcp listening socket 127.0.0.1:6379: bind No error

window下启动redis服务报错&#xff1a; creating server tcp listening socket 127.0.0.1:6379: bind No error 解决方案如下按顺序输入如下命令即可连接成功 redis-cli.exeshutdownexit运行&#xff1a;redis-server.exe redis.windows.conf shutdown出现以下错误&#xff…

正点原子嵌入式linux驱动开发——Linux USB驱动

USB是很常用的接口&#xff0c;目前大多数的设备都是USB接口的&#xff0c;比如鼠标、键盘、USB摄像 头等&#xff0c;在实际开发中也常常遇到USB接口的设备&#xff0c;本章就来学习一下如何使能Linux内核自带的USB驱动。这里不会具体学习USB的驱动开发。 USB接口简介 什么是…

2023-11-04 LeetCode每日一题(数组中两个数的最大异或值)

2023-11-04每日一题 一、题目编号 421. 数组中两个数的最大异或值二、题目链接 点击跳转到题目位置 三、题目描述 给你一个整数数组 nums &#xff0c;返回 nums[i] XOR nums[j] 的最大运算结果&#xff0c;其中 0 ≤ i ≤ j < n 。 示例 1&#xff1a; 示例 2&…

【笔记】单片机卡死的八大原因和解决方法

在微控制器上&#xff0c;程序卡住&#xff08;即停止执行&#xff09;可能有多种原因。下面我将列举一些常见的原因&#xff0c;并提供一些可能导致程序卡住的示例情况。请注意&#xff0c;这里只是一些示例&#xff0c;并不能穷尽所有可能的情况。 1. 死循环&#xff08;Infi…

Nignx安装负载均衡动静分离以及Linux前端项目部署将域名映射到特定IP地址

目录 一、nginx简介 1.1 定义 1.2 背景 1.3 作用 二、nginx搭载负载均衡提供前后分离后台接口数据 2.1 nginx安装 2.1.1 下载依赖 2.1.2 下载并解压安装包 2.1.3 安装nginx 2.1.4 启动nginx服务 2.2 tomcat负载均衡 2.2.1 负载均衡所需服务器准备 2.2.2 配置修改 …

2022年12月 Python(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试&#xff08;1~6级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 列表L1中全是整数&#xff0c;小明想将其中所有奇数都增加1&#xff0c;偶数不变&#xff0c;于是编写了如下图所示的代…

驱动开发11-2 编写SPI驱动程序-点亮数码管

驱动程序 #include <linux/init.h> #include <linux/module.h> #include <linux/spi/spi.h>int m74hc595_probe(struct spi_device *spi) {printk("%s:%d\n",__FILE__,__LINE__);char buf[]{0XF,0X6D};spi_write(spi,buf,sizeof(buf));return 0; …

阿里云推出AI编程工具“通义灵码“;生成式 AI 入门教程 2

&#x1f989; AI新闻 &#x1f680; 阿里云推出AI编程工具"通义灵码"&#xff0c;支持多种语言及实时续写功能 摘要&#xff1a;阿里云推出了一款名为"通义灵码"的AI编程工具&#xff0c;支持多种主流编程语言&#xff0c;包括Java、Python、Go等。该工…

Redis Sentinel 哨兵模式

Sentinel 哨兵模式 Redis Sentinel 官网 Redis 的 Sentinel 文档 -- Redis中国用户组&#xff08;CRUG&#xff09; Sentinel Redis 命令参考&#xff08;红色&#xff09; Sentinel 通过监控的方式获取主机的工作状态是否正常&#xff0c;当主机发生故障时&#xff0c; Senti…

十年JAVA搬砖路——Linux搭建Ldap服务器。

1.安装命令 yum -y install openldap compat-openldap openldap-clients openldap-servers openldap-servers-sql openldap-devel2.启动ldap systemctl start slapd systemctl enable slapd3.修改密码 slappasswd Aa123456获得返回的密码加密密码串&#xff1a; {SSHA}DkSw0…

RPC 原理详解

文章目录 什么是 RPCRPC 基本原理RPC核心功能服务寻址数据编解码网络传输一次RPC的调用过程 实践基于HTTP协议的RPC基于TCP协议的RPC 什么是 RPC RPC&#xff08;Remote Procedure Call&#xff09;&#xff0c;即远程过程调用&#xff0c;它允许像调用本地服务一样调用远程服…

Python基础入门例程37-NP37 不低于与不超过(运算符)

最近的博文&#xff1a; Python基础入门例程36-NP36 谁的数字大&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程35-NP35 朋友的年龄是否相等&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程34-NP34 除法与取模运算&#xff08;运算符&#xff09;…

07.Diffusion Model概述

文章目录 Diffusion Model原理Reverse ProcessDenoise模块Forward Process(Diffusion Process) 文字生成图片by Diffusion Model文字生成图像的常见套路Text EncoderFrchet Inception DistanceContrastive Language-Image Pre-Training(CLIP) DecoderGeneration Model 部分截图…