赞
踩
本篇文章首先介绍YOLOV8实现人流量跟踪计数的原理,文末附代码下载地址
yolo8人流量统计
引言:行人跟踪统计是智能监控系统中的重要功能,可以广泛应用于人流控制、安全监控等领域。传统的行人跟踪算法往往受到光照、遮挡等因素的干扰,难以实现准确跟踪。随着深度学习技术的发展,目标检测模型逐渐成为行人跟踪的主流方案。本文介绍使用 YOLOv8 目标检测模型实现行人跟踪统计的方法。
一、YOLOv8模型介绍
YOLOv8 是 ultralytics 公司在 2023 年开源的 YOLOv5 的下一个重大更新版本,按照官方描述,YOLOv8 是一个 SOTA 模型,它建立在以前 YOLO 版本的成功基础上,并引入了新的功能和改进,以进一步提升性能和灵活性。不过 ultralytics 并没有直接将开源库命名为 YOLOv8,而是直接使用 ultralytics 这个词,原因是 ultralytics 将这个库定位为算法框架,而非某一个特定算法,一个主要特点是可扩展性。其希望这个库不仅仅能够用于 YOLO 系列模型,而是能够支持非 YOLO 模型以及分类分割姿态估计等各类任务。因此,YOLO发展到如今的版本,已经不单单是目标检测的代名词,就像官方所解释的那样,YOLOv8 更应该更名为Ultralytics 。目前YOLO8算法框架(ultralytics库)全面支持图像分类、目标检测和实例分割、人体关键点检测等任务。在目标跟踪方面,YOLO8算法库内置了多目标跟踪领域的SOTA算法(Byte-tracker和Bot-tracker)。在实例分割方面,支持与SAM、Fast-SAM无缝集成.....未来,我们也期待着ultralytics库能够扩充更多的CV领域的SOTA算法。
与之前的YOLO版本相比,YOLOv8在以下几个方面有所不同:
骨干网络:YOLOv8采用了全新的骨干网络,以提高模型的性能和准确性。YOLOv8的骨干网络是Darknet-53。Darknet-53是一个深度卷积神经网络模型,它由53个卷积层和池化层组成,用于提取图像特征。其实Darknet-53在YOLOv3网络中就已经被广泛使用,并在YOLOv4和YOLOv5中也得到了应用。它具有较强的特征提取能力,能够在目标检测任务中提供较好的性能。
检测头:YOLOv8采用了Anchor-Free的检测头,这意味着它不再需要预先定义一组固定的先验框来检测目标,而是可以直接从原始图像中预测目标的边界框,这有助于提高模型的灵活性和准确性。
损失函数:YOLOv8采用了新的损失函数,以更好地优化模型的训练过程,进一步提高模型的性能。YOLOv8的损失函数由多个部分组成,包括分类损失(VFL Loss)、回归损失为CIOU Loss+DFL的形式。
限于文章的篇幅,详细分析YOLO8的网络结构并不是本篇文章的重点,我们单独在另外一篇文章中详细介绍。接下来,我们来介绍一下如何使用yolo8实现行人跟踪计数。
二、基于yolo8实现行人统计
统计行人必须先要检测到行人。这不得不提一下YOLO目标检测实现的基本原理:基于将输入图像分割成若干个网格,然后对每个网格进行目标检测。每个网格会预测出多个bounding box(包含物体的矩形区域)以及这些box中包含物体的概率和物体的类别信息。具体来说,YOLO首先将输入图像分成SxS个格子,如果某个物体的中心位置的坐标落入到某个格子,那么这个格子就负责检测出这个物体。每个网格会预测B个bounding box的信息和C个物体属于某种类别的概率信息。Bounding box信息包含5个数据值,分别是x,y,w,h,和confidence,其中x,y是指当前格子预测得到的物体的bounding box的中心位置的坐标,w,h是bounding box的宽度和高度,confidence代表该box中是否包含物体的置信度。
由于yolo官方已经在COCO数据集上训练过yolov8,分别有yolo8n、yolo8m、yolo8s、yolo8l、yolo8x五种不同尺寸的模型。因此,使用yolov8的这五种预训练模型,可以识别COCO数据集上已有的80种物体。接下来,我们使用yolo官方提供的预训练模型YOLO8n,识别并统计一张图片中有多少个人。首先看下面的代码:
from ultralytics import YOLO
model=YOLO('./yolov8n.pt')#加载本地的yolo8n模型
# results=model.predict('./people.jpeg')
results=model('./people.jpeg')#推理本地图片
print(type(results))
print(type(results[0]))
上面的代码我们使用model('./people.jpeg')和model.predict('./people.jpeg)两种方式对图片进行推理预测
图片来源于网络
我们输出模型推理的结果,发现推理结果results是一个保存Results类的List数组,由于我们是一张一张图片推理的,因此List数组中仅有一个Results对象。
那么这个Results对象是干什么的呢?其实,这对象包含了YOLO8模型的所有预测信息,包括目标检测任务、图片分类任务、实例分割任务、人体关键点检测任务、多目标跟踪任务的所有预测信息都可以在这个对象中找到。因此,使用yolo8很简单,第一步配置好环境、第二步下载好模型、第三步写两行预测代码,后续的事情就是处理预测结果Results对象的事情了。下面我们来看一下Results对象中究竟都有什么属性。首先看一下YOLO官方对这个对象的注释:
- """
- A class for storing and manipulating inference results.
- Args:
- orig_img (numpy.ndarray): The original image as a numpy array.
- path (str): The path to the image file.
- names (dict): A dictionary of class names.
- boxes (torch.tensor, optional): A 2D tensor of bounding box coordinates for each detection.
- masks (torch.tensor, optional): A 3D tensor of detection masks, where each mask is a binary image.
- probs (torch.tensor, optional): A 1D tensor of probabilities of each class for classification task.
- keypoints (List[List[float]], optional): A list of detected keypoints for each object.
- Attributes:
- orig_img (numpy.ndarray): The original image as a numpy array.
- orig_shape (tuple): The original image shape in (height, width) format.
- boxes (Boxes, optional): A Boxes object containing the detection bounding boxes.
- masks (Masks, optional): A Masks object containing the detection masks.
- probs (Probs, optional): A Probs object containing probabilities of each class for classification task.
- keypoints (Keypoints, optional): A Keypoints object containing detected keypoints for each object.
- speed (dict): A dictionary of preprocess, inference, and postprocess speeds in milliseconds per image.
- names (dict): A dictionary of class names.
- path (str): The path to the image file.
- _keys (tuple): A tuple of attribute names for non-empty attributes.
- """
Results对象主要包含下列重要的属性:
boxes:该对象保存了目标检测的结果。
masks:该对象保存了实例分割的结果
probs:该对象保存了图像分类的结果
keypoints: 关键点检测的结果
names: 模型的类别
speed: 检测速度相关信息
orig_img:加载在内存中的原始图像
path:包含输入图像的路径
result对象默认是torch.Tensor对象,也可以转为其他对象
这里我们主要来看一下boxes对象的属性:
- """
- A class for storing and manipulating detection boxes.
- Args:
- boxes (torch.Tensor | numpy.ndarray): A tensor or numpy array containing the detection boxes,
- with shape (num_boxes, 6) or (num_boxes, 7). The last two columns contain confidence and class values.
- If present, the third last column contains track IDs.
- orig_shape (tuple): Original image size, in the format (height, width).
- Attributes:
- xyxy (torch.Tensor | numpy.ndarray): The boxes in xyxy format.
- conf (torch.Tensor | numpy.ndarray): The confidence values of the boxes.
- cls (torch.Tensor | numpy.ndarray): The class values of the boxes.
- id (torch.Tensor | numpy.ndarray): The track IDs of the boxes (if available).
- xywh (torch.Tensor | numpy.ndarray): The boxes in xywh format.
- xyxyn (torch.Tensor | numpy.ndarray): The boxes in xyxy format normalized by original image size.
- xywhn (torch.Tensor | numpy.ndarray): The boxes in xywh format normalized by original image size.
- data (torch.Tensor): The raw bboxes tensor (alias for `boxes`).
- Methods:
- cpu(): Move the object to CPU memory.
- numpy(): Convert the object to a numpy array.
- cuda(): Move the object to CUDA memory.
- to(*args, **kwargs): Move the object to the specified device.
- """
因此我们要统计一张图像的行人数,就非常容易了,见如下代码:
上面的代码中我们先统计模型检测到的所有的物体的数量,然后进一步筛序出person的个数。就完成了一张图片下的行人统计。
那么如果不是一张图片而是一段视频呢?我们知道,视频本质上是由一张张图片按照时间序列组成的,如果把一段视频拆成一张张图片然后再按照上面的方法,能不能统计出一段视频有多少人呢?答案是不行的,比如一段10帧的视频,但是整个视频只有一个人,试想如果把这段视频分成10张图片然后单独统计,最后是不是把一个人算成了10个人?这里涉及到了目标跟踪,目标跟踪是指在给定第一帧图像中的目标位置后,根据跟踪算法预测出后续帧中目标的位置。其基本原理包括特征提取、运动模型、外观模型、在线更新机制等部分。其中,特征提取用于提取图像目标的特征,运动模型用于描述帧与帧之间的目标运动状态关系,预测下一帧中目标的可能位置。在目标跟踪中,会为同一个被跟踪的物体赋予一个ID,以区别其他物体。因此,要想统计一段视频中有多少行人,势必要求我们使用目标跟踪技术手段。限于文章的篇幅,在这里,我们就不详细介绍目标跟踪领域的知识了。下面直接介绍Byte-Tracker多目标追踪算法,这也是YOLO8内置的一种多目标追踪算法。
ByteTracker是一种用于多目标跟踪的算法,它是基于深度学习的目标检测算法和跟踪算法的结合。ByteTracker算法的核心思想是在目标检测的基础上,利用目标之间的相似性和连续性,通过对目标进行跟踪,实现多目标跟踪。
ByteTracker算法的流程如下:
目标检测:首先使用目标检测算法对视频序列中的每一帧进行目标检测,获取每个目标的位置和大小。
特征提取:对于每个检测到的目标,利用深度学习网络提取其特征,这些特征将被用于后续的跟踪过程。
目标跟踪:在连续帧之间,利用目标的特征相似性和运动连续性,建立目标之间的对应关系,实现目标的跟踪。
数据关联:将不同帧中的目标进行跟踪,需要解决数据关联问题,即确定哪些目标属于同一个轨迹。ByteTracker采用了一种基于匈牙利算法的数据关联方法。
轨迹管理:对于每个目标轨迹,需要对其进行起始、终止、更新等操作,以便实现多目标跟踪。
下面我们来看,如何在yolo8中使用这种多目标追踪算法,实现视频人流量追踪统计。
实现起来非常简单,也仅仅只需要一行代码。
model.track(source=source)即可调用yolo8内置的跟踪模式,但是默认使用的是BotTracker跟踪算法,这是yolo8内置的另外一种算法,在具有遮挡的情况下,效果非常好,比Byte-tracker、DeepSort、Sort等算法准确许多。但是速度却比这些算法慢,我们这里使用byte-tracker跟踪算法,需要在track()中指定tracker="bytetrack.yaml"即可。上图代码中,classes=[0]表示只检测行人,忽略其他物体。
还记得yolo8返回的Results对象的boxes属性吗,在使用track模式后,boxes对象的id就不再像是在目标检测任务那样为None,它现在有了唯一的值,只要跟踪算法没有丢失目标,这个id值就一直不会变,因此这个值就可以用来区分不同的物体。比如,同一个人一直都是一个id值,除非跟踪算法丢失了这个人。
我们可以一边遍历Results的结果一边把id值放在一个set()中,最后统计set()的长度,这样就实现了统计一个视频中的人数。
我们在视频中划定两个区域,如本篇文章的第一个视频所示,线的上方和下方其实各有一个不可见的区域。如果一个人的出现在上面的区域,之后又出现下面的区域,说明这个人是从视频的上方向下方行走,这样就可以知道一个人的轨迹方向了,就可以按照方向统计人流量了。比如本篇文章的第一个视频,人物从视频下方向上方走,视为‘出’,而从上方移动到下方,视为‘进’。
另外,限于本篇文章的篇幅,更细致的逻辑讲解、代码实现将在源码注释中体现,需要源码的小伙伴记得给文章点赞收藏哦。源码资源放在公众号中了,微信公众号搜索 ‘编程学习园地’,关注公众号,在聊天窗口回复关键字“yolo8实战”即可获得下载链接。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。