做装修巡检或工地记录时,经常要面对几十 G 的延时录像。人工一帧帧翻太低效,本文用一段 Python 脚本,把一段长视频按固定时间间隔自动抽帧,再用 OpenCV + Pillow 拼成一张「每日进度九宫格」,既能发日报,也能做前后对比。
用 ffmpeg + OpenCV 把施工延时视频自动抽帧,生成「每日进度九宫格」(Python 批处理实战)
做装修巡检或工地记录时,经常要面对几十 G 的延时录像。人工一帧帧翻太低效,本文用一段 Python 脚本,把一段长视频按固定时间间隔自动抽帧,再用 OpenCV + Pillow 拼成一张「每日进度九宫格」,既能发日报,也能做前后对比。
ffmpeg按-vf fps=1/N把视频均匀抽成图片序列(不依赖逐帧解码,速度快);2. 用 OpenCV 读取这些帧,统一缩放到固定尺寸;3. 用 Pillow 把多张图拼成 3×3 九宫格(或 N×M 网格);4. 批处理:遍历一个文件夹里的所有.mp4,每个生成一个九宫格。> 为什么不全用 OpenCV 解码?ffmpeg的抽帧对大视频更稳、可指定时间步长,避免把整段视频读进内存。## 二、ffmpeg 抽帧(核心命令)bash# 每 600 秒(10 分钟)抽 1 帧,输出 frame_0001.jpg ...ffmpeg -i input.mp4 -vf "fps=1/600" -qscale:v 2 frames/frame_%04d.jpg-fps=1/600:每 600 秒 1 帧;想更密就调小,比如1/60每分钟 1 帧。--qscale:v 2:JPG 质量,2 接近无损、体积小。## 三、Python 拼九宫格pythonimport cv2, glob, osfrom PIL import Imagedef make_grid(frame_dir, out_path, cols=3, rows=3, size=(320, 180)): files = sorted(glob.glob(os.path.join(frame_dir, "*.jpg")))[:cols*rows] if not files: return False thumbs = [cv2.cvtColor(cv2.resize(cv2.imread(f), size), cv2.COLOR_BGR2RGB) for f in files] # 用黑块补齐不足 9 张的情况 while len(thumbs) < cols * rows: import numpy as np thumbs.append(np.zeros((size[1], size[0], 3), dtype=np.uint8)) w, h = size grid = Image.new("RGB", (w * cols, h * rows)) for idx, im in enumerate(thumbs): r, c = divmod(idx, cols) grid.paste(Image.fromarray(im), (c * w, r * h)) grid.save(out_path) return Truemake_grid("frames", "progress_grid.jpg")关键点:- OpenCV 读到的是 BGR,拼图前转成 RGB,否则颜色会偏蓝;- 用sorted保证帧顺序,否则九宫格会被打乱;- 帧数不足时补黑块,避免IndexError。## 四、批处理整个文件夹pythonimport osfor mp4 in glob.glob("videos/*.mp4"): name = os.path.splitext(os.path.basename(mp4))[0] frame_dir = f"tmp/{name}_frames" os.makedirs(frame_dir, exist_ok=True) os.system(f'ffmpeg -i "{mp4}" -vf "fps=1/600" -qscale:v 2 "{frame_dir}/frame_%04d.jpg"') make_grid(frame_dir, f"grids/{name}_grid.jpg")跑完grids/下就是每个视频对应的九宫格,直接发日报、做周报对比都行。## 五、踩过的坑-中文路径:os.system调 ffmpeg 时,Windows 下中文路径偶尔抽风,建议先import subprocess用subprocess.run([...], shell=False)传列表参数,比拼字符串稳妥。-帧太多内存爆:别一次性cv2.VideoCapture读完整个长视频,始终走 ffmpeg 抽帧落地再读图。-时间戳叠加:可在抽帧时加-vf "fps=1/600,drawtext=..."把时间烧录进画面,九宫格一眼看出是第几天。这套方法我们做工地巡检日报时天天在用,比人工翻视频省了 90% 时间。类似的「把重复劳动交给脚本」的思路,我们也沉淀成了几款小工具,整理在 maixuzi.cn/resources/ ,感兴趣的可以看看。