【深度学习|目标跟踪】StrongSORT 详解(以及StrongSORT++)

StrongSort详解

  • 1、论文及源码
  • 2、DeepSORT回顾
  • 3、StrongSORT的EMA
  • 4、StrongSORT的NSA Kalman
  • 5、StrongSORT的MC
  • 6、StrongSORT的BOT特征提取器
  • 7、StrongSORT++的AFLink
  • 8、StrongSORT++的GSI模块

1、论文及源码

在这里插入图片描述
论文地址:https://arxiv.org/pdf/2202.13514
源码地址:https://github.com/dyhBUPT/StrongSORT?tab=readme-ov-file

2、DeepSORT回顾

参考此篇博客

3、StrongSORT的EMA

  EMA即指数加权移动平均,在StrongSort中,self.track在update时,会将当前提取到的目标特征向量进行如下两步操作:

  • 将特征向量归一化
  • 指数加权移动平均

在代码中的体现,在track脚本文件中,Track类:
在这里插入图片描述
相比较于DeepSort中将每次的匹配上的目标的特征向量直接存储到对应track的gallery中,StrongSort的做法可以有效的平滑视频中间由于遮挡,噪声或其他不利因素导致的目标特征的衰减,使得在特征在匹配时的准确率能够有效提升。
  在Trackerupdate的最后,我们会更新对应track的特征库:
在这里插入图片描述

nn_matching脚本中的NearestNeighborDistanceMetric类中:
在这里插入图片描述
这里的self.budget可以在config.yaml中指定,意思是存储当前帧的前多少帧的特征进特征库。本质上还是和DeepSort一样,给每个track弄了个特征库,只不过特征库中的特征向量是从第一帧开始就进行指数加权移动平均并归一化的特征向量。

4、StrongSORT的NSA Kalman

  在DeepSort中使用的是一个普通的kalman filter,即通过状态量直接估计下一时刻的状态,只有位置信息,而StrongSort中融合了目标的置信度信息,在计算噪声的均值和方差时,加入了track对应的检测目标的置信度信息,自适应的调整噪声。自适应计算噪声协方差的公式:
在这里插入图片描述
其中,Rk是预设的常数测量噪声协方差,Ck 是状态 k 下的检测置信度分数。即当置信度高时,意味着这次检测的结果有较小的噪声,对下次的状态预测的影响较小。
  现在来看一下源码中关于NSA Kalman的流程:

  • strong_sort.py中StrongSort类的self.tracker.predict()
  • 进入tracker.py中的Tracker类的predict()方法,遍历self.tracks然后进入track的predict()预测,然后进入track.py中的Track类的predict()预测,然后进入kalman_filter.py中的KalmanFilter类中的predict()方法来计算均值和方差。
  • 然后回到strong_sort.py中的self.tracker.update(),进入tracker.py的Tracker类的update()方法,经过self._match()匹配完成之后,会得到匹配列表,未匹配的跟踪,未匹配的检测。然后我们遍历匹配列表来,跟新我们已经匹配上的track,进入track.py中的Track类的update()方法,在这里我们会看到加入了检测框的confidence来更新均值和方差:
    在这里插入图片描述
  • 进入kalman_filter.py中的KalmanFilter类中的update()方法,进入self.project()方法计算出融合了confidence后的均值和方差。

这便是代码中NSA Kalman的一个实现过程。

5、StrongSORT的MC

  在DeepSort中,虽然说结合了外观特征和运动特征来进行跟踪,但是DeepSort的lambda权重是设置成0或1的,因此并没有真正的结合外观特征追踪和运动特征追踪,只是将他们分成两个阶段分别匹配。而在StrongSort中,在外观特征匹配阶段,引入了一个mc_lambda权重作用在运动特征的门控矩阵上,结合外观代价矩阵来计算得到最后的cost_matrix,公式如下:
在这里插入图片描述
代码如下:
在这里插入图片描述
这是在_match()方法中的gated_metric()方法中调用。

6、StrongSORT的BOT特征提取器

  这是一个关于行人重识别的特征提取网络,具体的还没有深入了解过,我个人觉得这里的特征提取器用什么不是StrongSort的亮点,毕竟这个模块是个即插即用的模块,用不同的分类网络或者孪生网络训练出来的特征提取网络都可以用在这个地方。

7、StrongSORT++的AFLink

  AFLink提出将两段30帧(可以自己调整,修改AFLink的分类网络重新训练即可)的时空序列作为输入,这两段tracklets分别是1 * 30 * 3维度的一个特征向量,其中30表示帧数,3分别表示帧数(时间),x,y(空间),即结合了时空的一段序列。网络将会输出这两段tracklets的相似置信度。

  • AFLink网络的定义:
    在这里插入图片描述
"""
@Author: Du Yunhao
@Filename: model.py
@Contact: dyh_bupt@163.com
@Time: 2021/12/28 14:13
@Discription: model
"""
import torch
from torch import nn

class TemporalBlock(nn.Module):
    def __init__(self, cin, cout):
        super(TemporalBlock, self).__init__()
        self.conv = nn.Conv2d(cin, cout, (7, 1), bias=False)
        self.relu = nn.ReLU(inplace=True)
        self.bnf = nn.BatchNorm1d(cout)
        self.bnx = nn.BatchNorm1d(cout)
        self.bny = nn.BatchNorm1d(cout)

    def bn(self, x):
        x[:, :, :, 0] = self.bnf(x[:, :, :, 0])
        x[:, :, :, 1] = self.bnx(x[:, :, :, 1])
        x[:, :, :, 2] = self.bny(x[:, :, :, 2])
        return x

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x


class FusionBlock(nn.Module):
    def __init__(self, cin, cout):
        super(FusionBlock, self).__init__()
        self.conv = nn.Conv2d(cin, cout, (1, 3), bias=False)
        self.bn = nn.BatchNorm2d(cout)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x


class Classifier(nn.Module):
    def __init__(self, cin):
        super(Classifier, self).__init__()
        self.fc1 = nn.Linear(cin*2, cin//2)
        self.relu = nn.ReLU(inplace=True)
        self.fc2 = nn.Linear(cin//2, 2)

    def forward(self, x1, x2):
        x = torch.cat((x1, x2), dim=1)
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x


class PostLinker(nn.Module):
    def __init__(self):
        super(PostLinker, self).__init__()
        self.TemporalModule_1 = nn.Sequential(
            TemporalBlock(1, 32),
            TemporalBlock(32, 64),
            TemporalBlock(64, 128),
            TemporalBlock(128, 256)
        )
        self.TemporalModule_2 = nn.Sequential(
            TemporalBlock(1, 32),
            TemporalBlock(32, 64),
            TemporalBlock(64, 128),
            TemporalBlock(128, 256)
        )
        self.FusionBlock_1 = FusionBlock(256, 256)
        self.FusionBlock_2 = FusionBlock(256, 256)
        self.pooling = nn.AdaptiveAvgPool2d((1, 1))
        self.classifier = Classifier(256)

    def forward(self, x1, x2):
        x1 = x1[:, :, :, :3]
        x2 = x2[:, :, :, :3]
        x1 = self.TemporalModule_1(x1)  # [B,1,30,3] -> [B,256,6,3]
        x2 = self.TemporalModule_2(x2)
        x1 = self.FusionBlock_1(x1)
        x2 = self.FusionBlock_2(x2)
        x1 = self.pooling(x1).squeeze(-1).squeeze(-1)
        x2 = self.pooling(x2).squeeze(-1).squeeze(-1)
        y = self.classifier(x1, x2)
        if not self.training:
            y = torch.softmax(y, dim=1)
        return y


if __name__ == '__main__':
    x1 = torch.ones((3, 1, 30, 3))
    x2 = torch.ones((3, 1, 30, 3))
    m = PostLinker()
    m.eval()
    # 提取第一个维度的第二个元素作为置信度(0表示第一个维度,1表示该维度的索引)
    y1 = m(x1, x2)[0, 1].detach().cpu().numpy()
    print(y1)

输入两个tracklets,维度分别是[1, 1, 30, 3];
           ||
           v
Temporal module: 特征层维度[1, 256, 6, 3];
           ||
           v
Fusion module: 特征层维度[1, 256, 6, 1];
           ||
           v
Pooling + Squeeze:特征层维度[1, 256];
           ||
           v
Classifier:特征层维度[1, 2];

  • AFLink的推理:
    AFLink是一个离线模块,在目标检测+跟踪推理完成后,将每一帧的track信息(帧数,位置)保存到txt中,然后离线的使用AFLink读取这个txt来得到最终的推理结果,也将序列信息保存到txt中。我们可以根据txt中的帧数和坐标信息来将检测结果可视化在视频中。

8、StrongSORT++的GSI模块

  GSI模块即高斯平滑插值,为了弥补跟踪之后的检测结果在帧上不够连续的情况。这一模块个人感觉对于跟踪的结果上没有影响,在完全跟对的情况下,能够改善跟踪的连续性的视觉效果,但是如果跟踪错误的前提下,GSI之后,结果会变得很奇怪(框开始飘来飘去)。
  在源码中,大致上分为两步骤:

  • 设定一个插帧得阈值,小于这个阈值得两个不连续的帧之间我们会一帧帧插值,而大鱼这个阈值的,我们只插这个阈值数量的帧在中间。
  • 高斯平滑,来使得插的帧的跟踪信息显得更加的连续平滑。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AntFlow 0.20.0版发布,增加多数据源多租户支持,进一步助力企业信息化,SAAS化

传统老牌工作流引擎比如activiti,flowable或者camunda等虽然功能强大,也被企业广泛采用,然后也存着在诸如学习曲线陡峭,上手难度大,流程设计操作需要专业人员,普通人无从下手等问题。。。引入工作流引擎往往需要企业储…

【设计模式系列】工厂方法模式(二十一)

一、什么是工厂方法模式 工厂方法模式(Factory Method Pattern)是一种创建型设计模式,其核心目的是定义一个创建对象的接口,但让实现这个接口的子类来决定实例化哪一个类。工厂方法模式让类的实例化推迟到子类中进行,…

HCIE:详解OSPF,从基础到高级特性再到深入研究

目录 前言 一、OSPF协议基本原理 简介 基本原理 OSPF路由器类型 OSPF网络类型 OSPF报文类型和封装 OSPF邻居的建立的维护 DR和BDR的选举 伪节点 LSDB的更新 OSPF的配置 二、OSPF的高级特性 虚连接(Virtual-Link) OSPF的LSA和路由选择 OSPF…

分享一款 Vue 图片编辑插件 (推荐)

💥本篇文章给大家分享一款强大到没朋友的Vue图片编辑插件,可以对图片进行旋转、缩放、裁剪、涂鸦、标注、添加文本等,快来试试并收藏吧!💕 这是一款对图片进行旋转、缩放、裁剪、涂鸦、标注、添加文本在线处理的图片处…

【时间之外】IT人求职和创业应知【53】-东莞也转型

目录 新闻一:Freysa挑战赛:人类智慧与策略战胜AI,奖金高达4.7万美元 新闻二:中国生成式AI用户规模突破2.3亿,行业应用广泛 新闻三:2024东莞智能终端新技术推广会圆满举行,聚焦AI与智能终端融…

大模型在推荐系统中的应用

引言 推荐系统在现代互联网应用中扮演着至关重要的角色。从电商到社交媒体,再到音乐与视频流媒体服务,推荐系统通过分析用户行为数据和内容特征,为用户提供个性化服务。近年来,大模型(Large Language Models, LLMs&…

Electron + vue3 打包之后不能跳转路由

路由不跳转问题原因: 是因为electron需要将vue-router的mode调整为hash模式(两种写法) export default new Router({mode: hash, //这里history修改为hashscrollBehavior: () > ({y: 0}),routes: constantRouterMap, }) export default new createRouter({his…

Linux网络_网络协议_网络传输_网络字节序

一.协议 1.概念 协议(Protocol) 是一组规则和约定,用于定义计算机网络中不同设备之间如何进行通信和数据交换。协议规定了数据的格式、传输方式、传输顺序等详细规则,确保不同设备和系统能够有效地互联互通。 在网络通信中&#…

Unity3D UI 嵌套滚动视图

Unity3D 解决 UI 嵌套滚动视图滑动问题。 嵌套滚动视图 滑动问题 在游戏开发中,我们常常会遇到一种情况,在一个滚动视图列表中,每个 item 还包含了一个内嵌的滚动视图。 这样,当我们在滑动外层的滚动视图时,如果点…

QT6学习第五天 第一个QT Quick程序

QT6学习第五天 第一个QT Quick程序 概述创建Qt Quick程序使用Qt资源文件程序发布 概述 如果将程序的用户界面成为前端,程序的数据存储和逻辑业务成为后端,那么传统QT Widgets程序的前后端都是用C完成的。对于现代软件开发而言,前端演化速度远…

【C++】单目操作符详解:前置与后置自增自减及正负号操作

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯单目操作符概述1 自增与自减操作符: 和 --2 前置 和 后置 案例 1:前置 案例 2:后置 小技巧 3 前置 -- 和 后置 --案例 1:前…

SAP SD学习笔记15 - 投诉处理2 - 返品处理流程之 参照请求传票(发票)来生成返品传票

上一章讲了返品处理(退货处理)的流程。 SAP SD学习笔记14 - 投诉处理1 - 返品处理(退货处理)的流程以及系统实操,比如 返品传票;请求Block标记;收到退货之后的处理,请求传票的登录_…

【C语言】二叉树(BinaryTree)的创建、3种递归遍历、3种非递归遍历、结点度的实现

代码主要实现了以下功能: 二叉树相关数据结构定义 定义了二叉树节点结构体 BiTNode,包含节点数据值(字符类型)以及指向左右子树的指针。 定义了顺序栈结构体 SqStack,用于存储二叉树节点指针,实现非递归遍历…

【博主推荐】C# Winform 拼图小游戏源码详解(附源码)

文章目录 前言摘要1.设计来源拼图小游戏讲解1.1 拼图主界面设计1.2 一般难度拼图效果1.3 普通难度拼图效果1.4 困难难度拼图效果1.5 地域难度拼图效果1.6 内置五种拼图效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载结束语 前言 在数字浪潮汹涌澎湃的时代,程序开…

C++初阶(十七)--STL--stack和queue详解及使用

目录 stack 概念 stack的定义 stack的使用 queue 概念 queue的定义 queue的使用 在 C 的标准模板库(STL)中,stack(栈)和queue(队列)是非常重要的容器适配器。它们基于其他基础容器实现&…

【ubuntu24.04】GTX4700 配置安装cuda

筛选显卡驱动显卡驱动 NVIDIA-Linux-x86_64-550.135.run 而后重启:最新的是12.6 用于ubuntu24.04 ,但是我的4700的显卡驱动要求12.4 cuda

远程桌面协助控制软件 RustDesk v1.3.3 多语言中文版

RustDesk 是一款开源的远程桌面软件,支持多平台操作,包括Windows、macOS、Linux、iOS、Android和Web。它提供端到端加密和基于角色的访问控制,确保安全性和隐私保护。使用简单,无需复杂配置,通过输入ID和密码即可快速连…

【Linux】gdb / cgdb 调试 + 进度条

🌻个人主页:路飞雪吖~ 🌠专栏:Linux 目录 一、Linux调试器-gdb 🌟开始使用 🌠小贴士: 🌟gdb指令 🌠小贴士: ✨watch 监视 ✨打条件断点 二、小程序----进…

C++初阶——动态内存管理

目录 1、C/C内存区域划分 2、C动态内存管理:malloc/calloc/realloc/free 3、C动态内存管理:new/delete 3.1 new/delete内置类型 3.2 new/delete自定义类型 4、operator new与operator delete函数 5、new和delete的实现原理 5.1 内置类型 5.2 自定…

开发一套ERP 第八弹 RUst 插入数据

更全面的报错,方便检查错误在哪里,现代高级语言越来越智能 还是得看下原文档怎么操作的 src 目录为crate 的根目录 想在crate 中模块相互引入需要在 main 中声明,各个模块,然后才能在各个模块中相互引入和使用 原始工程引入,避免直接使用 lib.rs 回合cargo 中的一些 工程管理出…