AI项目十九:YOLOV8实现目标追踪

若该文为原创文章,转载请注明原文出处。

主要是学习一下实现目标追踪的原理,并测试一下效果。

目的是通过YOLOV8实现人员检测,并实现人员追踪,没个人员给分配一个ID,实现追踪的效果。

也可以统计人数。在小区办公楼的出入场所,这类很常见。

一、简介

追踪任务是指识别和跟踪特定目标在视频序列中的运动和位置,一般用唯一ID或固定颜色检测框表示),如下图:

目标检测和目标跟踪的区别:
目标检测:目标检测任务要求同时完成对象的定位(即确定对象的边界框位置)和分类(即确定对象的类别)。这意味着目标检测算法必须不仅能够确定对象是否存在,还要知道它是什么。
目标检测通常用于识别和定位图像或视频帧中的对象,通常需要明确的目标类别信息。
目标跟踪:目标跟踪任务更关注对象在帧与帧之间的连续性,通常更注重对象的运动特征,而不要求进行目标的分类。
目标跟踪可以不涉及目标的类别,它的主要目标是维护对象的位置和轨迹,以实现在视频序列中的跟踪。

这里就有个问题,视频中不同时刻的同一个人,位置发生了变化,那么是如何关联上的呢?答案就是匈牙利算法和卡尔曼滤波。

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

最经典的是DeepSORT,本篇记录的是如何使用IOU,所以了解下DeepSORT。

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

检测器得到bbox → 生成detections → 卡尔曼滤波预测→ 使用匈牙利算法将预测后的tracks和当前帧中的detecions进行匹配(级联匹配和IOU匹配) → 卡尔曼滤波更新

Frame 0:检测器检测到了3个detections,当前没有任何tracks,将这3个detections初始化为tracks
Frame 1:检测器又检测到了3个detections,对于Frame 0中的tracks,先进行预测得到新的tracks,然后使用匈牙利算法将新的tracks与detections进行匹配,得到(track, detection)匹配对,最后用每对中的detection更新对应的track

二、方法介绍

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

实现目标跟踪的方法:

1、IOU

比较前后两帧检测框IOU是否大于指定阈值,是则是同一个物体,不是则分配新ID,此方法对于运动慢的可以,效果差。

2、卡尔曼滤波

卡尔曼滤波是一种用于估计系统状态的优秀算法。它结合了传感器测量和系统模型,通过递归地计算加权平均值,实时更新状态估计。卡尔曼滤波在众多领域,如导航、机器人技术和信号处理中广泛应用,以提高系统的准确性和鲁棒性。

可以用的库:GitHub - adipandas/multi-object-tracker: Multi-object trackers in Python

3、botsort&bytetrack

BoT-SORT是今年非常游戏的跟踪器模型。就所有主要 MOT 指标MOTA、IDF1 和 HOTA而言,BoT-SORT 和 BoT-SORT-ReID 在 MOT17 和 MOT20 测试集的 MOTChallenge数据集中排名第一。对于 MOT17:实现了 80.5 MOTA、80.2 IDF1 和 65.0 HOTA,在跟踪器的排行榜上暂居第一。
论文翻译:https://blog.csdn.net/hhhhhhhhhhwwwwwwwwww/article/details/126890651
论文链接:https://arxiv.org/pdf/2206.14651.pdf
代码:https://github.com/NirAharon/BOT-SORT
 

ByteTrack是基于tracking-by-detection范式的跟踪方法。大多数多目标跟踪方法通过关联分数高于阈值的检测框来获取目标ID。对于检测分数较低的目标,例如遮挡目标,会被简单的丢弃,这带来了不可忽略的问题,包括大量的漏检和碎片化轨迹。为了解决该问题,作者提出了一种简单、高效且通用的数据关联方法BYTE,通过关联每个检测框而不仅仅是高分检测框来进行跟踪。对于低分检测框,利用它们与轨迹的相似性来恢复真实目标并过滤掉背景检测。

BoT-SORT:https://github.com/NirAharon/BoT-SORT

ByteTrack :https://github.com/ifzhang/ByteTrack

三、IOU实现目标追踪

1、环境安装

本人的电脑使用的是CPU(无GPU)版本,所以直接安装,GPU需要安装CUDA等,自行安装。

# 使用Conda为本项目单独创建一个虚拟环境(python 3.8版本)
conda create -n yolov8_env python=3.8
# 激活进入环境
conda activate yolov8_env# YOLOv8安装方式
pip install ultralytics

2、验证

# 图片cli验证
yolo predict model=yolov8n.pt source=./bus.jpg# 视频cli验证
yolo predict model=yolov8n.pt source=./test.mp4

3、使用python验证

使用python语言验证主要是熟悉YOLOV8的API,知道如何调用,并测试。

from ultralytics import YOLO
import cv2
import numpy as np
import time# 加载模型
model = YOLO("./yolov8n.pt")  # load a pretrained model (recommended for training)
objs_labels = model.names  # get class labels
print(objs_labels)# 打开摄像头
cap = cv2.VideoCapture(0)while True:# 读取一帧start_time = time.time()ret, frame = cap.read()if ret:# 检测result = list(model(frame, stream=True))[0]  # inference,如果stream=False,返回的是一个列表,如果stream=True,返回的是一个生成器boxes = result.boxes  # Boxes object for bbox outputsboxes = boxes.cpu().numpy()  # convert to numpy array# 遍历每个框for box in boxes.data:l,t,r,b = box[:4].astype(np.int32) # left, top, right, bottomconf, id = box[4:] # confidence, class# 绘制框cv2.rectangle(frame, (l,t), (r,b), (0,0,255), 2)# 绘制类别+置信度(格式:98.1%)cv2.putText(frame, f"{objs_labels[id]} {conf*100:.1f}%", (l, t-10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)end_time = time.time()fps = 1 / (end_time - start_time)# 绘制FPScv2.putText(frame, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)# 显示cv2.imshow("frame", frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakelse:break

在终端里执行python demo.py

4、IOU实现追踪

'''
iou追踪示例
'''
from ultralytics import YOLO
import cv2
import numpy as np
import time
import random
import os
from shapely.geometry import Polygon, LineString
import jsonclass IouTracker:def __init__(self):# 加载检测模型self.detection_model = YOLO("./yolov8n.pt")  # 获取类别 self.objs_labels = self.detection_model.names # 打印类别print(self.objs_labels)# 只处理personself.track_classes = {0: 'person'}# 追踪的IOU阈值self.sigma_iou = 0.5# detection thresholdself.conf_thresh = 0.3def iou(sel,bbox1, bbox2):"""计算两个bounding box的IOU"""(x0_1, y0_1, x1_1, y1_1) = bbox1(x0_2, y0_2, x1_2, y1_2) = bbox2# 计算重叠的矩形的坐标overlap_x0 = max(x0_1, x0_2)overlap_y0 = max(y0_1, y0_2)overlap_x1 = min(x1_1, x1_2)overlap_y1 = min(y1_1, y1_2)# 检查是否有重叠if overlap_x1 - overlap_x0 <= 0 or overlap_y1 - overlap_y0 <= 0:return 0# 计算重叠矩形的面积以及两个矩形的面积size_1 = (x1_1 - x0_1) * (y1_1 - y0_1)size_2 = (x1_2 - x0_2) * (y1_2 - y0_2)size_intersection = (overlap_x1 - overlap_x0) * (overlap_y1 - overlap_y0)size_union = size_1 + size_2 - size_intersection# 计算IOUreturn size_intersection / size_uniondef predict(self, frame):'''检测'''result = list(self.detection_model(frame, stream=True, conf=self.conf_thresh))[0]  # inference,如果stream=False,返回的是一个列表,如果stream=True,返回的是一个生成器boxes = result.boxes  # Boxes object for bbox outputsboxes = boxes.cpu().numpy()  # convert to numpy arraydets = [] # 检测结果# 遍历每个框for box in boxes.data:l,t,r,b = box[:4] # left, top, right, bottomconf, class_id = box[4:] # confidence, class# 排除不需要追踪的类别if class_id not in self.track_classes:continuedets.append({'bbox': [l,t,r,b], 'score': conf, 'class_id': class_id })return detsdef main(self):'''主函数'''# 读取视频cap = cv2.VideoCapture("./media/video.mp4")# 获取视频帧率、宽、高fps = cap.get(cv2.CAP_PROP_FPS)width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))print(f"fps: {fps}, width: {width}, height: {height}")tracks_active = [] # 活跃的跟踪器frame_id = 1 # 帧IDtrack_idx = 1 # 跟踪器ID# writerout = cv2.VideoWriter("./test_out.mp4", cv2.VideoWriter_fourcc(*'mp4v'), fps, (1280, 720))while True:# 读取一帧start_time = time.time()ret, raw_frame = cap.read()if ret:# 检测frame = cv2.resize(raw_frame, (1280, 720))raw_frame = framedets = self.predict(raw_frame)# 更新后的跟踪器updated_tracks = [] # 遍历活跃的跟踪器for track in tracks_active:if len(dets) > 0:# 根据最大IOU更新跟踪器,先去explain.ipynb中看一下MAX用法best_match = max(dets, key=lambda x: self.iou(track['bboxes'][-1], x['bbox'])) # 找出dets中与当前跟踪器(track['bboxes'][-1])最匹配的检测框(IOU最大)# 如果最大IOU大于阈值,则将本次检测结果加入跟踪器if self.iou(track['bboxes'][-1], best_match['bbox']) > self.sigma_iou:# 将本次检测结果加入跟踪器track['bboxes'].append(best_match['bbox'])track['max_score'] = max(track['max_score'], best_match['score'])track['frame_ids'].append(frame_id)# 更新跟踪器updated_tracks.append(track)# 删除已经匹配的检测框,避免后续重复匹配以及新建跟踪器del dets[dets.index(best_match)]# 如有未分配的目标,创建新的跟踪器new_tracks = []for det in dets: # 未分配的目标,已经分配的目标已经从dets中删除new_track = {'bboxes': [det['bbox']], # 跟踪目标的矩形框'max_score': det['score'], # 跟踪目标的最大score'start_frame': frame_id,  # 目标出现的 帧id'frame_ids': [frame_id],  # 目标出现的所有帧id'track_id': track_idx,    # 跟踪标号'class_id': det['class_id'], # 类别'is_counted': False       # 是否已经计数}track_idx += 1new_tracks.append(new_track)# 最终的跟踪器tracks_active = updated_tracks + new_trackscross_line_color = (0,255,0) # 越界线的颜色# 绘制跟踪器for tracker in tracks_active:# 绘制跟踪器的矩形框l,t,r,b = tracker['bboxes'][-1]# 取整l,t,r,b = int(l), int(t), int(r), int(b)class_id = tracker['class_id']cv2.rectangle(raw_frame, (l,t), (r,b), cross_line_color, 2)# 绘制跟踪器的track_id + class_name + score(99.2%格式)cv2.putText(raw_frame, f"{tracker['track_id']}", (l, t-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,255,0), 2)# 设置半透明color = (0,0,0)alpha = 0.2l,t = 0,0r,b = l+240,t+40raw_frame[t:b,l:r,0] = raw_frame[t:b,l:r,0] * alpha + color[0] * (1-alpha)raw_frame[t:b,l:r,1] = raw_frame[t:b,l:r,1] * alpha + color[1] * (1-alpha)raw_frame[t:b,l:r,2] = raw_frame[t:b,l:r,2] * alpha + color[2] * (1-alpha)# end timeend_time = time.time()# FPSfps = 1 / (end_time - start_time)# 绘制FPScv2.putText(raw_frame, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)# 显示cv2.imshow("frame", raw_frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakout.write(raw_frame)else:breakout.release()  # 实例化
iou_tracker = IouTracker()
# 运行
iou_tracker.main()

测试效果,视频是马路上的,如果想要效果好,建议自己训练模型,使用的是yolov8n.pt模型

如有侵权,或需要完整代码,请及时联系博主。

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

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

相关文章

2020蓝桥杯省赛---java---B---7(单词分析)

题目描述 【问题描述】 小蓝正在学习一门神奇的语言&#xff0c;这门语言中的单词都是由小写英文字母组 成&#xff0c;有些单词很长&#xff0c;远远超过正常英文单词的长度。小蓝学了很长时间也记不 住一些单词&#xff0c;他准备不再完全记忆这些单词&#xff0c;而是根据单…

维护win10注册表

一、早期的注册表都是以后缀为.ini的配置文件 二、打开注册表编辑器&#xff1a;winr–>输入regedit–>回车 三、注册表结构&#xff1a;树状结构&#xff0c;分为5子树&#xff0c;每个项里面都有多个子项构成 四、子树的各项信息&#xff1a; 1.HKEY_LOCAL_MACHINE…

mybatis入门(五)之Java API

转载自 mybatis Java API Java API 既然你已经知道如何配置 MyBatis 和创建映射文件&#xff0c;你就已经准备好来提升技能了。MyBatis 的 Java API 就是你收获你所做的努力的地方。正如你即将看到的&#xff0c;和 JDBC 相比&#xff0c;MyBatis 很大程度简化了你的代码并…

c语言程序设计的一般错误的是,《C语言程序设计》第十章 程序常见错误分析.pdf...

第十章 程序常见错误分析第十章 程序常见错误分析C 语言是一种方便灵活、功能性很强的程序设计语言&#xff0c;但是对于初学者很难掌握&#xff0c;尤其是出了错还不知道错误在哪儿&#xff0c;这是由于 c 编译程序对语法的检查不如其他高级语言那样严格&#xff0c;往往要求设…

Dapper源码学习和源码修改(下篇)

继上篇Dapper源码学习和源码修改 讲了下自己学习Dapper的心得之后&#xff0c;下篇也随之而来&#xff0c;上篇主要讲的入参解析那下篇自然主打出参映射了。 好了&#xff0c;废话不多说&#xff0c;开始吧。 学习之前你的先学习怎么使用Dapper&#xff0c;这个我在上篇都提过…

2020蓝桥杯省赛---java---B---6(成绩分析)

题目描述 时间限制: 1.0s 内存限制: 512.0MB 本题总分&#xff1a;15 分【问题描述】 小蓝给学生们组织了一场考试&#xff0c;卷面总分为 100 分&#xff0c;每个学生的得分都是 一个 0 到 100 的整数。请计算这次考试的最高分、最低分和平均分。【输入格式】 输入的第一行包…

Photoshop基本操作

一、缩放工具&#xff1a; 1.按快捷键z,单击图片即可放大缩小 2.按住alt键&#xff0c;滚动鼠标滑轮&#xff0c;往上放大&#xff0c;往下缩小 3.如果细微缩放出不来&#xff1a;编辑–》首选项–》性能–》在openGL绘图前面的复选框中打钩–》确定–》重新开ps软件 二、抓手工…

c语言程序设计实践教程张卫国,C语言程序设计实践教程

本书包括三大章和六个附录。第一章介绍了VC6.0调试C语言程序的基础知识和方法&#xff0c;其目的是使读者掌握调试C语言程序的基本方法和技能&#xff0c;主要内容包括&#xff1a;VC6.0的安装、VC6.0的界面介绍、VC6.0错误类型及其查询方法、建立和运行C语言程序的方法以及VC6…

mybatis入门(六)之SQL语句构建器类

转载自 mybatis SQL语句构建器类 问题 Java程序员面对的最痛苦的事情之一就是在Java代码中嵌入SQL语句。这么来做通常是由于SQL语句需要动态来生成-否则可以将它们放到外部文件或者存储过程中。正如你已经看到的那样&#xff0c;MyBatis在它的XML映射特性中有一个强大的动…

2020蓝桥杯省赛---java---B---5(排序)

题目描述 思路分析 01231391&#xff0c;而01231314105。 让下标为j的字符提到最前&#xff0c;正好达到100次交换&#xff0c;这样也满足了最小字典序&#xff0c;也可以验证一下。 代码实现 package TEST;public class Main {public static void main(String[] args) {St…

ASP.NET Core MVC 源码学习:MVC 启动流程详解

前言 在 上一篇 文章中&#xff0c;我们学习了 ASP.NET Core MVC 的路由模块&#xff0c;那么在本篇文章中&#xff0c;主要是对 ASP.NET Core MVC 启动流程的一个学习。 ASP.NET Core 是新一代的 ASP.NET 应用程序&#xff0c;它是跨平台的&#xff0c;并且不依赖于 IIS&…

ps基础知识

一、ps全称&#xff1a;Adobe Photoshop &#xff0c;Adobe Photoshop是由Adobe Systems 开发和发行的专门用于图形图像处理的软件。 二、PS的应用领域&#xff1a; 1.在平面设计中的应用 2.在插画设计中的应用 3.在网页设计中的应用 4.在界面设计中的应用 5.在数码艺术中的应用…

Photoshop的绘图工具

一、油漆桶工具 1.快捷键&#xff1a;g 2.选区图像部分&#xff0c;使用油漆桶工具直接单击选区部分即可 3.返回上一步&#xff1a;ctrlshiftz 4.不透明度&#xff1a;一般我们调整不透明度的时候&#xff0c;使用调整图层的不透明度的方法来实现要求。 二、渐变工具&#xff1…

C语言调用es6,ES6 箭头函数、普通函数、调用方法

importReact,{Component} fromreact;import{Platform,StyleSheet,Text,Image,View,TouchableOpacity,ToastAndroid,} fromreact-native;export default classsrrowFunDemo extendsComponent {constructor(props) {super(props);this.state {data0: 点击0,data1: 点击1,data2: 点…

2020蓝桥杯省赛---java---B---9(子串分值和)

题目描述 时间限制: 3.0s 内存限制: 512.0MB 本题总分&#xff1a;25 分【问题描述】 对于一个字符串 S&#xff0c;我们定义 S 的分值 f(S) 为 S 中出现的不同的字符个 数。例如 f(”aba”) 2&#xff0c;f(”abc”) 3, f(”aaa”) 1。 现在给定一个字符串 S[0…n−1]&…

GitHub 贡献第一的微软开源软件列表

作者&#xff5c;木环 编辑&#xff5c;小智 在GitHub上贡献最多的公司&#xff0c;不是Facebook&#xff0c;也不是Google&#xff0c;而是微软。InfoQ对微软数个较受社区欢迎的项目进行了整理&#xff0c;以飨读者。希望开源的精神&#xff0c;能给技术社区带来更多的实惠&am…

mybatis入门(七)之日志

转载自 mybatis入门&#xff08;七&#xff09;之日志 Mybatis 的内置日志工厂提供日志功能&#xff0c;内置日志工厂将日志交给以下其中一种工具作代理&#xff1a; SLF4JApache Commons LoggingLog4j 2Log4jJDK logging MyBatis 内置日志工厂基于运行时自省机制选择合适…

Photoshop图像修饰工具

一、修饰工具&#xff1a; 1.准确来说是一个修饰工具组。 2.进行图像修饰时&#xff0c;没根据具体情况&#xff0c;进行针对性的选择相应的工具进行修饰。 二、仿制图章工具组: 1.仿制图章工具组 2.图案图章工具 三、修复工具组 1.污点修复画笔工具 2.修复画笔工具 3.修补工具…

android 画布控件,Android canvas画图操作之切割画布实现方法(clipRect)

本文实例讲述了Android canvas画图操作之切割画布实现方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;android切割画布的历程不算很难&#xff0c;可是理解起来也比较麻烦&#xff0c;这里写一下我的理解 但是不一定正确&#xff1a;canvas.clipRect(30,30,70,Reg…

MyBatis传入多个参数的问题

转载自 MyBatis传入多个参数的问题 一、单个参数&#xff1a; public List<XXBean> getXXBeanList(String xxCode); <select id"getXXXBeanList" parameterType"java.lang.String" resultType"XXBean">select t.* from tableN…