家里监控攒了几百 GB 的录像,大部分是没人时的静止画面。要的是'有人就保留、无人就剪掉',还得快、还得全自动。我用 YOLOv8n(OpenVINO,跑在核显+NPU 混合池)做逐秒人形检测,给 D 盘 1677 个目录 / 7.9 万个文件做了一次全自动瘦身:502.5GB → 235.7GB(压缩 53%),一夜 6.5 小时跑完,0 错误。这篇是完整作战记录。
环境:Core Ultra 5 235H / Arc 140T 核显(copy 切割)/ Intel AI Boost NPU(检测)双池 / 混合 GPU4+NPU3 / OpenVINO 2026.5.0.dev / yolov8n_openvino_model FP16 / ffmpeg 9.0.1 / Windows 计划任务。2026-09-12~13 实测。
为什么从 freezedetect 叛逃到 YOLO
一开始用的是 ffmpeg freezedetect/MOG2/帧差这类'运动检测',但在监控夜景面前全军覆没:噪点抖动会让静止画面被判成'活动',而真正有人走动时帧差又稀碎。它区分不了'静止'和'有人'——这是两个完全不同的问题。用户最终拍板:检测标准 = 有人就保留。这种语义判断只有目标检测模型做得了。
| 方案 | 夜景问题 |
|---|---|
| freezedetect | 噪点=活动,误报成串 |
| MOG2 / 帧差 | 有人走动帧差不连续 |
| YOLOv8n 人形检测 | 语义判断,唯一权威 |
流水线三段式
- 检测(GPU4+NPU3 常驻服务):每 3 秒抽 1 帧推 YOLOv8n,产出全局活动段 JSON(含 people_secs / 段区间)
- 切割(copy 流复制):按段映射回文件内秒,ffmpeg
-ss/-t每段独立切片,-c:v copy零质量损失 - 合并(concat):demuxer 无缝拼接成片,输出
监控成片\目录名.mp4
从 15x 到 127x:每一步的提速账
这条流水线是三轮迭代磨出来的,每轮都砍掉至少一半时间:
| 版本 | 端到端 | x 实时 | 关键改动 |
|---|---|---|---|
| v4 NPU 单池 | ~235s | 15x | NPU jobs=6 检测 + 独立切片重编码 |
| v5 GPU+NPU 混合 | 36.2s | 99x | 双池并行 + copy 切割替代重编码 |
| v6 640x360 + ratio 0.6 | ~21s | 172x | rawvideo 管道 + 缩半分辨率 + 比例分配 |
| v7 3秒采样 + 全盘 | ~8s/目录 | 127x | 每 3 秒 1 帧推理量减 2/3,全盘批跑 |
最关键的两次决策:copy 流复制切割代替重编码(44 片 2.8s vs 单命令重编码 87s,快 24 倍),和 把一个小时视频的检测压到 17s 内(混合池 + 3 秒采样)。
切割为什么要 copy 不重编码
| 方案 | 耗时(42段/1908s活动) | 成片 |
|---|---|---|
| copy 切片 + concat jobs=8 | 3.6s | 208.4MB ✅ 最优 |
| copy jobs=12/16 | 4.1/4.4s | 208.4MB(进程启动开销>收益) |
| filter_complex + qsv 重编码 | 87.2s | 120.4MB(重编码慢 24 倍,弃) |
视频流是 HEVC,源本就是高压缩,重编码只会又慢又损。既然检测已经精确到秒级区间,直接 -c:v copy 把对应包切出来再拼,零质量损失、无可感知体积代价。这也是 127 倍实时能成立的核心。
音画同步与质量抽查
抽检最终成片(HEVC 1080p@20 + aac 16k 单声道):分辨率/帧率/音频流/时长全部正确;音画偏差 64ms(视频 start 0.064s / 音频 0s)可接受;820s 处画面亮度 117,是有效画面不是黑/绿帧。
全盘部署:计划任务 + 断点续跑
规模吓人:1677 目录 / 79027 文件 / 502.5GB,D 盘机械盘只读、不删原文件。直接命令行后台跑必挂(工具环境杀进程),正解是 Windows 计划任务:
:: 计划任务「监控压缩全量」→ launch_all.py(自包含:确保服务运行→调 batch_run)
:: batch_run.py D:\ --jobs 8 --interval 3 --pad 3 --skip-existing --log batch_log.txt
:: --skip-existing:跳过已完成目录,中断后重跑即断点续传(速率 ~6.1 目录/分钟)
踩过的部署雷:计划任务直接调 python 会因中文路径/D:\ 参数序列化污染而 Last Result=1;cmd 包装脚本又被反斜杠引号多重解析搞崩。最终用 launch_all.py 纯 Python 启动器、参数写死在代码里(D:/ 正斜杠),计划任务只调无参脚本——稳定跑完。
结果
- 1677/1677 目录全部完成,0 错误;成片 1554 个(123 个无人目录无成片)
- 体积 502.5GB → 235.7GB,压缩 53%
- 全程 ~6.5 小时(23:51 → 06:26),机器一边跑检测一边还能干别的
- 输出统一到桌面
监控成片\目录名.mp4,临时切片自动清理
