如何用OpenCV VideoWriter录制与YOLO模型实时推理速率一致的视频?
保留YOLO实时推理卡顿效果的录制方案
问题说明
运行YOLO实时推理代码时,窗口显示的画面会因模型推理耗时出现明显卡顿,但直接用OpenCV VideoWriter录制时,视频会按照固定帧率输出,无法还原这种真实的卡顿效果。
解决方案
以下两种方案可实现需求,根据场景选择:
方案1:录制显示窗口(直观还原卡顿)
直接录制YOLO推理时的显示窗口,完整保留实时卡顿效果,操作简单。
步骤:
- 安装依赖:
pip install mss ultralytics opencv-python
- 运行代码:
import cv2 import time from ultralytics import YOLO import mss import numpy as np # 加载YOLO模型 model = YOLO('yolov8n.pt') # 打开目标视频 video_path = "path/to/your/video/file.mp4" cap = cv2.VideoCapture(video_path) # 创建显示窗口并获取窗口位置 window_name = "YOLOv8 Inference" cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) # 先渲染一帧以确定窗口位置 success, frame = cap.read() if success: results = model(frame) annotated_frame = results[0].plot() cv2.imshow(window_name, annotated_frame) cv2.waitKey(1) # 获取窗口坐标与尺寸 x, y, w, h = cv2.getWindowImageRect(window_name) # 初始化屏幕录制器 sct = mss.mss() monitor = {"top": y, "left": x, "width": w, "height": h} # 初始化视频写入器,帧率沿用原视频帧率 fourcc = cv2.VideoWriter_fourcc(*'mp4v') video_writer = cv2.VideoWriter('recorded_lag_effect.mp4', fourcc, cap.get(cv2.CAP_PROP_FPS), (w, h)) # 开始推理、显示与录制 while cap.isOpened(): success, frame = cap.read() if success: # YOLO推理与标注 results = model(frame) annotated_frame = results[0].plot() # 显示卡顿画面 cv2.imshow(window_name, annotated_frame) # 录制当前窗口画面 sct_img = sct.grab(monitor) frame_np = np.array(sct_img) frame_bgr = cv2.cvtColor(frame_np, cv2.COLOR_BGRA2BGR) # 写入视频文件 video_writer.write(frame_bgr) # 按q键退出 if cv2.waitKey(1) & 0xFF == ord("q"): break else: break # 释放所有资源 cap.release() video_writer.release() cv2.destroyAllWindows() sct.close()
注意:录制期间需保持窗口在前台,避免被其他窗口遮挡。
方案2:基于推理耗时生成可变帧率视频(后台处理)
记录每帧的实际推理耗时,通过FFmpeg合成可变帧率视频,无需显示窗口,适合后台批量处理场景。
步骤:
- 确保已安装FFmpeg(需自行下载配置到系统环境变量)
- 运行代码:
import cv2 import time import os from ultralytics import YOLO # 加载YOLO模型 model = YOLO('yolov8n.pt') video_path = "path/to/your/video/file.mp4" cap = cv2.VideoCapture(video_path) # 创建临时文件夹保存单帧图像 temp_dir = "temp_frames" os.makedirs(temp_dir, exist_ok=True) frame_times = [] frame_idx = 0 # 批量处理视频帧并记录耗时 while cap.isOpened(): success, frame = cap.read() if success: start_time = time.time() # YOLO推理与标注 results = model(frame) annotated_frame = results[0].plot() # 记录单帧处理耗时 frame_time = time.time() - start_time frame_times.append(frame_time) # 保存帧到临时文件夹 frame_path = os.path.join(temp_dir, f"frame_{frame_idx:04d}.jpg") cv2.imwrite(frame_path, annotated_frame) frame_idx += 1 if cv2.waitKey(1) & 0xFF == ord("q"): break else: break cap.release() cv2.destroyAllWindows() # 生成FFmpeg所需的时间戳配置文件 with open("timestamps.txt", "w", encoding="utf-8") as f: total_time = 0.0 for idx, t in enumerate(frame_times): f.write(f"file '{os.path.abspath(os.path.join(temp_dir, f'frame_{idx:04d}.jpg'))}'\n") f.write(f"duration {t}\n") # FFmpeg要求最后一帧重复写入一次 f.write(f"file '{os.path.abspath(os.path.join(temp_dir, f'frame_{frame_idx-1:04d}.jpg'))}'\n") # 调用FFmpeg合成可变帧率视频 os.system('ffmpeg -f concat -safe 0 -i timestamps.txt -c:v libx264 -crf 23 -vf "fps=60" output_lag_effect.mp4') # 可选:清理临时文件 # import shutil # shutil.rmtree(temp_dir) # os.remove("timestamps.txt")
优缺点:无需显示窗口,视频帧率完全匹配实际推理耗时,但依赖FFmpeg,且涉及文件IO,处理速度较慢。
内容的提问来源于stack exchange,提问作者ailauli69
相关产品推荐
相关产品推荐

