自学内容网 自学内容网

实战OpenCV之视频处理

基础入门

        视频是由一系列连续的图像帧组成的,这些帧按照一定的速率连续播放,从而形成动态画面。与视频相关的主要参数有:分辨率、帧率、码率、编解码器、帧类型、文件格式等,下面分别进行介绍。

        1、帧率。表示每秒显示的图像帧数,该参数决定视频流畅度,更高的帧率意味着更平滑的动作。常见的帧率有:24fps(电影)、30fps(电视标准)、60fps(流畅的游戏体验)等。

        2、分辨率。表示视频每一帧图像的宽度和高度,通常以像素为单位,该参数决定视频的清晰度和细节程度。常见的分辨率有:720p(1280 x 720)、1080p(1920 x 1080)、4K(3840 x 2160)等。

        3、码率。也叫比特率,指每秒传送的数据量,通常以kbps (千比特/秒) 或 Mbps (兆比特/秒) 表示。该参数影响视频的质量和文件大小,高比特率意味着更好的视频质量,但文件也更大。码率可以是恒定的(CBR, Constant Bitrate),也可以是可变的(VBR, Variable Bitrate)。

        4、编解码器。即Codec,是编码器和解码器的组合词,用于压缩和解压视频数据。该参数影响视频质量和文件大小,常见的编解码算法有:H.264/AVC、H.265/HEVC、MJPEG、VP9等。

        5、帧类型。在H.264、H.265编码算法中,使用了不同的帧类型来提高压缩效率,主要包括I帧、P帧和B帧。

        (1)I帧:也称为帧内编码帧,是一个完整的图像帧,它包含了该帧所有的图像信息,类似于一张静态图片。I帧不需要参考其他任何帧来解码,因此可以在视频的任何点开始播放。但是,由于包含完整信息,所以占用的空间较大。通常用于视频的开头或场景变化较大的地方,因为这些位置不适合使用预测编码。

        (2)P帧:也称为前向预测帧,只包含相对于前一帧变化的部分信息。P帧会参考前一个I帧或P帧来进行解码,通过对前一帧的预测,P帧只需要记录变化的内容,这样就能大大减少所需的存储空间。P帧在视频中占大多数,用于高效地表示场景中变化不大的部分。

        (3)B帧:也称为双向预测帧,会同时向前和向后参考相邻的I帧或P帧。B帧进一步提高了压缩效率,但增加了解码复杂度。

        6、文件格式。用于存储视频数据的标准或容器,不同的视频文件格式有着不同的特性和用途。常见的视频文件格式有:MP4、AVI、MOV、FLV、MPEG、WMV等。

API接口

        cv::VideoCapture是OpenCV中用于处理视频输入的核心类之一,它可以用来从摄像头设备或视频文件中捕获视频帧。cv::VideoCapture类构造函数的原型如下。

VideoCapture();
VideoCapture(int device_index);
VideoCapture(const String& filename);

        各个参数的含义如下。

        device_index:整数,表示设备索引,通常0表示第一个摄像头。

        filename:视频文件的路径。

        cv::VideoCapture类提供了很多实用性的方法来控制视频流,其导出的主要方法如下。

        open用于打开摄像头或者视频文件,成功打开设备或文件返回true,失败返回false。其参数的含义与上面完全相同,故这里不再赘述。

bool open(int device_index);
bool open(const String& filename);

        read用于读取一帧视频数据,成功读取帧返回true,失败返回false。参数image为一个OutputArray,通常是一个cv::Mat对象,用于接收读取到的帧。

bool read(OutputArray image);

        grab会提前获取下一帧的数据,但并不立即填充到image中。如果成功获取下一帧,grab方法返回true。如果没有更多的帧可获取,或者发生错误,grab方法返回false。

bool grab();

        retrieve将先前通过grab方法获取的帧数据填充到image中。如果成功填充了一帧,retrieve方法返回true,并且image将包含这一帧的数据。如果没有通过grab方法获取帧,或者发生错误,retrieve方法返回false。grab和retrieve方法通常一起使用,先通过grab获取下一帧,再通过retrieve获取该帧的数据。这种分离的设计使得处理视频流时更为灵活,可以在获取下一帧之前处理当前帧,或者处理多路视频流。

bool retrieve(OutputArray image, int stream = 0);

        各个参数的含义如下。

        image:一个OutputArray,通常是一个cv::Mat对象,用于接收读取的帧。

        stream:整数,指定要从中检索帧的流。对于单流设备,默认为0。

        isOpened用于判断视频设备或文件是否打开,如果已成功打开,则返回true,否则返回false。

bool isOpened() const;

        release用于释放VideoCapture对象所使用的资源。

void release();

实战解析

        在下面的实战代码中,我们首先定义了一个预处理宏VIDEO_PROCESSING_MODE,用于控制程序是打开一个视频文件还是打开默认摄像头。在主函数中,根据该宏的取值,程序尝试打开视频文件,或启动默认摄像头。如果无法打开视频文件或摄像头,程序会输出错误信息并终止。

        接下里,我们创建了一个名为"Video Processing"的窗口,并设置了窗口的大小。程序随后进入一个无限循环,在每次循环中读取一帧视频,并显示该帧。如果无法读取更多帧,则跳出循环。另外,程序还监听键盘输入,如果用户按下了'q'键,则退出循环。最后,我们释放了VideoCapture对象使用的资源,并销毁所有窗口。

#include <opencv2/opencv.hpp>
using namespace cv;

#include <iostream>
using namespace std;

#define VIDEO_PROCESSING_MODE           0

int main()
{
#if VIDEO_PROCESSING_MODE == 0
    // 打开视频文件
    VideoCapture cap("DigitalHuman.mp4");
    if (!cap.isOpened())
    {
        cout << "Can not open or find the video file" << endl;
        return -1;
    }
#else
    // 打开摄像头
    VideoCapture cap(0);
    if (!cap.isOpened())
    {
        cout << "Can not open or find the camera" << endl;
        return -1;
    }
#endif

    namedWindow("Video Processing", WINDOW_NORMAL);
    resizeWindow("Video Processing", 640, 360);

    Mat frame;
    // 获取视频的帧率
    int nFPS = (int)cap.get(CAP_PROP_FPS);
    while (true)
    {
        // 读取一帧
        if (!cap.read(frame))
        {
            // 如果无法读取更多帧,跳出循环
            break;
        }

        // 显示当前帧
        imshow("Video Processing", frame);

        // 按q键可以退出
        if (waitKey(1000 / nFPS) == 'q')
        {
            break;
        }
    }

    // 释放资源
    cap.release();
    destroyAllWindows();
    return 0;
}

        执行上面的代码,运行效果可参考下图。


原文地址:https://blog.csdn.net/hope_wisdom/article/details/142801196

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!