《博主简介》
小伙伴们好,我是阿旭。
专注于计算机视觉领域,包括目标检测、图像分类、图像分割和目标跟踪等项目开发,提供模型对比实验、答疑辅导等。
《------往期经典推荐------》
二、机器学习实战专栏【链接】 ,已更新31期,欢迎关注,持续更新中~~
三、深度学习【Pytorch】专栏【链接】
四、【Stable Diffusion绘画系列】专栏【链接】
五、YOLOv8改进专栏【链接】,持续更新中~~
六、YOLO性能对比专栏【链接】,持续更新中~
《------正文------》
目录
- 引言
- 一、环境准备
- 二、完整代码
- 三、核心代码逐行解析
-
- [3.1 库导入](#3.1 库导入)
- [3.2 类初始化方法](#3.2 类初始化方法)
- [3.3 自定义静态方法](#3.3 自定义静态方法)
-
- [3.3.1 `draw_text_with_bg`:绘制带背景的文字](#3.3.1
draw_text_with_bg:绘制带背景的文字) - [3.3.2 `draw_bbox`:绘制自定义边界框](#3.3.2
draw_bbox:绘制自定义边界框)
- [3.3.1 `draw_text_with_bg`:绘制带背景的文字](#3.3.1
- [3.4 主推理循环](#3.4 主推理循环)
- [3.5 程序入口](#3.5 程序入口)
- 四、代码运行步骤
- 五、使用注意事项
- 六、总结
引言

YOLO26作为YOLO系列的全新版本,在检测速度和精度上都有不小的提升,而ONNX格式的模型又能实现跨平台的灵活部署,是工程落地的优选。今天就给大家带来一篇YOLO26-ONNX模型实现视频实时目标检测的实战教程,这份代码不仅完成了核心的检测推理,还做了自定义的可视化美化、FPS/处理时间统计,甚至能自动保存检测后的视频,直接拿过去就能用,新手也能轻松上手!
一、环境准备
首先要搭建好运行环境,这份代码基于Python编写,核心依赖三个库:opencv-python(用于视频读写和图像绘制)、ultralytics(YOLO系列的核心库,支持YOLO26和ONNX模型加载)、time(Python内置库,无需额外安装)。
直接执行以下命令安装依赖即可:
bash
pip install opencv-python ultralytics
二、完整代码
先把完整代码贴出来,大家可以先复制保存,后续我们逐行拆解核心逻辑:
python
# 导入OpenCV库,用于视频读写、图像绘制
import cv2
# 导入时间库,用于统计推理时长和计算FPS
import time
# 从ultralytics库导入YOLO类,核心用于加载模型和推理
from ultralytics import YOLO
# 导入颜色生成工具,为不同检测类别分配专属颜色
from ultralytics.utils.plotting import colors
class YOLOVisualizer:
"""
YOLO26-ONNX视频实时检测可视化类
功能:加载模型、读取视频/摄像头、实时推理、自定义可视化、保存结果
"""
def __init__(self, source=0, model="yolo26n.onnx", device="cpu"):
"""
类初始化方法,完成资源加载和参数配置
:param source: 检测源,0为电脑摄像头,字符串为视频文件路径
:param model: YOLO26的ONNX模型文件路径
:param device: 推理设备,cpu为CPU推理,cuda为GPU推理
"""
# 保存传入的核心参数
self.source = source
self.model_path = model
self.device = device
# 加载YOLO26-ONNX模型,指定任务为目标检测
self.model = YOLO(model, task="detect")
# 获取模型的类别名称字典(键为类别ID,值为类别名称,如0: person)
self.names = self.model.names
# 打开视频源(摄像头/视频文件)
self.cap = cv2.VideoCapture(source)
# 获取视频的核心参数:宽度、高度、原始FPS
w = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(self.cap.get(cv2.CAP_PROP_FPS))
# 创建视频写入器,用于保存检测后的视频
# 输出文件名:yolo-output.avi,编码格式:mp4v,FPS和分辨率与原视频一致
self.video_writer = cv2.VideoWriter(
"yolo-output.avi",
cv2.VideoWriter_fourcc(*"mp4v"),
fps,
(w, h),
)
# 初始化列表,用于存储每帧的FPS,后续计算平均FPS
self.avg_fps = []
@staticmethod
def draw_text_with_bg(
img,
text,
pos,
font_scale=0.6,
bg_color=(0, 0, 0),
fg_color=(104, 31, 17),
padding=15,
thickness=4,
):
"""
静态方法:绘制带实心背景的文字,解决视频中文字看不清的问题
:param img: 待绘制的图像帧
:param text: 要显示的文字内容
:param pos: 文字背景矩形的左上角坐标
:param font_scale: 文字大小
:param bg_color: 背景矩形颜色
:param fg_color: 文字颜色
:param padding: 背景矩形的内边距
:param thickness: 文字粗细
"""
# 选择字体类型
font = cv2.FONT_HERSHEY_SIMPLEX
# 计算文字的宽度、高度和基线
(text_width, text_height), baseline = cv2.getTextSize(
text, font, font_scale, thickness
)
# 计算背景矩形的实际宽高(文字尺寸+2倍内边距)
rect_width = text_width + 2 * padding
rect_height = text_height + baseline + 2 * padding
# 计算背景矩形的右下角坐标
rect_x1, rect_y1 = pos
rect_x2, rect_y2 = rect_x1 + rect_width, rect_y1 + rect_height
# 绘制实心背景矩形
cv2.rectangle(img, (rect_x1, rect_y1), (rect_x2, rect_y2), bg_color, -1)
# 计算文字的居中坐标
text_x = rect_x1 + (rect_width - text_width) // 2
text_y = rect_y1 + (rect_height + text_height) // 2
# 绘制文字,LINE_AA参数让文字边缘更平滑
cv2.putText(
img,
text,
(text_x, text_y),
font,
font_scale,
fg_color,
thickness,
cv2.LINE_AA,
)
@staticmethod
def draw_bbox(img, box, label="", conf=None, cls_id=0):
"""
静态方法:绘制自定义样式的边界框和类别标签
:param img: 待绘制的图像帧
:param box: 边界框坐标,格式为[x1, y1, x2, y2]
:param label: 类别名称标签
:param conf: 检测置信度(本文未显示,预留参数)
:param cls_id: 检测类别ID
"""
# 将边界框坐标转换为整数(模型输出为浮点数)
x1, y1, x2, y2 = map(int, box)
# 为类别分配颜色,类别2(默认是汽车)单独使用颜色11,其余按ID分配
color = colors(11 if cls_id == 2 else cls_id, True)
# 边界框线宽
thickness = 3
# 绘制目标边界框
cv2.rectangle(img, (x1, y1), (x2, y2), color, thickness)
# 若有类别标签,绘制标签框
if label:
text_scale = 1.4 # 标签文字大小
thickness_text = 2 # 标签文字粗细
# 计算标签文字的尺寸
(tw, th), baseline = cv2.getTextSize(
label, cv2.FONT_HERSHEY_SIMPLEX, text_scale, thickness_text
)
pad = 8 # 标签框内边距
# 初始设置标签框在边界框上方
lx1, ly1 = x1, y1 - (th + baseline + 2 * pad)
lx2, ly2 = x1 + tw + 2 * pad, y1
# 若标签框超出图像顶部,将其移至边界框下方
if ly1 < 0:
ly1 = y1
ly2 = y1 + th + baseline + 2 * pad
# 绘制标签实心背景框
cv2.rectangle(img, (lx1, ly1), (lx2, ly2), color, -1)
# 计算标签文字的居中坐标
text_x = lx1 + (lx2 - lx1 - tw) // 2
text_y = ly1 + (ly2 - ly1 + th) // 2
# 绘制类别标签文字
cv2.putText(
img,
label,
(text_x, text_y),
cv2.FONT_HERSHEY_SIMPLEX,
text_scale,
(255, 255, 255),
thickness_text,
cv2.LINE_AA,
)
def run(self):
"""
类核心方法:执行视频实时检测的主循环
"""
# 循环读取视频帧,直到视频源关闭或读取失败
while self.cap.isOpened():
# 读取一帧视频,ret为读取成功标志,frame为图像帧数据
ret, frame = self.cap.read()
if not ret:
# 读取失败(视频结束),终止循环
break
# 记录推理开始时间
start_time = time.time()
# 模型推理:传入图像帧,指定推理设备,置信度阈值0.25
# 取结果列表的第一个元素(单帧推理结果)
results = self.model.predict(frame, device=self.device, conf=0.25)[0]
# 计算单帧处理总时长(秒)
process_time = time.time() - start_time
# 解析推理结果:边界框坐标
boxes = results.boxes.xyxy.tolist()
# 解析推理结果:类别ID
clss = results.boxes.cls.tolist()
# 解析推理结果:检测置信度
confs = results.boxes.conf.cpu().numpy()
# 遍历所有检测结果,逐一生成边界框和标签
for box, cls, conf in zip(boxes, clss, confs):
cls = int(cls) # 类别ID转换为整数
# 调用方法绘制边界框和标签
self.draw_bbox(
frame,
box,
label=self.names[cls], # 传入类别名称
conf=conf,
cls_id=cls,
)
# 计算单帧FPS并加入列表,用于后续求平均值
self.avg_fps.append(1.0 / process_time if process_time > 0 else 0)
avg_fps = sum(self.avg_fps) / len(self.avg_fps)
# 绘制平均FPS信息
self.draw_text_with_bg(
frame,
f"FPS: {int(avg_fps)}",
(25, 45),
bg_color=(104, 31, 17),
fg_color=(255, 255, 255),
font_scale=2.2,
)
# 绘制单帧处理时间(转换为毫秒)
self.draw_text_with_bg(
frame,
f"Time: {process_time * 1000:.0f}ms",
(360, 45),
bg_color=(104, 0, 123),
font_scale=2.2,
)
# 显示实时检测画面
cv2.imshow("Ultralytics YOLO26 实时检测", frame)
# 将检测后的帧写入视频文件
self.video_writer.write(frame)
# 监听键盘输入,按q键立即退出检测
if cv2.waitKey(1) & 0xFF == ord("q"):
break
# 释放视频源资源
self.cap.release()
# 释放视频写入器资源
self.video_writer.release()
# 销毁所有OpenCV显示窗口
cv2.destroyAllWindows()
if __name__ == "__main__":
# YOLO26-ONNX模型导出命令(终端执行):
# yolo export format=onnx model=yolo26n.onnx
# 实例化检测可视化类
# source:视频文件路径(本地视频)/ 0(摄像头)
# model:导出的YOLO26 ONNX模型路径
visualizer = YOLOVisualizer(source=r"horse-rider.mp4", model="yolo26n.onnx")
# 执行实时检测
visualizer.run()
三、核心代码逐行解析
这份代码采用面向对象 的方式封装,把YOLO检测、可视化、视频处理的逻辑都整合在YOLOVisualizer类中,复用性极高,我们按类初始化 、自定义可视化函数 、主推理循环 、程序入口四个部分解析。
3.1 库导入
python
import cv2
import time
from ultralytics import YOLO
from ultralytics.utils.plotting import colors
cv2:OpenCV核心库,负责视频/摄像头的帧读取、图像绘制、视频保存;time:用于统计单帧的处理时间,计算FPS;YOLO:ultralytics库的核心类,支持加载YOLO26的ONNX模型并执行推理;colors:ultralytics内置的颜色生成函数,为不同检测类别分配专属颜色,让可视化更清晰。
3.2 类初始化方法
这部分是程序的初始化配置,完成模型加载、视频读取、视频写入器创建等工作,传入3个参数:
source:检测源,0为电脑摄像头,字符串为视频文件路径;model:YOLO26的ONNX模型路径;device:推理设备,cpu/gpu均可。
python
def __init__(self, source=0, model="yolo26n.onnx", device="cpu"):
self.source = source
self.model_path = model
self.device = device
# 加载YOLO26-ONNX模型,指定任务为目标检测
self.model = YOLO(model, task="detect")
self.names = self.model.names # 获取模型的类别名称字典(如0:person,1:bicycle)
# 打开视频/摄像头
self.cap = cv2.VideoCapture(source)
# 获取视频的宽度、高度、原始FPS
w, h, fps = (
int(self.cap.get(x))
for x in (
cv2.CAP_PROP_FRAME_WIDTH,
cv2.CAP_PROP_FRAME_HEIGHT,
cv2.CAP_PROP_FPS,
)
)
# 创建视频写入器,将检测后的视频保存为yolo-output.avi
self.video_writer = cv2.VideoWriter(
"yolo-output.avi",
cv2.VideoWriter_fourcc(*"mp4v"), # 视频编码格式
fps, # 保存视频的FPS与原视频一致
(w, h), # 保存视频的分辨率与原视频一致
)
self.avg_fps = [] # 用于存储每帧的FPS,计算平均FPS
3.3 自定义静态方法
代码中写了两个静态方法 (无需实例化即可调用,也可在类内直接使用),分别实现带背景的文字绘制 和带标签的自定义边界框绘制,这是比YOLO默认可视化更美观、更实用的地方。
3.3.1 draw_text_with_bg:绘制带背景的文字
解决了直接绘制文字在视频中看不清的问题,为文字添加实心背景矩形,还支持文字居中、自定义颜色/大小/内边距。
python
@staticmethod
def draw_text_with_bg(img, text, pos, font_scale=0.6, bg_color=(0,0,0), fg_color=(104,31,17), padding=15, thickness=4):
font = cv2.FONT_HERSHEY_SIMPLEX # 字体
# 计算文字的宽高和基线
(text_width, text_height), baseline = cv2.getTextSize(text, font, font_scale, thickness)
# 计算背景矩形的宽高(文字宽高+左右/上下内边距)
rect_width = text_width + 2 * padding
rect_height = text_height + baseline + 2 * padding
# 背景矩形的左上角/右下角坐标
rect_x1, rect_y1 = pos
rect_x2, rect_y2 = rect_x1 + rect_width, rect_y1 + rect_height
# 绘制实心背景矩形
cv2.rectangle(img, (rect_x1, rect_y1), (rect_x2, rect_y2), bg_color, -1)
# 计算文字的居中坐标
text_x = rect_x1 + (rect_width - text_width) // 2
text_y = rect_y1 + (rect_height + text_height) // 2
# 绘制文字,LINE_AA让文字边缘更平滑
cv2.putText(img, text, (text_x, text_y), font, font_scale, fg_color, thickness, cv2.LINE_AA)
3.3.2 draw_bbox:绘制自定义边界框
为检测目标绘制带类别标签的彩色边界框,核心亮点:
- 为不同类别分配专属颜色,类别2(默认是汽车)单独分配颜色11,区分更明显;
- 自动调整标签框位置,防止标签超出视频帧范围;
- 标签框与边界框同色,视觉更统一。
python
@staticmethod
def draw_bbox(img, box, label="", conf=None, cls_id=0):
x1, y1, x2, y2 = map(int, box) # 边界框坐标转整数(模型输出为浮点数)
color = colors(11 if cls_id == 2 else cls_id, True) # 为类别分配颜色
thickness = 3 # 边界框线宽
cv2.rectangle(img, (x1, y1), (x2, y2), color, thickness) # 绘制边界框
if label: # 如果有类别标签,绘制标签框
text_scale = 1.4
thickness_text = 2
# 计算标签文字的宽高
(tw, th), baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, text_scale, thickness_text)
pad = 8 # 标签框内边距
# 初始标签框位置(在边界框上方)
lx1, ly1 = x1, y1 - (th + baseline + 2 * pad)
lx2, ly2 = x1 + tw + 2 * pad, y1
# 若标签框超出帧顶部,将其移到边界框下方
if ly1 < 0:
ly1 = y1
ly2 = y1 + th + baseline + 2 * pad
cv2.rectangle(img, (lx1, ly1), (lx2, ly2), color, -1) # 绘制标签实心框
# 文字居中绘制
text_x = lx1 + (lx2 - lx1 - tw) // 2
text_y = ly1 + (ly2 - ly1 + th) // 2
cv2.putText(img, label, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, text_scale, (255,255,255), thickness_text, cv2.LINE_AA)
3.4 主推理循环
这是整个程序的核心执行逻辑 ,实现逐帧读取→模型推理→结果解析→可视化绘制→FPS统计→帧显示/保存→退出逻辑的闭环,一步到位。
python
def run(self):
while self.cap.isOpened(): # 循环读取视频帧,直到视频结束/摄像头关闭
ret, frame = self.cap.read() # 读取一帧,ret为是否读取成功,frame为帧图像
if not ret: # 读取失败(视频结束),退出循环
break
start_time = time.time() # 记录推理开始时间
# 模型推理:传入帧图像,指定设备,置信度阈值0.25(只保留置信度>25%的检测结果)
results = self.model.predict(frame, device=self.device, conf=0.25)[0]
process_time = time.time() - start_time # 计算单帧处理时间(秒)
# 解析推理结果
boxes = results.boxes.xyxy.tolist() # 边界框坐标(x1,y1,x2,y2),转列表
clss = results.boxes.cls.tolist() # 检测类别ID,转列表
confs = results.boxes.conf.cpu().numpy() # 检测置信度,转numpy数组
# 遍历每个检测结果,绘制边界框
for box, cls, conf in zip(boxes, clss, confs):
cls = int(cls)
self.draw_bbox(frame, box, label=self.names[cls], conf=conf, cls_id=cls)
# 计算平均FPS
self.avg_fps.append(1.0 / process_time if process_time > 0 else 0)
fps = sum(self.avg_fps) / len(self.avg_fps)
# 绘制FPS和单帧处理时间(转毫秒)
self.draw_text_with_bg(frame, f"FPS: {int(fps)}", (25, 45), bg_color=(104,31,17), fg_color=(255,255,255), font_scale=2.2)
self.draw_text_with_bg(frame, f"Time: {process_time * 1000:.0f}ms", (360, 45), bg_color=(104,0,123), fg_color=(255,255,255), font_scale=2.2)
cv2.imshow("Ultralytics YOLO", frame) # 显示检测后的帧窗口
self.video_writer.write(frame) # 将检测后的帧写入视频文件
# 按q键退出检测(等待1ms,检测键盘输入)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
# 释放资源:关闭视频/摄像头、关闭视频写入器、销毁所有显示窗口
self.cap.release()
self.video_writer.release()
cv2.destroyAllWindows()
3.5 程序入口
这部分是程序的启动项 ,只需实例化YOLOVisualizer类,调用run方法即可执行检测,同时给出了YOLO26-ONNX模型的导出命令,直接复制就能用。
python
if __name__ == "__main__":
# YOLO26-ONNX模型导出命令,在终端执行即可
# Export command: yolo export format=onnx model=yolo26n.onnx
# 实例化类:指定检测视频为horse-rider.mp4,模型为yolo26n.onnx
visualizer = YOLOVisualizer(source=r"horse-rider.mp4", model="yolo26n.onnx")
visualizer.run() # 执行检测
四、代码运行步骤
这份代码的运行步骤非常简单,分3步即可完成,零基础也能操作:
步骤1:导出YOLO26的ONNX模型
在终端/命令行 中执行以下命令,导出YOLO26n的ONNX模型(如果用YOLO26s/m/l,替换yolo26n即可):
bash
yolo export format=onnx model=yolo26n.onnx
执行完成后,当前目录会生成yolo26n.onnx模型文件。
步骤2:准备测试视频
将需要检测的视频文件放到代码同一目录下,修改代码中source的参数为你的视频文件名(如source=r"test.mp4");如果想用电脑摄像头实时检测,直接设置source=0即可。
步骤3:运行代码
直接运行Python代码,会弹出检测窗口,实时显示检测结果,同时在代码目录下自动生成检测后的视频文件yolo-output.avi,按q键可随时退出检测。
五、使用注意事项
- 设备切换 :如果想使用GPU推理,只需将
YOLOVisualizer实例化的device参数改为cuda(需提前配置好CUDA、cuDNN环境); - 置信度调整 :模型推理的
conf=0.25可根据需求修改,值越高,检测结果越严格,漏检增多;值越低,检测结果越多,误检增多; - 路径问题 :视频路径和模型路径如果不是当前目录,需要写绝对路径 (如
source=r"C:\Users\xxx\Videos\test.mp4"); - 类别颜色 :如果想修改某类别的颜色,只需在
draw_bbox方法中修改cls_id == 2的判断条件和对应的颜色ID即可。
六、总结
这份YOLO26-ONNX的视频检测代码,不仅实现了核心的目标检测推理 ,还做了很多工程化的优化:
- 面向对象封装,代码结构清晰,复用性高,可直接集成到其他项目中;
- 自定义可视化效果,比YOLO默认效果更美观、更易读;
- 统计平均FPS和单帧处理时间,便于分析模型的推理性能;
- 同时支持视频文件 和摄像头检测,灵活切换;
- 自动保存检测后的视频,方便后续查看和分析。
YOLO26结合ONNX格式,既保留了YOLO系列的速度和精度优势,又实现了跨平台部署的灵活性,这份代码可以作为YOLO26工程落地的基础模板,大家可以在此基础上根据需求修改(如添加跟踪、计数、告警等功能)。
如果大家在运行过程中遇到问题,欢迎在评论区留言交流,后续也会给大家带来更多实战教程!

好了,这篇文章就介绍到这里,喜欢的小伙伴感谢给点个赞和关注,更多精彩内容持续更新~~
关于本篇文章大家有任何建议或意见,欢迎在评论区留言交流!