YOLOv8目标跟踪model.track的封装

2024-06-22 03:28

本文主要是介绍YOLOv8目标跟踪model.track的封装,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

YOLOv8目标跟踪model.track的封装

flyfish

在使用目标跟踪时, 调用model.track整个步骤就完成,track封装了内部运行的步骤。这里主要说回调部分。
使用model.track

import cv2from ultralytics import YOLO
from collections import defaultdict
import numpy as nptrack_history = defaultdict(lambda: [])
# Open the video file
video_path = "1.mp4"model = YOLO("yolov8s.pt")# Open the video filecap = cv2.VideoCapture(video_path)# Retrieve video properties: width, height, and frames per second
w, h, fps = (int(cap.get(x)) for x in (cv2.CAP_PROP_FRAME_WIDTH, cv2.CAP_PROP_FRAME_HEIGHT, cv2.CAP_PROP_FPS))# Initialize video writer to save the output video with the specified properties
out = cv2.VideoWriter("detection-object-tracking-bytetrack.avi", cv2.VideoWriter_fourcc(*"MJPG"), fps, (w, h))# Loop through the video frames
while cap.isOpened():# Read a frame from the videosuccess, frame = cap.read()if success:# Run YOLOv8 tracking on the frame, persisting tracks between framesresults = model.track(frame, persist=True,tracker="bytetrack.yaml")# Get the boxes and track IDsboxes = results[0].boxes.xywh.cpu()track_ids = results[0].boxes.id.int().cpu().tolist()# Visualize the results on the frameannotated_frame = results[0].plot()# Plot the tracksfor box, track_id in zip(boxes, track_ids):x, y, w, h = boxtrack = track_history[track_id]track.append((float(x), float(y)))  # x, y center pointif len(track) > 30:  # retain 90 tracks for 90 framestrack.pop(0)# Draw the tracking linespoints = np.hstack(track).astype(np.int32).reshape((-1, 1, 2))cv2.polylines(annotated_frame,[points],isClosed=False,color=(230, 230, 230),thickness=10,) # Display the annotated frameout.write(annotated_frame)cv2.imshow("YOLOv8 Tracking", annotated_frame)# Break the loop if 'q' is pressedif cv2.waitKey(1) & 0xFF == ord("q"):breakelse:# Break the loop if the end of the video is reachedbreak# Release the video capture object and close the display window
out.release()
cap.release()
cv2.destroyAllWindows()

model.track 背后就是回调
我们分析下它的回调代码
model.predict()方法会触发on_predict_starton_predict_postprocess_end事件
分析回调

from functools import partial
from pathlib import Pathimport torchfrom ultralytics.utils import IterableSimpleNamespace, yaml_load
from ultralytics.utils.checks import check_yamlfrom .bot_sort import BOTSORT
from .byte_tracker import BYTETracker# A mapping of tracker types to corresponding tracker classes
TRACKER_MAP = {"bytetrack": BYTETracker, "botsort": BOTSORT}def on_predict_start(predictor: object, persist: bool = False) -> None:"""Initialize trackers for object tracking during prediction.Args:predictor (object): The predictor object to initialize trackers for.persist (bool, optional): Whether to persist the trackers if they already exist. Defaults to False.Raises:AssertionError: If the tracker_type is not 'bytetrack' or 'botsort'."""if hasattr(predictor, "trackers") and persist:returntracker = check_yaml(predictor.args.tracker)cfg = IterableSimpleNamespace(**yaml_load(tracker))if cfg.tracker_type not in {"bytetrack", "botsort"}:raise AssertionError(f"Only 'bytetrack' and 'botsort' are supported for now, but got '{cfg.tracker_type}'")trackers = []for _ in range(predictor.dataset.bs):tracker = TRACKER_MAP[cfg.tracker_type](args=cfg, frame_rate=30)trackers.append(tracker)if predictor.dataset.mode != "stream":  # only need one tracker for other modes.breakpredictor.trackers = trackerspredictor.vid_path = [None] * predictor.dataset.bs  # for determining when to reset tracker on new videodef on_predict_postprocess_end(predictor: object, persist: bool = False) -> None:"""Postprocess detected boxes and update with object tracking.Args:predictor (object): The predictor object containing the predictions.persist (bool, optional): Whether to persist the trackers if they already exist. Defaults to False."""path, im0s = predictor.batch[:2]is_obb = predictor.args.task == "obb"is_stream = predictor.dataset.mode == "stream"for i in range(len(im0s)):tracker = predictor.trackers[i if is_stream else 0]vid_path = predictor.save_dir / Path(path[i]).nameif not persist and predictor.vid_path[i if is_stream else 0] != vid_path:tracker.reset()predictor.vid_path[i if is_stream else 0] = vid_pathdet = (predictor.results[i].obb if is_obb else predictor.results[i].boxes).cpu().numpy()if len(det) == 0:continuetracks = tracker.update(det, im0s[i])if len(tracks) == 0:continueidx = tracks[:, -1].astype(int)predictor.results[i] = predictor.results[i][idx]update_args = {"obb" if is_obb else "boxes": torch.as_tensor(tracks[:, :-1])}predictor.results[i].update(**update_args)def register_tracker(model: object, persist: bool) -> None:"""Register tracking callbacks to the model for object tracking during prediction.Args:model (object): The model object to register tracking callbacks for.persist (bool): Whether to persist the trackers if they already exist."""model.add_callback("on_predict_start", partial(on_predict_start, persist=persist))model.add_callback("on_predict_postprocess_end", partial(on_predict_postprocess_end, persist=persist))

简单仿写,可以独立运行

 def on_predict_start(predictor: object, persist: bool = False) -> None:# 回调函数代码print("on_predict_start")passdef on_predict_postprocess_end(predictor: object, persist: bool = False) -> None:# 回调函数代码print("on_predict_postprocess_end")pass
from functools import partialdef register_tracker(model: object, persist: bool) -> None:model.add_callback("on_predict_start", partial(on_predict_start, persist=persist))model.add_callback("on_predict_postprocess_end", partial(on_predict_postprocess_end, persist=persist))from functools import partialclass Model:def __init__(self):self.callbacks = {"on_predict_start": [], "on_predict_postprocess_end": []}def add_callback(self, event, callback):if event in self.callbacks:self.callbacks[event].append(callback)def predict(self):# 触发'on_predict_start'事件for callback in self.callbacks["on_predict_start"]:callback(self)# 模拟预测过程print("Predicting...")# 触发'on_predict_postprocess_end'事件for callback in self.callbacks["on_predict_postprocess_end"]:callback(self)# 使用例子 model.predict()方法会触发on_predict_start和on_predict_postprocess_end事件,调用已注册的回调函数。
model = Model()
register_tracker(model, persist=True)
model.predict()

输出

on_predict_start
Predicting...
on_predict_postprocess_end

partial应用在回调函数中
在回调函数的场景中,partial 特别有用,因为它允许预设某些参数,而不是在每次调用时都传入这些参数。

假设有一个回调函数,它需要两个参数,但是在注册回调函数时,只能传入一个参数:

def callback_function(event, persist):print(f"Event: {event}, Persist: {persist}")

希望将这个函数作为回调函数,但是只希望在事件发生时传入 event 参数,而 persist 参数是预设好的。这时可以使用 partial:

from functools import partial# 预设 persist 参数
partial_callback = partial(callback_function, persist=True)# 当事件发生时,只需要传入 event 参数
partial_callback(event="on_predict_start")  # 输出: Event: on_predict_start, Persist: True

这篇关于YOLOv8目标跟踪model.track的封装的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1083152

相关文章

公共筛选组件(二次封装antd)支持代码提示

如果项目是基于antd组件库为基础搭建,可使用此公共筛选组件 使用到的库 npm i antdnpm i lodash-esnpm i @types/lodash-es -D /components/CommonSearch index.tsx import React from 'react';import { Button, Card, Form } from 'antd'

YOLOv8改进 | SPPF | 具有多尺度带孔卷积层的ASPP【CVPR2018】

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有40+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进——点击即可跳转 Atrous Spatial Pyramid Pooling (ASPP) 是一种在深度学习框架中用于语义分割的网络结构,它旨

React+TS前台项目实战(十七)-- 全局常用组件Dropdown封装

文章目录 前言Dropdown组件1. 功能分析2. 代码+详细注释3. 使用方式4. 效果展示 总结 前言 今天这篇主要讲全局Dropdown组件封装,可根据UI设计师要求自定义修改。 Dropdown组件 1. 功能分析 (1)通过position属性,可以控制下拉选项的位置 (2)通过传入width属性, 可以自定义下拉选项的宽度 (3)通过传入classN

axios全局封装AbortController取消重复请求

为什么? 问题:为什么axios要配置AbortController?防抖节流不行吗? 分析: 防抖节流本质上是用延时器来操作请求的。防抖是判断延时器是否存在,如果存在,清除延时器,重新开启一个延时器,只执行最后一次请求。节流呢,是判断延时器是否存在,如果存在,直接return掉,直到执行完这个延时器。事实上,这些体验感都不算友好,因为对于用户来说,得等一些时间,尤其是首次请求,不是那么流畅

Python利用qq邮箱发送通知邮件(已封装成model)

因为经常喜欢写一些脚本、爬虫之类的东西,有需要通知的时候,总是苦于没有太好的通知方式,虽然邮件相对于微信、短信来说,接收性差了一些,但毕竟免费,而且支持html直接渲染,所以,折腾了一个可以直接使用的sendemail模块。这里主要应用的是QQ发邮件,微信关注QQ邮箱后,也可以实时的接收到消息,肾好! 好了,废话不多说,直接上代码。 # encoding: utf-8import lo

3月份目标——刷完乙级真题

https://www.patest.cn/contests/pat-b-practisePAT (Basic Level) Practice (中文) 标号标题通过提交通过率1001害死人不偿命的(3n+1)猜想 (15)31858792260.41002写出这个数 (20)21702664840.331003我要通过!(20)11071447060.251004成绩排名 (20)159644

线程封装,互斥

文章目录 线程封装线程互斥加锁、解锁认识接口解决问题理解锁 线程封装 C/C++代码混编引起的问题 此处pthread_create函数要求传入参数为void * func(void * )类型,按理来说ThreadRoutine满足,但是 这是在内类完成封装,所以ThreadRoutine函数实际是两个参数,第一个参数Thread* this不显示 解决方法: 第

示例:推荐一个基于第三方开源控件库DataGridFilter封装的FilterColumnDataGrid,可以像Excel拥有列头筛选器

一、目的:基于第三方开源控件库DataGridFilter封装的FilterColumnDataGrid,可以像Excel拥有列头筛选器,感兴趣的可以去下方链接地址查看开源控件库地址。本控件封装的目的在于将第三方库的皮肤和样式封装到皮肤库中可统一设置样式,同时生成nuget方便调用 二、效果如下 三、环境 VS2022 Net7 四、使用方式 1、安装nuget包:H.Con

基于动力学的六自由度机器人阻抗恒力跟踪控制

1.整个代码的控制流程图如下: 2.正逆运动学计算 略 3.动力学模型 采用拉格朗日法计算机械臂的动力学模型,其输入的是机械臂的关节角度、角速度和角加速度;其中M、C、G本别是计算的惯性力、科式力和重力项,相关部分如下: 4.RBF神经网络自适应参数调节 采用RBF自适应调节阻抗控制器参数,末端每个方向单独进行参数的调整,其中rbf的输入的是力和位置,输出的是阻抗控制器的参数,rb

C语言封装获取本机IP地址的程序

文章目录 0.概要1. 设计2. 完整的代码`ip_address.h``ip_address.c``main.c`编译命令执行结果 0.概要 本文介绍用C语言编写一个函数来获取本机的IP地址。 1. 设计 将获取IP地址的逻辑封装到一个独立的函数中,并定义一个结构体来存储IP地址和接口名称。 将获取IP地址的逻辑封装到一个函数中,该函数遍历本机的所有网络接口并获取其IP