当前位置: 首页 > news >正文

深度学习目标跟踪相关细节-毕设

DeepSORT

算法流程

img img
  • 设置了不确定态、确定态、删除态,用于匹配(转换关系如上图)

    • 不确定态:说明新轨迹刚出现的一段时间
    • 确定态:确定是轨迹的时间
    • 删除态:轨迹已经丢失的状态

毕设项目演示地址: 链接

毕业项目设计代做项目方向涵盖:

目标检测、语义分割、深度估计、超分辨率、3D目标检测、CNN、模型压缩、人脸对齐、超分辨、去噪、强化学习、行为识别、OpenCV、场景文本识别、去雨、机器学习、风格迁移、视频目标检测、去模糊、显著性检测、剪枝、活体检测、人脸关键点检测、3D目标跟踪、视频修复、人脸表情识别、时序动作检测、图像检索、异常检测等

  • 增加了级联匹配和IOU匹配

    • 级联匹配只针对确定态轨迹和检测结果
      解决遮挡问题(只利用了图像特征,并结合了马氏距离避免远距离匹配)——需要解决误匹配问题

    • IOU匹配针对其他所有情况:不确定态轨迹、匹配失败轨迹、匹配失败检测结果

      根据相对位置进行二次匹配,避免同一个人发生了一定的动作变化,导致级联匹配没有匹配到(因为级联只使用图像特征,而此时图像变化很大)——为了解决漏匹配问题

    • 两次匹配,可以认为该匹配的都已经匹配成功,此时再进行相关状态的修改

DeepSORT的上级函数是状态更新函数:

  1. 根据检测结果对轨迹进行匹配(这就是deepsort做的)
  2. 根据匹配结果进行相关的状态更新——和扶梯思路一致
    1. 匹配成功的更新各状态:添加图像feature,更新kalman参数什么的,还有不确定态什么的。
    2. 匹配失败的进行删除或者新增轨迹
#  tracker.py
"整个匹配流程:级联+IOU匹配。最终返回匹配成功、不成功的结果"
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) """这个函数中会把马氏距离很大的位置置为inf"""
        return cost_matrix

    """1. 区分开confirmed tracks和unconfirmed tracks"""
    confirmed_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()]

    """2. 对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)

    """3. 对级联匹配中未匹配的tracks和unconfirmed tracks中time_since_update为1的tracks进行IOU匹配"""
    iou_track_candidates = unconfirmed_tracks + [k for k in unmatched_tracks_a if
                                                 self.tracks[k].time_since_update == 1]
    unmatched_tracks_a = [k for k in unmatched_tracks_a if
                          self.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)
	
    # 整合所有的匹配对和未匹配的tracks
    matches = matches_a + matches_b
    unmatched_tracks = list(set(unmatched_tracks_a + unmatched_tracks_b))
    
    return matches, unmatched_tracks, unmatched_detections

级联匹配

用于解决遮挡问题

  1. 让未匹配的检测结果和各级轨迹进行匹配(即便越高,说明轨迹越久没有被匹配)——体现了优先为刚刚跟踪成功的轨迹进行匹配。
  2. 匹配使用了马氏距离和reid结合的代价矩阵

级联的思想

为了解决遮挡问题,就必须使检测结果与过往长时间没有跟踪到的轨迹进行匹配,而级联匹配就是解决了这个问题。

会为每一个轨迹添加一个状态来记录其已经有多少帧没有被跟踪到。
1首先将检测结果与最近跟踪到的轨迹进行匹配–>会得到没有匹配成功的检测框
2未匹配成功的检测框再与更长时间没有跟踪成功的轨迹进行匹配…
3直到所有检测框都完成匹配或者超出了最大级联深度(深度越大,则允许轨迹长时间跟踪丢失)

def matching_cascade(
        distance_metric, max_distance, cascade_depth, tracks, detections,
        track_indices=None, detection_indices=None):
    .............
    # cascade depth = max age 默认为70
    for level in range(cascade_depth): # level越大,说明往回查的时间越久
        if len(unmatched_detections) == 0:  # 没有检测框需要匹配时,直接提前退出
            break

        track_indices_l = [
            k for k in track_indices
            if tracks[k].time_since_update == 1 + level
        ] # 找出当前level存在的所有的轨迹,并根据这些轨迹来匹配检测结果
        if len(track_indices_l) == 0:  # 如果当前level不存在轨迹,就遍历下一个level
            continue

        # 2. 级联匹配核心内容就是这个函数
        matches_l, _, unmatched_detections = \ # 使用reid+马氏距离进行KM匹配
            min_cost_matching(  # max_distance=0.2
                distance_metric, max_distance, tracks, detections,
                track_indices_l, unmatched_detections)
        matches += matches_l
    unmatched_tracks = list(set(track_indices) - set(k for k, _ in matches))
    return matches, unmatched_tracks, unmatched_detections

KM匹配具体实现

流程就是:
计算代价矩阵
KM匹配
根据匹配结果获得匹配成功、未成功的检测及轨迹。

def min_cost_matching(
        distance_metric, max_distance, tracks, detections, track_indices=None,
        detection_indices=None):
    if track_indices is None:
        track_indices = np.arange(len(tracks))
    if detection_indices is None:
        detection_indices = np.arange(len(detections))

    if len(detection_indices) == 0 or len(track_indices) == 0:
        return [], track_indices, detection_indices  # Nothing to match.
    # -----------------------------------------
    # Gated_distance——>
    #       1. cosine distance
    #       2. 马氏距离
    # 得到代价矩阵
    # -----------------------------------------
    # iou_cost——>
    #       仅仅计算track和detection之间的iou距离
    # -----------------------------------------
    """1. 计算代价矩阵"""
    cost_matrix = distance_metric(
        tracks, detections, track_indices, detection_indices)
    # -----------------------------------------
    # gated_distance中设置距离中最高上限,
    # 这里最远距离实际是在deep sort类中的max_dist参数设置的
    # 默认max_dist=0.2, 距离越小越好
    # -----------------------------------------
    # iou_cost情况下,max_distance的设置对应tracker中的max_iou_distance,
    # 默认值为max_iou_distance=0.7
    # 注意结果是1-iou,所以越小越好
    # -----------------------------------------
    cost_matrix[cost_matrix > max_distance] = max_distance + 1e-5

    """2. 匈牙利算法或者KM算法"""
    row_indices, col_indices = linear_assignment(cost_matrix)

    matches, unmatched_tracks, unmatched_detections = [], [], []

    # 这几个for循环用于对匹配结果进行筛选,得到匹配和未匹配的结果
    for col, detection_idx in enumerate(detection_indices):
        if col not in col_indices:
            unmatched_detections.append(detection_idx)

    for row, track_idx in enumerate(track_indices):
        if row not in row_indices:
            unmatched_tracks.append(track_idx)
	"""3. 对匹配成功的对,再次判断其距离,如果距离过大就标记为匹配失败"""
    for row, col in zip(row_indices, col_indices):
        track_idx = track_indices[row]
        detection_idx = detection_indices[col]
        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                           

马氏距离与reid的结合

KM匹配代价矩阵的计算:reid与马氏距离结合,值是reid余弦距离,马氏距离用于将一些位置距离很远的目标距离设为inf,防止其进行匹配。
虽然设置为了inf,但KM依然会存在匹配结果,因此在匹配完成之后,必须对匹配成功的对再次进行距离判断,将距离很大的仍然标记为匹配失败——和扶梯项目中改掉的那个bug一模一样。

马氏距离是预测结果与测量结果之间的距离,具体作用就是,根据位置信息来区分一些图像特征相似的目标(例子如下):
代价矩阵中的距离是Track和Detection之间的表观相似度,假如一个轨迹要去匹配两个表观特征非常相似的Detection,这样就很容易出错,但是这个时候分别让两个Detection计算与这个轨迹的马氏距离,并使用一个阈值gating_threshold进行限制,所以就可以将马氏距离较远的那个Detection区分开,可以降低错误的匹配。

def gate_cost_matrix(
        kf, cost_matrix, tracks, detections, track_indices, detection_indices,
        gated_cost=INFTY_COST, only_position=False):
    # 根据通过卡尔曼滤波获得的状态分布,使成本矩阵中的不可行条目无效。
    """就是让位置距离差别很大的直接不采用匹配(具体实现就是将其距离设为inf)"""
    gating_dim = 2 if only_position else 4
    gating_threshold = kalman_filter.chi2inv95[gating_dim]  # 9.4877

    measurements = np.asarray([detections[i].to_xyah()
                               for i in detection_indices])

    for row, track_idx in enumerate(track_indices):
        track = tracks[track_idx]
        gating_distance = kf.gating_distance(
            track.mean, track.covariance, measurements, only_position)
        cost_matrix[row, gating_distance >
                    gating_threshold] = gated_cost  """马氏距离很大的目标代价直接设置为inf"""

    return cost_matrix

相关问题

如何解决遮挡问题?

参考级联匹配一节,级联匹配就是用来解决遮挡问题的。

  1. 使用ReID提取每个轨迹点的外观特征
  2. 当前第N帧的检测结果和前面100帧的轨迹点外观特征计算余弦距离,取最小的距离作为当前检测结果和该轨迹的外观相似度。

由于是取前100帧轨迹点的最小距离,基本该轨迹中间丢失了几个轨迹点,当该目标重新出现时依然可以和他准确匹配成功,自动解决了遮挡问题。

马氏距离

马氏距离(Mahalanobis Distance)是一种距离的度量,可以看作是欧氏距离的一种修正,修正了欧式距离中各个维度尺度不一致且相关的问题。

image-20210714160022810

参考链接:马氏距离(Mahalanobis Distance)

参考链接

DeepSORT的细节

目标跟踪初探(DeepSORT)——比较简单,适合快速复习

Deep SORT多目标跟踪算法代码解析(上)——有一个代码仓库,直接添加了注释,分别查看细节(建议仔细看这个)

https://gitee.com/xn1997/deep-sort-self.git——上述链接的仓库,个人加了一部分注释,用于查看跟踪流程(建议用工作机打开,有对重要的几个函数打了断点,也可以直接看程序内注释了解)

相关文章:

  • JVM基础:什么是STW?
  • Teams Bot App 初探
  • 3d卷积神经网络应用,3d可视动态神经检测
  • Hive on Tez 的安装配置
  • 05 关于局部变量名字的存储
  • java毕业设计教程SSM框架实现的车位租赁管理系统|停车场计费系统[包运行成功]
  • 微雪树莓派PICO笔记——7. SPI(串行外设接口)
  • 真正理解Java中的异步
  • 《Unity3D脚本编程与游戏开发》学习Day one
  • JavaScript:JavaScript编程语言学习之前端框架(VUE)架构(MVVM)的简介、案例应用之详细攻略
  • [Python]闭包
  • 《C++程序设计原理与实践》笔记 第5章 错误
  • 静息态fMRI方法在脑动力学表征上的比较
  • LabVIEW自动整理程序框图
  • 拨测API接口+监控方案
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • Java编程基础24——递归练习
  • JAVA并发编程--1.基础概念
  • Material Design
  • spring security oauth2 password授权模式
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • - 概述 - 《设计模式(极简c++版)》
  • 高程读书笔记 第六章 面向对象程序设计
  • 观察者模式实现非直接耦合
  • 机器学习中为什么要做归一化normalization
  • 免费小说阅读小程序
  • 一份游戏开发学习路线
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • PostgreSQL之连接数修改
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • #13 yum、编译安装与sed命令的使用
  • #每天一道面试题# 什么是MySQL的回表查询
  • $$$$GB2312-80区位编码表$$$$
  • (1)常见O(n^2)排序算法解析
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (附源码)springboot 基于HTML5的个人网页的网站设计与实现 毕业设计 031623
  • (三) diretfbrc详解
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (十) 初识 Docker file
  • (转)GCC在C语言中内嵌汇编 asm __volatile__
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .bat批处理(五):遍历指定目录下资源文件并更新
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .Net高阶异常处理第二篇~~ dump进阶之MiniDumpWriter
  • .NET设计模式(7):创建型模式专题总结(Creational Pattern)
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • .Net下的签名与混淆
  • @拔赤:Web前端开发十日谈
  • [ vulhub漏洞复现篇 ] Grafana任意文件读取漏洞CVE-2021-43798
  • [Android]创建TabBar
  • [Android]一个简单使用Handler做Timer的例子
  • [Angularjs]asp.net mvc+angularjs+web api单页应用之CRUD操作
  • [ANT] 项目中应用ANT
  • [ASP.NET MVC]Ajax与CustomErrors的尴尬