OpenCV Python 视频实战:用 VideoCapture 与 VideoWriter 完成视频读取、显示与保存

📅 发布时间:2026/9/7 6:53:06
OpenCV Python 视频实战:用 VideoCapture 与 VideoWriter 完成视频读取、显示与保存
OpenCV Python 视频实战用 VideoCapture 与 VideoWriter 完成视频读取、显示与保存【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv本文基于 OpenCV 官方 Python 教程 py_video_display.markdown 展开系统讲解 OpenCV Python 接口中视频处理三件套的完整用法从摄像头实时采集cv.VideoCapture()、从文件播放视频、逐帧写入并保存视频cv.VideoWriter()并结合 videoio.hpp 中的类定义与属性枚举深入read()、grab()/retrieve()、get()/set()的底层语义以及各平台后端FFmpeg、GStreamer、DirectShow 等的选择机制帮助读者写出可复制、可排错的视频 I/O 代码。一、目标与函数总览本教程的核心目标是学会读取视频、显示视频、保存视频学会从摄像头采集视频并显示掌握两个核心类cv.VideoCapture()采集/读取与cv.VideoWriter()写入。在源码层面这两个类对应 C 侧的cv::VideoCapture与cv::VideoWriter声明于 videoio.hpp。VideoCapture的文档注释中明确指出Python 基础示例位于 samples/python/video.py多线程示例位于samples/python/video_threaded.pyV4L2 后端特性演示位于samples/python/video_v4l2.py均可作为本教程代码的进阶参考。二、从摄像头采集视频VideoCapture实时采集是视频应用中最常见的场景。OpenCV 提供了一个非常简单的接口创建VideoCapture对象其构造参数可以是设备索引摄像头编号或视频文件名。设备索引只是一个整数用于指定使用哪个摄像头——通常只连接一个摄像头直接传0即可传1表示选择第二个摄像头依此类推。创建后逐帧读取最后务必释放release采集对象。官方教程给出的完整示例打开默认摄像头转成灰度视频并显示import numpy as np import cv2 as cv cap cv.VideoCapture(0) if not cap.isOpened(): print(Cannot open camera) exit() while True: # Capture frame-by-frame ret, frame cap.read() # if frame is read correctly ret is True if not ret: print(Cant receive frame (stream end?). Exiting ...) break # Our operations on the frame come here gray cv.cvtColor(frame, cv.COLOR_BGR2GRAY) # Display the resulting frame cv.imshow(frame, gray) if cv.waitKey(1) ord(q): break # When everything done, release the capture cap.release() cv.destroyAllWindows()几个关键点需要理解cap.read()的返回值。它返回一个布尔值帧读取成功时为True。因此可以通过检查该返回值判断视频是否读到结尾流结束。从源码结构看read()在 C 侧的注释写明它“combines VideoCapture::grab() and VideoCapture::retrieve() in one call”即 videoio.hpp 中read()是grab()抓取原始帧retrieve()解码并返回Mat的一次性组合。失败时返回false并给出空图像可用Mat::empty()判断。cap.isOpened()检查初始化状态。有时cap未能成功初始化此时代码会报错。用cap.isOpened()检查为True表示正常否则应改用cap.open()显式打开。示例开头的if not cap.isOpened(): exit()就是这种防御式写法。资源释放。结束时调用cap.release()关闭摄像头/文件。C 侧的release()注释说明它会被后续的open()调用和析构函数自动调用但显式释放是好习惯。排错提示继承原文档如果采集报错请先用其他相机应用如 Linux 下的 Cheese确认摄像头本身工作正常——大部分视频采集问题源于设备或驱动而非 OpenCV 代码。源码佐证read/grab/retrieve 的分工对于多摄像头或多通道设备如立体相机、Kinect 类多深度/红外头设备read()的一体化流程并不总是最优。从 videoio.hpp 中grab()的注释可以看到其设计意图对多个摄像头先各自调用grab()再分别调用较慢的retrieve()完成解码可以消除去马赛克、Motion JPEG 解压等开销带来的时间差使各摄像头取回的帧在时间上更接近对多头设备则需先grab()再按不同channel多次retrieve()。单摄像头逐帧显示时read()就是最便捷的选择。三、用 get() / set() 读取和修改视频属性教程指出可以通过cap.get(propId)访问视频的一些特性propId是0到18的整数编号教程写作时的范围每个编号对应视频的一个属性若该属性适用于该视频。部分属性还可以用cap.set(propId, value)修改value即想要的新值。例如用cap.get(cv.CAP_PROP_FRAME_WIDTH)和cap.get(cv.CAP_PROP_FRAME_HEIGHT)可以查看帧宽高默认是 640×480若想改成 320×240只需ret cap.set(cv.CAP_PROP_FRAME_WIDTH, 320) ret cap.set(cv.CAP_PROP_FRAME_HEIGHT, 240)属性枚举全景从 0~18 到 73 的扩展当前仓库源码中这些编号对应 videoio.hpp 的VideoCaptureProperties枚举已经扩展到 73 号。常用通用属性如下表编号与源码枚举值一致常量编号含义CAP_PROP_POS_MSEC0视频文件当前位置毫秒CAP_PROP_POS_FRAMES1下一个要解码/采集的帧索引0 基CAP_PROP_POS_AVI_RATIO2相对位置0片头1片尾CAP_PROP_FRAME_WIDTH3帧宽像素CAP_PROP_FRAME_HEIGHT4帧高像素CAP_PROP_FPS5帧率CAP_PROP_FOURCC6编解码器 4 字节代码CAP_PROP_FRAME_COUNT7视频文件总帧数CAP_PROP_FORMAT8返回 Mat 的格式默认 8UC3设为 -1 可取 RAW 流CAP_PROP_BRIGHTNESS10亮度仅支持该功能的摄像头CAP_PROP_CONTRAST11对比度CAP_PROP_SATURATION12饱和度CAP_PROP_GAIN14增益CAP_PROP_EXPOSURE15曝光CAP_PROP_CONVERT_RGB16是否转换为 BGRCAP_PROP_WHITE_BALANCE_BLUE_U17目前不支持CAP_PROP_RECTIFICATION18立体相机矫正标志仅 DC1394 v2.x 后端教程原文的“0 到 18”正是表中到CAP_PROP_RECTIFICATION为止的通用属性段。此后源码又陆续加入了CAP_PROP_MONOCHROME(19)、CAP_PROP_AUTO_EXPOSURE(21)、CAP_PROP_ZOOM(27)、CAP_PROP_FOCUS(28)、CAP_PROP_BUFFERSIZE(38)、CAP_PROP_AUTOFOCUS(39)、CAP_PROP_BACKEND(42只读返回当前所用后端)、音频相关 58~66、FFmpeg 专有的CAP_PROP_FRAME_TYPE(69)、CAP_PROP_PTS(71) 等可按需查阅枚举完整注释。两个容易踩坑的语义细节源码注释中写得很明确set()返回True不代表设置生效。VideoCapture::set()注释videoio.hpp写道“Even if it returnstruethis doesnt ensure that the property value has been accepted by the capture device”即它只说明后端支持该属性硬件/驱动是否接受该值另当别论。枚举头部的注释也强调“Reading / writing properties involves many layers... Effective behaviour depends from device hardware, driver and API Backend”。因此设置分辨率后建议再get()一次验证实际值。get()返回 -1 表示属性未知或不支持CAP_PROP_UNKNOWN -1可作为探测“当前后端支持哪些属性”的简单手段。仓库中官方示例 samples/python/video.py 的create_capture()函数就实际演示了设置分辨率的用法cap cv.VideoCapture(source) if size in params: w, h map(int, params[size].split(x)) cap.set(cv.CAP_PROP_FRAME_WIDTH, w) cap.set(cv.CAP_PROP_FRAME_HEIGHT, h)四、从文件播放视频从文件播放视频与从摄像头采集完全一样只需把摄像头索引换成视频文件名。另外一个关键点是显示帧时cv.waitKey()的取值值太小 → 视频播放过快值太大 → 视频播放变慢这正是慢动作显示的来源正常情况下 25 毫秒是合适的取值对应约 25 FPS 的节拍。教程示例文件名换成任意视频例如仓库自带的测试视频 samples/data/vtest.aviimport numpy as np import cv2 as cv cap cv.VideoCapture(vtest.avi) while cap.isOpened(): ret, frame cap.read() # if frame is read correctly ret is True if not ret: print(Cant receive frame (stream end?). Exiting ...) break gray cv.cvtColor(frame, cv.COLOR_BGR2GRAY) cv.imshow(frame, gray) if cv.waitKey(1) ord(q): break cap.release() cv.destroyAllWindows()排错提示继承原文档请确保安装了正确版本的 FFmpeg 或 GStreamer。视频采集问题中很大一部分由 ffmpeg/gstreamer 安装不当引起。源码佐证后端自动选择机制“同一个cv.VideoCapture(文件名)在不同操作系统上能正常工作”背后是后端的自动选择。videoio.hpp 中VideoCaptureAPIs枚举列出了全部内置后端及其编号后端常量编号说明CAP_ANY0自动探测默认值CAP_V4L/CAP_V4L2200Linux Video4LinuxCAP_DSHOW700Windows DirectShowCAP_AVFOUNDATION1200iOS/macOS AVFoundationCAP_MSMF1400Windows Media FoundationCAP_GSTREAMER1800GStreamer支持 gst-launch 格式的 pipeline 字符串CAP_FFMPEG1900FFmpeg读/写文件与流媒体CAP_IMAGES2000OpenCV 图像序列如img_%02d.jpgCAP_OPENCV_MJPEG2200内置 OpenCV MotionJPEG 编解码器CAP_INTEL_MFX2300Intel MediaSDKCAP_XINE2400Linux XINE 引擎构造函数注释说明filename参数实际上可以是四类输入视频文件名、图像序列模式img_%02d.jpg会依次读取img_00.jpg、img_01.jpg……、视频流 URLprotocol://host:port/...、或 GStreamer pipeline 字符串。当系统编译了多个后端时CAP_ANY会按内置优先级逐一尝试如果自动选择结果不理想可以显式传第二个参数强制指定后端例如cv.VideoCapture(rtsp://..., cv.CAP_FFMPEG)。这也解释了为什么教程特别强调 ffmpeg/gstreamer 的安装问题CAP_ANY能否成功直接取决于当前 OpenCV 二进制里编译进了哪些后端源码注释明确提示 “Backends are available only if they have been built with your OpenCV binaries”。此外新版构造函数还支持params参数paramId, value键值对形式在打开时传入open-only属性如CAP_PROP_HW_ACCELERATION(50)、CAP_PROP_OPEN_TIMEOUT_MSEC(53)、CAP_PROP_READ_TIMEOUT_MSEC(54) 等对 RTSP 流的打开/读取超时控制尤为实用。五、保存视频VideoWriter与 FourCC 代码采集并逐帧处理后常需要把结果保存为视频文件。图片只需cv.imwrite()视频则需要多做一些创建VideoWriter对象依次指定输出文件名如output.aviFourCC 编码见下段说明每秒帧数fps帧尺寸宽×高cv2.Size或元组isColor标志True表示编码器期望彩色帧False表示按灰度帧处理。FourCC是用于指定视频编解码器的 4 字节代码其可用列表因平台而异教程原文给出的经验值如下FedoraDIVX、XVID、MJPG、X264、WMV1、WMV2XVID 较推荐MJPG 生成的视频体积较大X264 生成的视频体积很小WindowsDIVX其余待补充macOSMJPG.mp4、DIVX.avi、X264.mkv。FourCC 的传法是cv.VideoWriter_fourcc(M,J,P,G)或简写的cv.VideoWriter_fourcc(*MJPG)展开字符串为 4 个字符参数。教程示例从摄像头采集对每一帧做垂直翻转并保存为视频import numpy as np import cv2 as cv cap cv.VideoCapture(0) # Define the codec and create VideoWriter object fourcc cv.VideoWriter_fourcc(*XVID) out cv.VideoWriter(output.avi, fourcc, 20.0, (640, 480)) while cap.isOpened(): ret, frame cap.read() if not ret: print(Cant receive frame (stream end?). Exiting ...) break frame cv.flip(frame, 0) # write the flipped frame out.write(frame) cv.imshow(frame, frame) if cv.waitKey(1) ord(q): break # Release everything if job is finished cap.release() out.release() cv.destroyAllWindows()几点实操注意事项out.write(frame)对每帧执行一次写入前必须保证frame的尺寸与构造VideoWriter时声明的(640, 480)一致通道数与isColor默认True即 3 通道 BGR一致。若从摄像头取回的分辨率不同可用cap.get(cv.CAP_PROP_FRAME_WIDTH)查询实际值应先cv.resize()。fps 参数这里取20.0只是文件封装的时间基准不要求与实际采集帧率严格相等但建议接近真实帧率以免播放节奏失真。结束前out.release()会 flush 缓冲并写文件尾缺了它输出文件可能损坏。源码佐证VideoWriter 属性枚举videoio.hpp 中的VideoWriterProperties枚举补充了教程未展开的写入端控制项VIDEOWRITER_PROP_QUALITY(1编码质量 0~100%部分编码器可动态调整)、VIDEOWRITER_PROP_IS_COLOR(4对应构造函数的isColor)、VIDEOWRITER_PROP_DEPTH(5默认CV_8U)以及仅 FFmpeg/GStreamer 后端的VIDEOWRITER_PROP_HW_ACCELERATION、VIDEOWRITER_PROP_COLOR_SPACE(14像素格式如 I420、NV12)、VIDEOWRITER_PROP_ENABLE_ALPHA(15输入含 alpha 通道) 等。VideoWriter同样支持get()/set()动态调参例如写入过程中按帧调整QUALITY。六、进阶官方示例 video.py 的完整实践仓库自带的 samples/python/video.py 把本教程的三个要点整合成了一个可运行的命令行程序它接收多个视频源摄像头索引、视频文件、或synth:过程化合成视频逐个cap.read()显示支持按 ESC 退出、按空格保存当前帧caps list(map(create_capture, sources)) while True: imgs [] for i, cap in enumerate(caps): ret, img cap.read() imgs.append(img) cv.imshow(capture %d % i, img) ch cv.waitKey(1) if ch 27: break ...其中create_capture()还演示了两条实用技巧cv.VideoCapture(source)打开失败时自动回退到过程化合成视频保证无摄像头环境也能调试管线以及用cap.set(cv.CAP_PROP_FRAME_WIDTH/HEIGHT, ...)按命令行参数调整分辨率。测试视频资源可直接使用仓库自带的 samples/data/vtest.avi、samples/data/Megamind.avi、samples/data/tree.avi。七、小结需求API关键点采集/读文件cv.VideoCapture(index)/cv.VideoCapture(filename)用isOpened()防御read()返回(ret, frame)结束release()查询/修改属性cap.get(propId)/cap.set(propId, value)属性编号见VideoCaptureProperties枚举set()返回 True 仍需get()验证显示节拍cv.waitKey(ms)25ms 约为正常播放过大成慢动作保存视频cv.VideoWriter(filename, fourcc, fps, size, isColor)FourCC 依平台选择write()前对齐尺寸与通道数release()收尾强制后端cv.VideoCapture(source, cv.CAP_FFMPEG)等自动选择失败时显式指定后端可用性取决于编译选项排查顺序建议先确认设备/文件本身可用 → 确认 OpenCV 编译了对应后端FFmpeg/GStreamer/V4L2/DirectShow→ 用isOpened()、CAP_PROP_BACKEND、read()返回值逐层定位。按此路径本教程的三段代码即可直接迁移到真实项目中。【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考