1. 核心概念解析
(1) stream=True
的作用
- 生成器模式:当处理视频或图像序列时,
stream=True
会将结果包装成一个 生成器(Generator),逐帧生成Results
对象,而不是一次性返回所有结果。 - 内存优化:避免同时加载全部帧的检测结果,显著降低内存占用(尤其对长视频或高分辨率输入至关重要)。
(2) Results
对象生成器
- 每次迭代返回一个
Results
对象,对应视频的 一帧 或输入列表中的 一个元素。 - 每个
Results
对象包含该帧的检测信息(如boxes
、masks
等)。
2. 工作流程对比
传统方式(stream=False
)
results = model("video.mp4") # 一次性处理所有帧
# 所有结果存储在内存中,可能导致OOM(内存不足)
- 内存峰值高:需缓存整个视频的检测结果。
- 延迟高:必须等待全部处理完成才能访问结果。
流式处理(stream=True
)
results = model("video.mp4", stream=True) # 生成器
for frame_results in results: # 逐帧处理print(frame_results.boxes) # 实时访问当前帧结果
- 内存友好:同一时间仅处理一帧的数据。
- 实时性:边处理边输出,适合实时分析或长时间视频。
3. 典型使用场景
(1) 视频处理
cap = cv2.VideoCapture("input.mp4")
out = cv2.VideoWriter("output.mp4", cv2.VideoWriter_fourcc(*'mp4v'), 30, (640, 480))# 流式推理
results = model("input.mp4", stream=True)
for frame_results in results:annotated_frame = frame_results.plot() # 绘制检测框out.write(annotated_frame) # 写入输出视频
- 优势:避免因视频过长导致内存爆炸。
- 值得注意,(输出视频只有1KB)通常是由于 视频编解码器配置问题 或 帧尺寸不匹配 导致的。以下是修正后的完整代码,解决写入视频无效的问题:
import cv2
from ultralytics import YOLO# 初始化模型
model = YOLO("../models/yolo11n.pt") # pretrained YOLO11n model# 输入视频路径
input_video = "../videos/test.mp4"# 读取输入视频获取帧尺寸和FPS
cap = cv2.VideoCapture(input_video)
fps = int(cap.get(cv2.CAP_PROP_FPS))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
cap.release()# 定义视频写入器(关键修正点)
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 或改用 'avc1' 兼容H.264
out = cv2.VideoWriter("output.mp4",fourcc,fps,(width, height) # 必须与原始视频尺寸一致!
)# 流式推理
results = model(input_video, stream=True, imgsz=640) # imgsz可调整for frame_results in results:# 获取带标注的帧(BGR格式)annotated_frame = frame_results.plot() # 自动返回numpy数组 (H,W,3)# 确保帧尺寸与写入器匹配(额外安全检查)if (annotated_frame.shape[1], annotated_frame.shape[0]) != (width, height):annotated_frame = cv2.resize(annotated_frame, (width, height))# 写入帧out.write(annotated_frame)# 释放资源
out.release()
print(f"视频已保存至 output.mp4,尺寸: {width}x{height}, FPS: {fps}")
(2) 实时摄像头流
results = model(0, stream=True) # 摄像头ID=0
for frame_results in results:cv2.imshow("Live", frame_results.plot())if cv2.waitKey(1) == ord('q'): # 按Q退出break
- 优势:低延迟,适合实时监控。
4. 内存优化原理
处理方式 | 内存占用曲线 | 特点 |
---|---|---|
stream=False | ![]() | 内存随帧数线性增长 |
stream=True | ![]() | 内存恒定(仅缓存当前帧) |
5. 注意事项
-
性能权衡:
- 优点:节省内存,适合资源受限环境。
- 缺点:总处理时间可能略长(因无法并行处理所有帧)。
-
不可逆迭代:
results = model(source, stream=True) list(results) # 第一次迭代后生成器耗尽,再次遍历需重新推理
-
与多线程结合:
from concurrent.futures import ThreadPoolExecutordef process_frame(frame_results):return frame_results.plot()with ThreadPoolExecutor() as executor:annotated_frames = list(executor.map(process_frame, results))
6. 类比解释
- 传统方式:像一次性下载整部电影再看 → 占用硬盘空间大。
- 流式处理:像在线边缓冲边播放 → 内存占用稳定。
通过 stream=True
,YOLOv8 实现了 高效流水线处理,尤其适合嵌入式设备或大规模视频分析场景。