C++ OpenCV 视频处理(实战指南)

C++ OpenCV 视频处理入门与实战

C++ OpenCV 视频处理 是许多开发者在图像识别、视频分析和计算机视觉项目中常用的技能。OpenCV 提供了丰富的 API 来读取、处理和写入视频流,本文将围绕这些核心功能,提供实用的代码示例和技巧,帮助你在工作中快速实现视频处理需求。


快速解决

要使用 OpenCV 在 C++ 中处理视频,首先需要包含相关头文件并初始化 VideoCaptureVideoWriter 对象。以下是一个最简单的视频读取和保存示例:

#include <opencv2/opencv.hpp> // 包含 OpenCV 头文件
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    VideoCapture cap("input.mp4"); // 打开视频文件
    if (!cap.isOpened()) {
        cout << "无法打开视频文件" << endl; // 如果失败,输出错误信息
        return -1;
    }

    int frameWidth = static_cast<int>(cap.get(CAP_PROP_FRAME_WIDTH)); // 获取视频宽度
    int frameHeight = static_cast<int>(cap.get(CAP_PROP_FRAME_HEIGHT)); // 获取视频高度
    VideoWriter writer("output.mp4", VideoWriter::fourcc('M','P','4','V'), 30, Size(frameWidth, frameHeight), true); // 创建 VideoWriter 保存处理后的视频

    Mat frame;
    while (true) {
        cap >> frame; // 读取视频帧
        if (frame.empty()) break; // 如果帧为空,说明视频结束

        // 在这里添加视频处理逻辑,例如灰度化
        cvtColor(frame, frame, COLOR_BGR2GRAY); // 将彩色帧转为灰度

        writer << frame; // 写入处理后的帧
        imshow("视频处理", frame); // 显示处理中的帧
        if (waitKey(30) == 27) break; // 按 ESC 键退出
    }

    cap.release(); // 释放视频捕获对象
    writer.release(); // 释放视频写入对象
    destroyAllWindows(); // 关闭所有窗口
    return 0;
}

常用方法

以下是 C++ OpenCV 视频处理中常见的方法,按使用频率排序:

方法名 作用描述 是否常用
VideoCapture::open() 打开视频文件或摄像头
VideoCapture::read() / >> 读取视频帧
VideoWriter::write() / << 写入视频帧
CAP_PROP_FRAME_WIDTH / CAP_PROP_FRAME_HEIGHT 获取视频宽高
CAP_PROP_FPS 获取帧率
cvtColor() 颜色空间转换
GaussianBlur() 高斯模糊处理
flip() 帧翻转(例如左右镜像)

详细说明

视频读取与显示

OpenCV 通过 VideoCapture 类读取视频文件,支持从文件或摄像头获取视频流:

VideoCapture cap("input.mp4"); // 从文件读取视频
if (!cap.isOpened()) {
    cout << "无法打开视频文件" << endl;
    return -1;
}

Mat frame;
while (true) {
    cap >> frame; // 读取下一帧
    if (frame.empty()) break;

    imshow("原始视频", frame); // 显示帧
    if (waitKey(30) == 27) break; // 按 ESC 退出
}

视频保存与写入

处理完视频帧后,使用 VideoWriter 将帧写入新文件:

int frameWidth = static_cast<int>(cap.get(CAP_PROP_FRAME_WIDTH));
int frameHeight = static_cast<int>(cap.get(CAP_PROP_FRAME_HEIGHT));
double fps = cap.get(CAP_PROP_FPS);

VideoWriter writer("output.mp4", 
                   VideoWriter::fourcc('M','P','4','V'), // 视频编码格式
                   fps, // 帧率
                   Size(frameWidth, frameHeight), // 分辨率
                   true); // 是否是彩色视频

Mat frame;
while (true) {
    cap >> frame;
    if (frame.empty()) break;

    // 示例:添加处理逻辑
    GaussianBlur(frame, frame, Size(15,15), 0); // 对帧进行高斯模糊

    writer << frame; // 写入帧到输出视频
}

视频属性获取

你可以通过 cap.get() 方法获取视频的详细属性,例如宽高、帧率、总帧数等:

int width = static_cast<int>(cap.get(CAP_PROP_FRAME_WIDTH)); // 获取视频宽度
int height = static_cast<int>(cap.get(CAP_PROP_FRAME_HEIGHT)); // 获取视频高度
double fps = cap.get(CAP_PROP_FPS); // 获取帧率
int totalFrames = static_cast<int>(cap.get(CAP_PROP_FRAME_COUNT)); // 获取总帧数
int codec = static_cast<int>(cap.get(CAP_PROP_FOURCC)); // 获取编码格式

cout << "视频宽度: " << width << endl;
cout << "视频高度: " << height << endl;
cout << "帧率: " << fps << endl;
cout << "总帧数: " << totalFrames << endl;
cout << "编码格式: " << codec << endl;

高级技巧

实时摄像头处理与保存

如果你需要从摄像头读取视频并实时处理:

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

int width = static_cast<int>(cap.get(CAP_PROP_FRAME_WIDTH));
int height = static_cast<int>(cap.get(CAP_PROP_FRAME_HEIGHT));
double fps = cap.get(CAP_PROP_FPS);

VideoWriter writer("output_webcam.mp4", 
                   VideoWriter::fourcc('M','P','4','V'),
                   fps,
                   Size(width, height),
                   true);

Mat frame;
while (true) {
    cap >> frame;
    if (frame.empty()) break;

    // 示例:灰度化 + 反色处理
    cvtColor(frame, frame, COLOR_BGR2GRAY);
    bitwise_not(frame, frame); // 反色

    writer << frame;
    imshow("处理中的摄像头", frame);
    if (waitKey(30) == 27) break;
}

cap.release();
writer.release();
destroyAllWindows();

视频帧率控制与跳帧处理

在某些场景下(如视频分析),你可能希望跳过某些帧以提高效率:

int skipFrame = 2; // 跳过每两帧
int count = 0;
Mat frame;

while (true) {
    cap >> frame;
    if (frame.empty()) break;

    if (count % skipFrame == 0) { // 只处理每隔 skipFrame 帧
        writer << frame;
        imshow("处理中的视频", frame);
    }
    count++;
}

常见问题

Q:为什么保存的视频没有声音?
A:OpenCV 的 VideoWriter 不支持音频通道,只能保存视频帧。如果需要带音频的输出,需使用其他工具(如 FFmpeg)进行后期合成。

Q:如何判断视频是否打开成功?
A:调用 cap.isOpened() 方法,返回 true 表示成功打开,否则为 false

Q:为什么输出视频播放不了?
A:可能使用了不兼容的编码格式(FourCC),例如在某些系统上 'M','P','4','V' 不可用,可以尝试 'X','V','I','D' 或其他格式。

Q:如何获取视频的当前帧号?
A:使用 cap.get(CAP_PROP_POS_FRAMES),该方法返回当前已读取的帧数。


总结

C++ OpenCV 视频处理 提供了强大的工具来读取、处理和保存视频,掌握基本的 VideoCaptureVideoWriter 用法即可完成大部分任务,结合颜色转换、模糊处理等图像操作,可以实现更多实际功能。