8.4 目标跟踪(下)——虎门大桥车流量统计

上一小节,对deepsort的实现步骤进行了详细分析,本小节将使用deepsort代码以及yolov5来实现车流量统计。

本节,首先对deepsort源代码的设计进行简要的结构剖析,来学习代码设计,然后将其结合yolov5,实现车流量统计。

注意,代码所需的模型文件,通过网盘下载:链接:https://pan.baidu.com/s/1Ys_v1Tqta4wJMHC8NKeTTg 提取码:ucf4

注意,ckpt.t7为deepsort的模型文件,一定要放到:F:\pytorch-tutorial-2nd\code\chapter-8\tracking\deep_sort\deep_sort\deep\checkpoint下面

deepsort源码——结构分析

deepsort的代码不算复杂,设计了几个核心类,然后为各个核心功能编写了实现函数。这里绘制简要的UML图,对代码设计的思路进行学习。

对于一个业务场景,首先识别实体,并分析实体的属性和功能,下面自下而上进行分析目标跟踪当中存在的实体。

Track目标物体:目标跟踪的核心元素是目标物体,这里称为Track类,对于一个目标,需要有坐标信息,id, 特征向量列表,状态等信息。

Tracker目标跟踪器:管理所有目标,并可实现目标的更新,因此需要卡尔曼滤波器,管理目标集合tracks等信息。

KalmanFilter卡尔曼滤波器:维护卡尔曼增益矩阵,并实现预测、更新两大功能。

DeepSort类:进行统一封装,对外提供update函数,返回跟踪框。

对于级联匹配,会在Tracker类中_match()实现,其中设计了一系列模块,包括

matching_cascade:级联匹配实现,循环70次进行匹配。

min_cost_matching:实现一次最小代价匹配。

linear_assignment:匈牙利算法实现。

NearestNeighborDistanceMetric:级联匹配中距离度量功能实现,其中维护了各目标的所有特征向量,每一帧的特征向量都会被保存。最大保存100个特征向量。

if self.budget is not None:
    self.samples[target] = self.samples[target][-self.budget:]  # 相当巧妙的实现最多记录最新的100个特征向量

到这里,deepsort大体框架以及搭建完毕,使用方法非常简单,只需要实例化DeepSort类,调用.update()即可获得跟踪框信息。

deepsort+yolov5——车流量统计

目标跟踪可以获得目标的位置及唯一标识,它只是方法,并不是目的。

基于目标跟踪方法,可以实现许多有价值的事情,例如卡口人流量计数,交通道路车流量计数与统计,警戒区域预警等。

进行行人计数或车流量计数时,需要判断目标是否经过特定区域,这时需要撞线机制来实现,撞线机制可以有两种方法实现。

一种是基于区域判断,另外一种是基于线段相交判断。

另外一种是基于线段相交判断,则是基于物体的历史轨迹曲线,判断是否与界线相交。

计数中的撞线机制

本案例采用基于区域的撞线机制,对边界设置两个区域,一般称inner和outter区域,当物体先到达inner,再进入outter,则可判断物体是离开,反之亦然。

对于inner和outter区域,每个区域需要记录曾经到达区域里的目标id,仅当两个区域同时存在过目标id,可以计数,并且删除目标id。

例如图中的ID-60,进入了inner区域(蓝色),inner区域需要观察ID-60是否存在outer区域中(黄色),当前是不存在的,因此添加到inner区域的历史列表中。

下一帧,ID-60到达黄色区域,黄色区域同样地,先判断ID-60是否来自蓝色区域,它在蓝色区域的历史记录中找到了ID-60,因此可以判断ID-60是从inner到达outer,所以outer进行加一。

反之inter加一。

在代码实现上有一些抽象,这里做简单的讲解。

如何判断物体到达inner和outter区域?

采用mask矩阵,inner区域像素是1, outer像素是2,mask矩阵大小与图片大小一致,采用目标的位置坐标对mask矩阵索引,通过索引值==1? 还是==2?来判断当前物体位于什么区域。

如何判断物体先、后顺序?

区域中发现新物体时,首先判断是否存在对向区域,若不存在,才可以加入区域的物体容器中进行管理。若存在,即可删除,并且计数。

为了实现撞线机制,这里设计了三个类,分别是BoundaryType、CountBoundary和BaseCounter

处理逻辑在BaseCounter的counting(),边界区域抽象成CountBoundary,实现了必要的函数来完成计数。

下面简单介绍counting函数中,如何判断物体是从outer来,到达inter,实现inter计数+1的(反之亦然)

第1行:通过物体的x,y坐标,对索引矩阵进行索引,得到索引值。例如:[1, 2, 0, 0, 0, ...]。通过索引值可知在何区域

第4行:通过索引值列表,判断当前在inner区域的目标,并且返回它们的id

第5行:获取,当前到过outer的目标id

第8行:判断是否有交集,有交集表明,该id从outer来,已经抵达inner。可以计数。

第9行:判断是否存在差集,inner有,outer没有,表明物体可以加入inner的id_container中进行管理

第10行:由于目标完成了计数,outer_boundary中需要删除它。

第11行:由于目标第一次到来,所以注册到inner_boundary中,后续供outer_boundary查询。

bbox_area_list = self.area_mask[index_xy]  # 获取bbox在图像中区域的索引,1,2分别表示在边界区域. [int,]

# ======================== 先处理inner区域 ====================================
inner_tracks_currently_ids = self.get_currently_ids_by_area(tracks, bbox_area_list, BoundaryType.inner)
outer_tracks_history_ids = list(self.outer_boundary.id_container.keys())  # 获取历史帧经过outer区域的目标的id

# 当前与历史的交集,认为是目标从outer已经到达inner,可以计数,并且删除。
outer_2_inner_tracks_id = self.intersection(inner_tracks_currently_ids, outer_tracks_history_ids)
only_at_inner_tracks_id = self.difference(inner_tracks_currently_ids, outer_tracks_history_ids)
self.outer_boundary.remove_tracks(outer_2_inner_tracks_id)  # 删除outer中已计数的id
self.inner_boundary.register_tracks(only_at_inner_tracks_id)  # 注册仅inner有的id

注意事项

在第1行中 self.area_mask的制作中,由于采用的是像素1和2,在resize时,导致2的边界有一系列1的存在,导致了误检!

按设计,1在2的下面,这里1反而出现在了2的上面,导致实际是“出”的,计算为了“入”

把上述代码组装起来得到01-main.py,做好模型文件、视频文件、边界点的配置,运行即可得到以下结果。

模型权重文件,视频文件可通过网盘下载:

注意,ckpt.t7为deepsort的模型文件,一定要放到:F:\pytorch-tutorial-2nd\code\chapter-8\tracking\deep_sort\deep_sort\deep\checkpoint下面

完整视频可见B站

这里为了实现边界区域点集的获取,编写了鼠标点选边界区域的代码00-draw-border.py

运行后,鼠标双击实现选点,选点顺序必须从左上角开始,顺时针,选择完毕,terminal中打印的点集list,复制下来使用即可。

小结

目标跟踪案例中,内容比较多,这里总结一些关键知识点:

  1. SORT与DeepSORT算法步骤:本案介绍目标跟踪中出现的问题,一步步引出DeepSORT设计的复杂逻辑,由问题出发,以解决问题的方式,观察DeepSORT的步骤。
  2. DeepSORT中的核心算法:卡尔曼滤波器与匈牙利算法,卡尔曼滤波常用于带有高斯噪声的线性运动系统,可以很好的预测运动状态。匈牙利算法可以解决二分图匹配问题,今后也可以借鉴两个算法解决实际业务问题。
  3. DeepSORT代码结构剖析:通过UML图,分析DeepSORT代码是如何抽象、设计的,巩固面向对象编程的思想。
  4. 计数的撞线机制:介绍基于区域的撞线机制,并通过面向对象编程来实现计数器。
  5. DeepSORT+YOLOv5的联合使用:将目标检测+目标跟踪+计数机制联合使用,构建实际应用,在主代码中可以发现,各功能模块抽象独立出去,主代码的核心代码仅两行:bboxes = detector.detect(im); counter.counting(list_bboxs);

目标跟踪仍是一个较大研究方向,DeepSORT仅是其中一种方法,要深入掌握目标跟踪还需学习其他方法。

Copyright © TingsongYu 2021 all right reserved,powered by Gitbook文件修订时间: 2024年04月26日21:48:10

results matching ""

    No results matching ""