视频写入 (FourCC, VideoWriter
)
1. VideoWriter_fourcc
- 视频编码器四字符代码
# OpenCV 3.x, 4.x
fourcc = cv2.VideoWriter_fourcc('M','J','P','G')
fourcc = cv2.VideoWriter_fourcc(*'H264')
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
- FourCC: 代表 Four Character Code,是一个4字节的代码,用于指定视频流的编码格式(Codec)。它决定了视频数据如何被压缩。
- 定义一个视频编码器(Codec)。视频编码器负责将连续的图像帧压缩成视频流,显著减小文件大小。
常用 FourCC 代码
- Video Codecs by FOURCC - fourcc.org
- **
'XVID'
: MPEG-4 编码器。兼容性好,文件大小适中,是最常用**的选择之一。 - **
'MJPG'
**: Motion-JPEG 编码器。质量高,但文件非常大。 - **
'H264'
: H.264/AVC 编码器。压缩效率极高(文件小),质量好。需要系统安装 H.264 编码器支持**(如 Windows 上的 OpenH264 或 x264)。 - **
'MP4V'
**: MPEG-4 视频编码器。常用于.mp4
文件。 - **
'AVC1'
**: 另一种表示 H.264 的方式。 - **
'DIVX'
**: DivX 编码器(基于 MPEG-4)。
常用 FourCC 代码与推荐的文件扩展名对应表
- 文件扩展名: 如
.avi
,.mp4
,.mov
,用于指定容器格式(Container)。容器是一个“包装盒”,里面可以存放由特定编码器压缩的视频流、音频流、字幕等信息。 - 关键点在于:FourCC 编码器和文件扩展名容器之间并没有严格的、一对一的强制绑定关系,但存在广泛认可和兼容的“最佳实践”组合。
- 选择一个不常见的组合(例如,在
.mp4
文件里使用XVID
编码)可能会导致某些播放器无法识别或播放。
FourCC 代码 | 推荐文件扩展名 | 说明与常见用途 |
---|---|---|
**'XVID' ** |
.avi |
最常用、兼容性最好的组合之一。XVID 是一个开源的 MPEG-4 视频编码器,生成的 .avi 文件可以在绝大多数设备和播放器上播放。文件大小和质量平衡得很好。 |
**'MJPG' ** |
.avi |
Motion-JPEG 编码,将每一帧都压缩为一张 JPEG 图片。视频质量很高,但文件体积非常大。常用于对质量要求极高且不介意文件大小的场景。 |
**'H264' ** |
.mp4 |
H.264/AVC 编码,当今最流行的编码标准。压缩效率极高(在相同质量下文件更小)。注意:OpenCV 可能需要系统安装额外的开源库(如 OpenH264 或 x264)才能使用此编码器。 |
**'AVC1' ** |
.mp4 |
本质上是 H.264 编码的另一种表示方法。行为与 'H264' 类似。 |
**'MP4V' ** |
.mp4 |
代表 MPEG-4 视频(Part 2),与 H.264(Part 10)不同。压缩效率通常不如 H.264,但兼容性可能更好。 |
**'DIVX' ** |
.avi |
DivX 编码器(也是基于 MPEG-4)。曾非常流行,现在多用于历史遗留项目。 |
**'FMP4' ** |
.mp4 |
FFmpeg 的 MPEG-4 编码器。如果你的 OpenCV 编译时包含了 FFmpeg 支持,可能会用到。 |
**'PIM1' ** |
.avi |
MPEG-1 编码。非常老的格式,文件大,质量一般,现较少使用。 |
**'X264' ** |
.mp4 |
特指使用 x264 库(一个优秀的开源 H.264 编码器实现)。这通常需要从源码自定义编译 OpenCV 才能直接使用。 |
选择建议:
- 为了最大兼容性:使用 **
'XVID'
+ .avi
**。这是 OpenCV 中最可靠、问题最少的输出组合,几乎总能成功。 - 为了更小的文件:使用 **
'H264'
或'AVC1'
+ .mp4
**。这是目前网络传输和存储的标准格式。但需要确保你的 OpenCV 环境支持它(否则会写入失败或生成空文件)。 - 高质量,不介意文件大小:'MJPG' +
.avi
**。
最重要的步骤:
在编写代码时,始终检查 VideoWriter
对象是否通过 isOpened()
方法成功打开。如果首选的高效编码器(如 H.264)不可用,则回退到兼容性更好的编码器(如 XVID)。这是一种良好的编程实践,可以增强代码的健壮性。
fourcc = cv2.VideoWriter_fourcc(*'H264')
out = cv2.VideoWriter('test.mp4', fourcc, 20.0, (640, 480))
if not out.isOpened():
print("错误:无法使用 H264 编码器!将回退到 XVID。")
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('test.avi', fourcc, 20.0, (640, 480))
2. VideoWriter
- 视频写入器
- 创建一个对象,用于将连续的图像帧写入视频文件。
out = cv2.VideoWriter(filename, fourcc, fps, frame_size[, isColor])
语法:
filename
: 要保存的视频文件路径(包括扩展名,如'output.avi'
或'result.mp4'
)。fourcc
: 由VideoWriter_fourcc
创建的编码器对象。fps
: 视频的帧率(每秒帧数)。应与输入源(如摄像头或视频文件)的帧率匹配或根据需求设定。frame_size
: 视频帧的尺寸,以元组形式表示(width, height)
。必须与你要写入的每一帧图像的尺寸完全一致!isColor
(可选): 指定是否为彩色视频。默认为True
。如果写入灰度帧,设为False
可能更高效。
核心方法:
- **
out.write(frame)
**: 将一帧图像(frame
,一个 NumPy 数组)写入视频文件。这是循环中最常用的方法。 - **
out.release()
: 非常重要!** 在完成所有帧的写入后,必须调用此方法来正确关闭视频文件,释放资源并确保文件完整可播。忘记调用会导致视频文件损坏或无法播放。
3. 完整工作流程示例
import cv2
# 1. 打开摄像头 (输入源)
cap = cv2.VideoCapture(0) # 0 表示默认摄像头
# 2. 获取摄像头参数 (用于设置VideoWriter)
fps = cap.get(cv2.CAP_PROP_FPS) # 获取摄像头帧率
# 如果摄像头返回0,设置一个合理的帧率 (如20)
if fps <= 0:
fps = 20.0
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 获取帧宽度
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取帧高度
frame_size = (width, height)
# 3. 定义视频编码器 (FourCC) 和创建 VideoWriter 对象 (输出)
fourcc = cv2.VideoWriter_fourcc(*'XVID') # 使用XVID编码器, 注意 '*' 解包
# 创建输出文件 'output.avi'
out = cv2.VideoWriter('output.avi', fourcc, fps, frame_size)
# 4. 循环处理每一帧
while cap.isOpened():
# 读取一帧
ret, frame = cap.read()
if not ret:
print("无法从摄像头读取帧!")
break
# 例如:将帧转换为灰度图 (实际项目中替换为你的AI模型推理)
processed_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 5. 将处理后的帧写入输出视频文件
out.write(processed_frame) # 写入处理后的帧
# 6. (可选) 在本地显示结果
cv2.imshow('Processed Video', processed_frame)
# 按 'q' 键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 7. 释放资源 (非常重要!)
cap.release() # 释放摄像头
out.release() # 释放VideoWriter,确保文件正确关闭
cv2.destroyAllWindows() # 关闭所有窗口
print("视频已保存为 'output.avi'")
4.详解 cv2.waitKey(1)
:图像刷新与键盘输入的完美结合
cv2.waitKey(1)
是 OpenCV 图像处理中一个看似简单但极其重要的函数,它在实时应用中扮演着关键角色。- 函数原型:
- retval = cv2.waitKey([, delay])
- 参数:
- delay: 等待键盘事件的时间(以毫秒为单位)。默认值为0。
- 返回值:
- retval: 返回按下的键的ASCII码值。如果没有按键被按下,则返回-1。
4.1 图像窗口刷新机制
cv2.waitKey()
是 OpenCV 窗口系统的事件处理核心- 调用此函数会强制刷新所有通过
cv2.imshow()
显示的窗口 - 没有这个调用,窗口会显示为灰色或显示旧内容,无法更新为最新图像帧
4.2 键盘事件检测
- 函数会检测并返回最近按下的按键的 ASCII 码值
- 参数
1
表示等待时间为 1 毫秒,这是一个非阻塞式等待 - 在等待期间,它会检查是否有按键事件发生
4.3 waitKey(0)
- 无限等待
- 程序会暂停,直到用户按下任意键
- 常用于静态图像显示场景
- 示例:显示一张图片后等待用户按键关闭窗口
4.4 waitKey(1)
- 短时等待(推荐用于实时应用)
- 等待 1 毫秒后继续执行
- 在等待期间检查按键事件
- 保持程序流畅运行的同时响应按键
- 最佳实践:在视频处理循环中使用
4.4 waitKey(25)
- 控制帧率
- 等待 25 毫秒 ≈ 40 FPS (1000ms/25ms)
- 可用于控制视频播放速度
4.5 & 0xFF
waitKey()
返回的是 32 位整数- 在 64 位系统上,高位可能包含无关数据
& 0xFF
操作只保留最低的 8 位(一个字节)- 确保我们只获取有效的 ASCII 码值