AI计算机视觉笔记二十七:YOLOV8实现目标追踪

简介: 本文介绍了使用YOLOv8实现人员检测与追踪的方法。通过为每个人员分配唯一ID,实现持续追踪,并可统计人数,适用于小区或办公楼出入管理。首先解释了目标检测与追踪的区别,接着详细描述了使用匈牙利算法和卡尔曼滤波实现目标关联的过程。文章提供了基于IOU实现追踪的具体步骤,包括环境搭建、模型加载及追踪逻辑实现。通过示例代码展示了如何使用YOLOv8进行实时视频处理,并实现人员追踪功能。测试结果显示,该方法在实际场景中具有较好的应用潜力。

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

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

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

一、简介

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

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

匈牙利算法可以告诉我们当前帧的某个目标,是否与前一帧的某个目标相同。
卡尔曼滤波可以基于目标前一时刻的位置,来预测当前时刻的位置,并且可以比传感器(在目标跟踪中即目标检测器,比如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,此方法对于运动慢的可以,效果差。
image.png

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 outputs
        boxes = boxes.cpu().numpy()  # convert to numpy array

        # 遍历每个框
        for box in boxes.data:
            l,t,r,b = box[:4].astype(np.int32) # left, top, right, bottom
            conf, 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)
        # 绘制FPS
        cv2.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'):
            break
    else:
        break

在终端里执行python demo.py
image.png

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 json

class IouTracker:
    def __init__(self):

        # 加载检测模型
        self.detection_model = YOLO("./yolov8n.pt")  
        # 获取类别 
        self.objs_labels = self.detection_model.names 
        # 打印类别
        print(self.objs_labels)
        # 只处理person
        self.track_classes = {0: 'person'}

        # 追踪的IOU阈值
        self.sigma_iou = 0.5
        # detection threshold
        self.conf_thresh = 0.3

    def 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
        # 计算IOU
        return size_intersection / size_union


    def 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 outputs
        boxes = boxes.cpu().numpy()  # convert to numpy array

        dets = [] # 检测结果
        # 遍历每个框
        for box in boxes.data:
            l,t,r,b = box[:4] # left, top, right, bottom
            conf, class_id = box[4:] # confidence, class
            # 排除不需要追踪的类别
            if class_id not in self.track_classes:
                continue
            dets.append({'bbox': [l,t,r,b], 'score': conf, 'class_id': class_id })
        return dets


    def 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 # 帧ID
        track_idx = 1 # 跟踪器ID

        # writer
        out = 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 = frame
                dets = 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 += 1
                    new_tracks.append(new_track)
                # 最终的跟踪器
                tracks_active = updated_tracks + new_tracks

                cross_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.2
                l,t = 0,0
                r,b = l+240,t+40
                raw_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 time
                end_time = time.time()
                # FPS
                fps = 1 / (end_time - start_time)
                # 绘制FPS
                cv2.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'):
                    break

                out.write(raw_frame)
            else:
                break

        out.release()  

# 实例化
iou_tracker = IouTracker()
# 运行
iou_tracker.main()

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

相关文章
|
8天前
|
人工智能 监控 自动驾驶
Migician:清北华科联手放大招!多图像定位大模型问世:3秒锁定跨画面目标,安防监控迎来AI革命!
Migician 是北交大联合清华、华中科大推出的多模态视觉定位模型,支持自由形式的跨图像精确定位、灵活输入形式和多种复杂任务。
60 3
Migician:清北华科联手放大招!多图像定位大模型问世:3秒锁定跨画面目标,安防监控迎来AI革命!
|
1天前
|
机器学习/深度学习 人工智能 监控
鸿蒙赋能智慧物流:AI类目标签技术深度解析与实践
在数字化浪潮下,物流行业面临变革,传统模式的局限性凸显。AI技术为物流转型升级注入动力。本文聚焦HarmonyOS NEXT API 12及以上版本,探讨如何利用AI类目标签技术提升智慧物流效率、准确性和成本控制。通过高效数据处理、实时监控和动态调整,AI技术显著优于传统方式。鸿蒙系统的分布式软总线技术和隐私保护机制为智慧物流提供了坚实基础。从仓储管理到运输监控再到配送优化,AI类目标签技术助力物流全流程智能化,提高客户满意度并降低成本。开发者可借助深度学习框架和鸿蒙系统特性,开发创新应用,推动物流行业智能化升级。
|
1天前
|
传感器 人工智能 搜索推荐
探索HarmonyOS在智慧出行领域的AI类目标签应用
在科技飞速发展的今天,智慧出行成为交通领域的重要发展方向。HarmonyOS凭借强大的系统能力,为智慧出行注入新活力,特别是在AI类目标签技术的应用上。通过精准分类和标签化处理车辆、路况及出行者数据,AI类目标签技术提升了出行体验与交通管理效率。HarmonyOS的分布式软总线技术和隐私保护机制,确保了设备间的无缝连接与数据安全。实际应用中,该技术助力智能交通管理和个性化出行服务,为解决交通拥堵、优化资源配置提供了新思路。开发者也迎来了广阔的机遇与挑战,共同推动智慧出行的美好未来。
|
1天前
|
人工智能 搜索推荐 vr&ar
让教育更智能:HarmonyOS助力AI类目标签革新教育行业
在科技飞速发展的当下,教育行业正经历深刻变革,智能化转型成为提升教育质量与效率的关键。AI类目标签技术脱颖而出,通过分析学生多维度数据生成个性化学习标签,助力因材施教;智能管理教学资源,提高备课效率。HarmonyOS NEXT API 12及以上版本的分布式能力和强大的数据安全机制,为多设备协同学习和数据保护提供了有力支持。开发者可利用鸿蒙生态构建创新教育应用,推动教育智能化发展。
|
1天前
|
机器学习/深度学习 人工智能 API
解锁HarmonyOS新姿势:金融风控中的AI类目标签实战
在金融行业中,风险控制是保障稳定与安全的核心。随着业务复杂化和数字化加深,传统风控手段难以应对新挑战。AI类目标签技术凭借强大的数据处理能力,为金融风控带来全新解决方案。本文探讨基于HarmonyOS NEXT API 12及以上版本,如何运用AI类目标签技术构建高效金融风控体系,助力开发者在鸿蒙生态中创新应用。通过精准风险识别、实时监测预警和优化信用评估,提升风控效果;结合鸿蒙系统的分布式软总线和隐私保护优势,实现无缝协同与数据安全。具体应用场景如信用卡欺诈防控和贷款审批风险评估,展示了技术的实际效益。
|
1天前
|
数据采集 人工智能 搜索推荐
影视行业大变革:HarmonyOS 下AI类目标签技术深度剖析
在影视行业蓬勃发展的背景下,AI类目标签技术凭借强大的分类与分析能力,成为数字化转型的关键驱动力。本文聚焦HarmonyOS NEXT API 12及以上版本,解析如何运用该技术提升内容管理、个性化推荐和用户体验,助力影视公司在鸿蒙生态下实现高效创作与创新。通过自动化标签生成,AI技术极大优化了素材管理和剪辑流程,提高了制作效率和质量。同时,基于用户行为数据的精准推荐,有效提升了平台流量和用户粘性。开发者需掌握相关API和深度学习框架,确保应用的准确性和兼容性,推动影视行业迈向智能化新时代。
|
3月前
|
人工智能 自然语言处理 搜索推荐
Open Notebook:开源 AI 笔记工具,支持多种文件格式,自动转播客和生成总结,集成搜索引擎等功能
Open Notebook 是一款开源的 AI 笔记工具,支持多格式笔记管理,并能自动将笔记转换为博客或播客,适用于学术研究、教育、企业知识管理等多个场景。
238 0
Open Notebook:开源 AI 笔记工具,支持多种文件格式,自动转播客和生成总结,集成搜索引擎等功能
|
4月前
|
人工智能 物联网 Shell
今日 AI 开源|共 12 项|开源的DIY健康追踪项目,基于低成本的智能戒指构建私人的健康监测应用
本文介绍了多个开源项目,涵盖了从量子计算错误纠正到视频生成和编辑的广泛应用领域。这些项目展示了AI技术在不同领域的创新和应用潜力。
338 10
今日 AI 开源|共 12 项|开源的DIY健康追踪项目,基于低成本的智能戒指构建私人的健康监测应用
|
3月前
|
人工智能 小程序 开发者
【一步步开发AI运动小程序】十一、人体关键点跳跃追踪
本文介绍如何利用“云智AI运动识别小程序插件”开发AI运动小程序,涵盖云上运动会、健身打卡等热门应用场景。通过示例代码展示如何调用插件功能,实现动作追踪与分析,助力开发者快速上手。
|
4月前
|
机器学习/深度学习 人工智能 算法
【AI系统】AI系统概述与设计目标
本文介绍了AI系统的全栈架构,涵盖设计目标、组成和生态。AI系统旨在连接硬件与应用,提供高效的模型服务和开发支持。文中探讨了高效编程语言、开发框架、工具链的重要性,以及AI任务系统级支持、自动编译优化和云原生自动分布式化等关键设计目标。此外,还详细讨论了AI训练与推理框架、AI编译与计算架构、AI硬件与体系结构等组成部分,以及AI算法和框架、更广泛的生态系统等。
201 1

热门文章

最新文章