opencv 之 视频类 VideoCapture、VideoWriter详细介绍

发布于:2025-06-14 ⋅ 阅读:(16) ⋅ 点赞:(0)

opencv 之 视频类 VideoCapture、VideoWriter 详细介绍

  • VideoCapture 用于打开视频文件或者摄像头及设置相关属性
  • VideoWriter 用于保存视频文件及设置相关属性

1. VideoCapture

  • cv::VideoCapture 是 OpenCV 中用于从视频文件、图像序列或摄像头捕获视频的类。它是 OpenCV 视频处理模块的核心类之一。

  • cv::VideoCapture 提供了以下主要功能:

    • 从视频文件(如 .avi, .mp4 等)读取帧
    • 摄像头捕获实时视频流
    • 从图像序列(一系列编号图像)读取帧
    • 获取和设置视频属性(如帧率、分辨率等)
  • 构造函数

// 默认构造函数
cv::VideoCapture();

// 从文件或设备构造
cv::VideoCapture(const String& filename, int apiPreference = CAP_ANY);
cv::VideoCapture(int index, int apiPreference = CAP_ANY);


参数说明:

filename:视频文件名或图像序列模式(如 "img_%02d.jpg")
index:摄像头索引(0 通常是默认摄像头)
apiPreference:指定使用的后端 API(如 CAP_FFMPEG, CAP_V4L2 等)
  • 常用方法
//打开视频源
bool open(const String& filename, int apiPreference = CAP_ANY);
bool open(int index, int apiPreference = CAP_ANY);

//检查是否成功打开
bool isOpened() const;
//读取帧
// 读取下一帧到 image
bool read(OutputArray image);

// 等同于 read(),但返回是否成功
VideoCapture& operator >> (Mat& image);

// 抓取下一帧(不解码)
bool grab();

// 解码并返回抓取的帧
bool retrieve(OutputArray image, int flag = 0);
//获取/设置属性
double get(int propId) const;
bool set(int propId, double value);

//常用属性 ID(在 cv::VideoCaptureProperties 中定义):
CAP_PROP_FRAME_WIDTH - 帧宽度
CAP_PROP_FRAME_HEIGHT - 帧高度
CAP_PROP_FPS - 帧率
CAP_PROP_FRAME_COUNT - 总帧数(视频文件)
CAP_PROP_POS_FRAMES - 当前帧位置
CAP_PROP_POS_MSEC - 当前时间位置(毫秒)
//释放资源
void release();

使用示例

//示例1:从摄像头捕获
#include <opencv2/opencv.hpp>

int main() {
    cv::VideoCapture cap(0); // 打开默认摄像头
    if (!cap.isOpened()) {
        std::cerr << "无法打开摄像头" << std::endl;
        return -1;
    }

    cv::Mat frame;
    while (true) {
        cap >> frame; // 或 cap.read(frame);
        if (frame.empty()) break;
        
        cv::imshow("摄像头", frame);
        if (cv::waitKey(30) >= 0) break;
    }
    
    cap.release();
    return 0;
}
//示例2:从视频文件读取
#include <opencv2/opencv.hpp>

int main() {
    cv::VideoCapture cap("video.mp4");
    if (!cap.isOpened()) {
        std::cerr << "无法打开视频文件" << std::endl;
        return -1;
    }

    // 获取视频属性
    double fps = cap.get(cv::CAP_PROP_FPS);
    int width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
    int height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
    std::cout << "视频信息: " << width << "x" << height << ", " << fps << " FPS" << std::endl;

    cv::Mat frame;
    while (cap.read(frame)) {
        cv::imshow("视频播放", frame);
        if (cv::waitKey(1000/fps) >= 0) break; // 按正确帧率显示
    }
    
    cap.release();
    return 0;
}
//示例3:从图像序列读取
cv::VideoCapture cap("img_%02d.jpg"); // 读取 img_00.jpg, img_01.jpg, ...
注意事项:
- 使用后务必调用 release() 释放资源
- 检查 isOpened() 确保视频源已正确打开
- 对于大视频文件,考虑使用 grab() + retrieve() 以提高性能
- 不同视频格式和编解码器的支持取决于安装的 OpenCV 版本和编解码器
- 在多线程环境中使用时需要注意线程安全
  • 高级用法
//使用特定后端 API
cv::VideoCapture cap("video.mp4", cv::CAP_FFMPEG);

//设置缓冲区大小
cap.set(cv::CAP_PROP_BUFFERSIZE, 1); // 减少延迟

//多摄像头同步
cv::VideoCapture cap1(0), cap2(1);
cap1.grab(); cap2.grab(); // 同步抓取
cv::Mat frame1, frame2;
cap1.retrieve(frame1);
cap2.retrieve(frame2);

2. cv::VideoWriter

  • cv::VideoWriter 是 OpenCV 中用于写入视频文件或图像序列的类,与 cv::VideoCapture 相对应,用于视频的保存和输出。

  • cv::VideoWriter 提供以下主要功能:

    • 将帧序列写入视频文件
    • 支持多种视频格式(如 .avi, .mp4 等)
    • 可设置视频编码器、帧率、分辨率等参数
    • 支持多通道图像写入
  • 构造函数

// 默认构造函数
cv::VideoWriter();

// 带参数的构造函数
cv::VideoWriter(const String& filename, int fourcc, double fps, 
                Size frameSize, bool isColor = true);

参数说明:
filename:输出视频文件名
fourcc:四字符编码的编解码器(如 "MJPG", "X264")
fps:输出视频的帧率
frameSize:视频帧的大小(宽度和高度)
isColor:是否为彩色视频(默认为 true
  • 常用方法
//打开视频写入器
bool open(const String& filename, int fourcc, double fps, 
          Size frameSize, bool isColor = true);

//检查是否成功打开
bool isOpened() const;
  • 写入帧
// 写入一帧
void write(InputArray image);

// 等同于 write()
VideoWriter& operator << (const Mat& image);

//释放资源
void release();
  • 四字符编码(FourCC)
FourCC 是视频编解码器的四字符代码,常见的有:

"MJPG" - Motion-JPEG
"XVID" - XVID MPEG-4
"X264" - H.264/AVC
"MP4V" - MPEG-4
"AVC1" - H.264
"H264" - H.264
"VP80" - VP8
//可以使用 cv::VideoWriter::fourcc() 函数生成 FourCC 代码:
int fourcc = cv::VideoWriter::fourcc('M', 'J', 'P', 'G');

使用示例

示例1:创建并写入视频文件
#include <opencv2/opencv.hpp>

int main() {
    // 创建一个 VideoWriter 对象
    cv::VideoWriter writer;
    
    // 设置视频参数
    int fourcc = cv::VideoWriter::fourcc('M', 'J', 'P', 'G'); // 编解码器
    double fps = 30.0; // 帧率
    cv::Size frameSize(640, 480); // 帧大小
    
    // 打开视频文件
    writer.open("output.avi", fourcc, fps, frameSize, true);
    
    if (!writer.isOpened()) {
        std::cerr << "无法创建视频文件" << std::endl;
        return -1;
    }
    
    // 创建一些示例帧(这里用彩色渐变作为示例)
    for (int i = 0; i < 300; i++) { // 写入300帧
        cv::Mat frame(frameSize, CV_8UC3);
        
        // 创建渐变效果
        for (int y = 0; y < frame.rows; y++) {
            for (int x = 0; x < frame.cols; x++) {
                frame.at<cv::Vec3b>(y, x) = cv::Vec3b(
                    (x + i) % 256, // B
                    (y + i) % 256, // G
                    (x + y + i) % 256 // R
                );
            }
        }
        
        writer.write(frame); // 写入帧
        // 或者使用 writer << frame;
        
        cv::imshow("正在写入的视频", frame);
        if (cv::waitKey(30) >= 0) break;
    }
    
    writer.release(); // 释放资源
    cv::destroyAllWindows();
    return 0;
}
示例2:从摄像头捕获并保存视频
#include <opencv2/opencv.hpp>

int main() {
    // 打开摄像头
    cv::VideoCapture cap(0);
    if (!cap.isOpened()) {
        std::cerr << "无法打开摄像头" << std::endl;
        return -1;
    }
    
    // 获取摄像头参数
    int frame_width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
    int frame_height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
    double fps = cap.get(cv::CAP_PROP_FPS);
    if (fps <= 0) fps = 30; // 如果获取不到帧率,使用默认值
    
    // 创建 VideoWriter
    int fourcc = cv::VideoWriter::fourcc('X', 'V', 'I', 'D'); // XVID 编码
    cv::VideoWriter writer("camera_output.avi", fourcc, fps, 
                          cv::Size(frame_width, frame_height));
    
    if (!writer.isOpened()) {
        std::cerr << "无法创建视频文件" << std::endl;
        return -1;
    }
    
    cv::Mat frame;
    while (true) {
        cap >> frame; // 从摄像头捕获一帧
        
        if (frame.empty()) break;
        
        writer.write(frame); // 写入视频文件
        
        cv::imshow("摄像头捕获", frame);
        if (cv::waitKey(30) >= 0) break; // 按任意键退出
    }
    
    cap.release();
    writer.release();
    cv::destroyAllWindows();
    return 0;
}
示例3:使用不同编解码器
// 使用 H.264 编码
int fourcc = cv::VideoWriter::fourcc('H', '2', '6', '4');
cv::VideoWriter writer("h264_output.mp4", fourcc, 30.0, cv::Size(640, 480));

// 使用 VP8 编码
int fourcc = cv::VideoWriter::fourcc('V', 'P', '8', '0');
cv::VideoWriter writer("vp8_output.webm", fourcc, 30.0, cv::Size(640, 480));
  • 注意事项

    • 1.​​编解码器支持​​:不是所有编解码器在所有系统上都可用,取决于安装的 OpenCV 版本和编解码器库
    • 2.文件扩展名​​:文件扩展名应与编解码器匹配(如 .avi 用于 MJPG,.mp4 用于 H.264)
    • ​​3.帧大小一致性​​:所有写入的帧必须与构造函数中指定的大小相同
    • ​​4.颜色格式​​:如果构造函数中指定 isColor=true,则必须写入 3 通道 (BGR) 图像
    • ​​5.性能考虑​​:视频编码可能很耗资源,高分辨率/高帧率视频可能需要优化
    • ​​6.释放资源​​:务必调用 release() 以确保视频文件正确关闭
  • 高级用法

检查编解码器支持
// 检查特定编解码器是否可用
if (!writer.isOpened()) {
    std::cerr << "编解码器不可用,尝试其他编解码器" << std::endl;
    fourcc = cv::VideoWriter::fourcc('M', 'J', 'P', 'G');
    writer.open("output.avi", fourcc, fps, frameSize);
}
写入灰度视频
// 创建灰度视频写入器
cv::VideoWriter writer("gray_output.avi", fourcc, fps, frameSize, false);

// 写入灰度帧
cv::Mat grayFrame;
cv::cvtColor(colorFrame, grayFrame, cv::COLOR_BGR2GRAY);
writer.write(grayFrame);
设置视频质量
// 对于某些编解码器,可以设置质量参数
writer.set(cv::VIDEOWRITER_PROP_QUALITY, 95); // 质量百分比 (0-100)
多线程视频写入
// 在一个线程捕获,另一个线程写入
std::thread writerThread([&]() {
    while (!frames.empty() || capturing) {
        if (!frames.empty()) {
            writer.write(frames.front());
            frames.pop();
        }
    }
});

cv::VideoWriter 是 OpenCV 视频输出的核心类,熟练掌握它可以实现各种视频录制和保存功能。根据实际需求选择合适的编解码器和参数,可以优化视频质量和文件大小。