实战指南:Python + YOLOv8 实现 CPU 版视频目标检测
实战指南:Python + YOLOv8 实现 CPU 版视频目标检测
引言
在计算机视觉领域,模型训练完成后,我们通常会得到 .pt 格式的模型文件。评估模型效果最直观的方式是对 .mp4 视频进行实时检测。然而,很多开发者在测试时会遇到两个核心挑战:一是如何快速构建完整的视频检测流程,包括模型加载、推理、可视化和结果保存;二是在无 GPU 环境下,如何强制使用 CPU 完成推理并优化性能。
本文将提供一份全面的实战指南,从环境搭建到代码实现,从性能优化到实际应用,帮助开发者快速掌握 CPU 环境下的 YOLOv8 视频检测技术。
一、项目规划与准备
1.1 适用场景分析
本方案适用于以下场景:
- 无 GPU 环境:如普通办公电脑、云服务器基础版等
- 快速模型验证:训练完成后快速评估模型效果
- 离线部署:在无法使用 GPU 的边缘设备上部署
- 教学演示:在课堂或培训中展示目标检测效果
1.2 模型选择指南
YOLOv8 系列提供了多种规格的模型,在 CPU 环境下,推荐使用以下轻量级模型:
| 模型 | 大小 | 精度 | CPU 推理速度 | 适用场景 |
|---|---|---|---|---|
| YOLOv8n | 3.2MB | 37.3% | 最快 | 资源受限设备 |
| YOLOv8s | 11.2MB | 44.9% | 较快 | 一般 CPU 环境 |
| YOLOv8m | 25.9MB | 50.2% | 中等 | 高性能 CPU |
| YOLOv8l | 43.7MB | 52.9% | 较慢 | 多核心高性能 CPU |
| YOLOv8x | 68.2MB | 53.9% | 最慢 | 不推荐在 CPU 上使用 |
选择建议:在 CPU 环境下,优先选择 YOLOv8n 或 YOLOv8s,以平衡速度和精度。
1.3 环境搭建
1.3.1 依赖库安装
# 基础安装命令
pip install ultralytics torch opencv-python numpy
# 推荐版本安装(指定版本避免兼容性问题)
pip install ultralytics==8.1.0 torch==2.1.0 opencv-python==4.8.1.78 numpy==1.24.4
1.3.2 验证安装
# 验证 PyTorch 安装
python -c "import torch; print('PyTorch version:', torch.__version__); print('CPU available:', torch.cuda.is_available())"
# 验证 YOLOv8 安装
python -c "from ultralytics import YOLO; print('YOLOv8 imported successfully')"
# 验证 OpenCV 安装
python -c "import cv2; print('OpenCV version:', cv2.__version__)"
二、核心技术实现
2.1 项目结构
yolo-video-detector/
├── models/ # 模型文件目录
│ └── yolov8n.pt # YOLOv8 模型文件
├── videos/ # 视频文件目录
│ └── test_video.mp4 # 待检测视频
├── outputs/ # 输出结果目录
│ └── detected_video.mp4 # 检测结果视频
├── detector.py # 核心检测脚本
├── utils.py # 工具函数
└── README.md # 项目说明
2.2 核心检测脚本
import cv2
import torch
from ultralytics import YOLO
import os
import time
def detect_model_on_video(
model_path,
video_path,
output_path="output.mp4",
conf_threshold=0.5,
resize=None, # 可选:(width, height),缩小输入尺寸提升速度
classes=None, # 可选:[0, 1, 2],只检测特定类别
show_preview=True # 是否显示实时预览
):
"""
加载.pt模型(强制CPU)检测.mp4视频,保存带检测结果的视频
参数说明:
model_path: str, .pt模型文件路径(如'best.pt')
video_path: str, 待检测的.mp4视频路径(如'test_video.mp4')
output_path: str, 检测结果视频保存路径
conf_threshold: float, 置信度阈值(0-1),过滤低置信度检测结果
resize: tuple, 可选,调整输入视频尺寸 (width, height)
classes: list, 可选,只检测指定类别索引
show_preview: bool, 是否显示实时检测预览
"""
# 1. 校验文件是否存在
if not os.path.exists(model_path):
raise FileNotFoundError(f"模型文件不存在:{model_path}")
if not os.path.exists(video_path):
raise FileNotFoundError(f"视频文件不存在:{video_path}")
# 2. 确保输出目录存在
output_dir = os.path.dirname(output_path)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir)
# 3. 强制使用CPU
device = 'cpu'
print(f"当前强制使用计算设备:{device}")
# 4. 加载模型
model = YOLO(model_path)
model.to(device)
# 5. 打开视频文件
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise RuntimeError(f"无法打开视频:{video_path}")
# 6. 获取视频参数
fps = int(cap.get(cv2.CAP_PROP_FPS))
original_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
original_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# 7. 计算输出尺寸
if resize:
output_width, output_height = resize
else:
output_width, output_height = original_width, original_height
# 8. 创建视频写入器
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, fps, (output_width, output_height))
# 9. 逐帧处理
frame_count = 0
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
start_time = time.time()
print(f"开始检测视频(CPU模式),共 {total_frames} 帧,请稍候...")
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 调整输入尺寸(如果指定)
if resize:
frame = cv2.resize(frame, resize)
# 单帧推理
frame_start = time.time()
results = model(frame, conf=conf_threshold, device=device, classes=classes)
frame_end = time.time()
# 计算单帧处理时间
frame_time = (frame_end - frame_start) * 1000 # 转换为毫秒
fps_current = 1 / (frame_end - frame_start + 1e-6)
# 绘制检测结果
annotated_frame = results[0].plot()
# 添加性能信息
cv2.putText(
annotated_frame,
f'CPU Inference: {frame_time:.1f}ms ({fps_current:.1f} FPS)',
(10, 30),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(0, 255, 0),
2
)
# 写入结果视频
out.write(annotated_frame)
# 实时预览
if show_preview:
cv2.imshow('YOLOv8 Detection (CPU)', annotated_frame)
# 按q键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
print("用户手动终止检测")
break
frame_count += 1
# 打印进度
if frame_count % 10 == 0:
progress = (frame_count / total_frames) * 100
elapsed_time = time.time() - start_time
estimated_total = elapsed_time / (frame_count / total_frames)
remaining_time = estimated_total - elapsed_time
print(f"进度: {progress:.1f}% | 已处理: {frame_count}/{total_frames}帧 | "
f"耗时: {elapsed_time:.1f}s | 预计剩余: {remaining_time:.1f}s")
# 10. 释放资源
cap.release()
out.release()
if show_preview:
cv2.destroyAllWindows()
# 11. 输出检测结果
total_time = time.time() - start_time
average_fps = frame_count / total_time
print("\n检测完成!")
print(f"结果视频保存路径:{output_path}")
print(f"总共处理帧数:{frame_count}")
print(f"总耗时:{total_time:.2f}秒")
print(f"平均帧率:{average_fps:.2f} FPS")
print(f"平均每帧处理时间:{1000/average_fps:.2f} 毫秒")
if __name__ == "__main__":
# 配置参数
config = {
"model_path": "models/yolov8n.pt",
"video_path": "videos/test_video.mp4",
"output_path": "outputs/detected_video.mp4",
"conf_threshold": 0.5,
"resize": (640, 480), # 缩小尺寸提升速度
"classes": None, # 检测所有类别
"show_preview": True
}
try:
detect_model_on_video(**config)
except Exception as e:
print(f"检测出错:{e}")
import traceback
traceback.print_exc()
2.3 工具函数模块
# utils.py
import os
import cv2
import numpy as np
def get_video_info(video_path):
"""
获取视频基本信息
"""
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise RuntimeError(f"无法打开视频:{video_path}")
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))
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
duration = total_frames / fps
cap.release()
return {
"fps": fps,
"width": width,
"height": height,
"total_frames": total_frames,
"duration": duration
}
def extract_video_frames(video_path, output_dir, interval=1):
"""
从视频中提取帧
"""
if not os.path.exists(output_dir):
os.makedirs(output_dir)
cap = cv2.VideoCapture(video_path)
frame_count = 0
extracted_count = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
if frame_count % interval == 0:
output_path = os.path.join(output_dir, f"frame_{extracted_count:04d}.jpg")
cv2.imwrite(output_path, frame)
extracted_count += 1
frame_count += 1
cap.release()
return extracted_count
def batch_process_videos(video_dir, model_path, output_dir, **detect_kwargs):
"""
批量处理文件夹中的所有视频
"""
if not os.path.exists(output_dir):
os.makedirs(output_dir)
video_files = [f for f in os.listdir(video_dir) if f.endswith('.mp4')]
for video_file in video_files:
video_path = os.path.join(video_dir, video_file)
output_path = os.path.join(output_dir, f"detected_{video_file}")
print(f"\n处理视频:{video_file}")
try:
from detector import detect_model_on_video
detect_model_on_video(
model_path=model_path,
video_path=video_path,
output_path=output_path,
**detect_kwargs
)
except Exception as e:
print(f"处理视频 {video_file} 时出错:{e}")
print(f"\n批量处理完成,共处理 {len(video_files)} 个视频")
三、实战应用示例
3.1 基础应用:交通场景检测
3.1.1 配置与运行
# 交通场景检测配置
config = {
"model_path": "models/yolov8n.pt",
"video_path": "videos/traffic.mp4",
"output_path": "outputs/traffic_detected.mp4",
"conf_threshold": 0.4,
"resize": (640, 480),
"classes": [2, 3, 5, 7], # 只检测车辆相关类别
"show_preview": True
}
# 运行检测
detect_model_on_video(**config)
3.1.2 检测效果
原始视频:城市交通场景,包含汽车、公交车、行人等
检测结果:
- 车辆被准确框出并标注类别(car、bus、truck)
- 实时显示 CPU 推理速度
- 检测结果视频保存为
outputs/traffic_detected.mp4
3.2 高级应用:批量视频处理
3.2.1 批量处理脚本
# batch_process.py
from utils import batch_process_videos
# 批量处理配置
batch_config = {
"video_dir": "videos/",
"model_path": "models/yolov8n.pt",
"output_dir": "outputs/batch_results/",
"conf_threshold": 0.5,
"resize": (640, 480),
"show_preview": False # 批量处理时关闭预览
}
# 运行批量处理
batch_process_videos(**batch_config)
3.2.2 应用场景
- 监控视频分析:批量处理多个监控摄像头的视频
- 数据集标注辅助:快速预览模型在多个视频上的表现
- 视频内容审核:批量检测视频中的特定目标
3.3 实用技巧:性能测试
3.3.1 CPU 性能测试脚本
# performance_test.py
import time
from detector import detect_model_on_video
# 测试不同模型在 CPU 上的性能
test_videos = ["videos/test_video_10s.mp4"] # 10秒测试视频
models = ["yolov8n.pt", "yolov8s.pt", "yolov8m.pt"]
results = []
for model in models:
print(f"\n测试模型:{model}")
start_time = time.time()
try:
detect_model_on_video(
model_path=f"models/{model}",
video_path=test_videos[0],
output_path=f"outputs/test_{model}_result.mp4",
conf_threshold=0.5,
resize=(640, 480),
show_preview=False
)
end_time = time.time()
results.append({"model": model, "time": end_time - start_time})
except Exception as e:
print(f"测试失败:{e}")
# 输出性能对比
print("\n=== CPU 性能测试结果 ===")
for result in results:
print(f"{result['model']}: {result['time']:.2f}秒")
四、常见问题与解决方案
4.1 性能问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| CPU 推理速度太慢 | 模型太大或视频分辨率过高 | 1. 使用更小的模型(YOLOv8n) 2. 降低视频分辨率 3. 减少检测类别 |
| 内存占用过高 | 视频分辨率过高或模型过大 | 1. 降低视频分辨率 2. 使用轻量级模型 3. 确保逐帧处理,不缓存视频 |
| 程序崩溃 | 内存不足 | 1. 减小输入尺寸 2. 使用更小的模型 3. 增加虚拟内存 |
4.2 技术问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 视频无法打开 | 路径错误或编码不支持 | 1. 检查视频路径 2. 尝试转换视频编码 3. 使用绝对路径 |
| 检测框不准确 | 置信度阈值设置不当 | 1. 调整 conf_threshold 参数 2. 使用更适合的模型 |
| 保存的视频无法播放 | 编码格式不兼容 | 1. 尝试使用不同的编码:'avc1' 或 'XVID' 2. 检查输出路径权限 |
| 预览窗口无响应 | 处理速度过慢 | 1. 关闭实时预览 2. 降低视频分辨率 3. 使用更快的模型 |
4.3 环境问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 依赖库安装失败 | 网络问题或版本冲突 | 1. 使用国内镜像源 2. 安装指定版本 3. 创建虚拟环境 |
| PyTorch 无法导入 | 版本不兼容 | 1. 安装与系统匹配的版本 2. 检查 Python 版本兼容性 |
| OpenCV 错误 | 缺少依赖 | 1. 安装完整版本:pip install opencv-python-headless2. 检查系统依赖 |
五、代码优化与进阶技巧
5.1 代码优化建议
-
使用上下文管理器:
class VideoCapture: def __init__(self, path): self.path = path self.cap = None def __enter__(self): self.cap = cv2.VideoCapture(self.path) return self.cap def __exit__(self, exc_type, exc_val, exc_tb): if self.cap: self.cap.release() -
多线程处理:
import threading from queue import Queue def process_frames(queue, model, device): while not queue.empty(): frame = queue.get() # 处理帧 results = model(frame, device=device) # 处理结果 queue.task_done() -
缓存优化:
# 预分配内存 import numpy as np # 预分配帧缓冲区 frame_buffer = np.zeros((height, width, 3), dtype=np.uint8)
5.2 进阶应用场景
-
实时摄像头检测:
# 实时摄像头检测 cap = cv2.VideoCapture(0) # 0 表示默认摄像头 -
视频流检测:
# RTSP 流检测 rtsp_url = "rtsp://username:password@camera_ip:554/stream1" cap = cv2.VideoCapture(rtsp_url) -
与其他系统集成:
- 与 Flask/Django 集成,提供 Web 接口
- 与消息队列集成,处理异步检测任务
- 与数据库集成,存储检测结果
六、总结与展望
6.1 核心收获
- 完整的视频检测流程:掌握了从模型加载、视频处理到结果保存的完整流程
- CPU 环境优化:学会了在 CPU 环境下优化 YOLOv8 推理性能
- 工程化实践:掌握了编写鲁棒、高效的计算机视觉脚本的技巧
- 实际应用能力:能够将目标检测技术应用到实际场景中
6.2 未来发展方向
- 模型压缩:使用模型量化、剪枝等技术进一步减小模型大小
- 推理加速:集成 OpenVINO、ONNX Runtime 等推理加速引擎
- 边缘部署:将优化后的模型部署到更广泛的边缘设备
- 多模态融合:结合音频、文本等信息,提升检测效果
- 自动化标注:利用检测结果辅助视频标注,提高数据处理效率
6.3 学习资源推荐
- 官方文档:Ultralytics YOLOv8 Documentation
- GitHub 仓库:ultralytics/ultralytics
- 视频教程:B 站搜索 "YOLOv8 实战"
- 社区论坛:Ultralytics Discord
七、项目部署指南
7.1 离线部署
-
打包依赖:
# 导出依赖 pip freeze > requirements.txt # 下载依赖包(用于离线安装) pip download -r requirements.txt -d packages/ -
离线安装:
# 在目标机器上安装 pip install --no-index --find-links=packages/ -r requirements.txt
7.2 脚本打包
使用 PyInstaller 打包为可执行文件:
# 安装 PyInstaller
pip install pyinstaller
# 打包脚本
pyinstaller --onefile --name yolo_detector detector.py
# 运行打包后的程序
./dist/yolo_detector
7.3 Docker 部署
# Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "detector.py"]
# 构建镜像
docker build -t yolo-video-detector .
# 运行容器
docker run --rm -v ./videos:/app/videos -v ./outputs:/app/outputs yolo-video-detector
个人矩阵
- 抖音账号:从 0 至 1(日常分享实操、效率工具教程)
- 微信公众号:从 0 至 1(可通过该渠道获取完整代码包及EXE程序)
- 博客网站:www.from0to1.cn(持续更新实战教程、技术干货内容)
- GitHub账号:https://github.com/mtnljbydd(开源更多实用工具脚本及项目工程)
扫描二维码,在手机上阅读
版权所有:从0至1
文章标题:实战指南:Python + YOLOv8 实现 CPU 版视频目标检测
文章链接:https://www.from0to1.cn/inspiration-coding/szzn-python-ysxcbsbmbjc.html
本站文章均为原创,未经授权请勿用于任何商业用途
文章标题:实战指南:Python + YOLOv8 实现 CPU 版视频目标检测
文章链接:https://www.from0to1.cn/inspiration-coding/szzn-python-ysxcbsbmbjc.html
本站文章均为原创,未经授权请勿用于任何商业用途
文章目录
打赏
如果觉得文章对您有用,请随意打赏。
您的支持是我们继续创作的动力!
微信扫一扫
支付宝扫一扫
收藏