OpenCV 从文件或相机播放视频

1,049 阅读4分钟

OpenCV 无法像 FFmepg 库一样,可以播放视频的声音,并且它显示视频的方式也是从视频文件提取图像帧显示到窗口上。来看例子:

播放视频文件

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, const char * argv[]) {
   
    // 打开视频文件.
    VideoCapture cap("/Users/xxx/Pictures/chengdu.mp4");
    
    if (!cap.isOpened()) {
        cout << "视频打开失败" << endl;
        cin.get();
        return -1;
    }
    
    // VideoCapture 属性设置
    //cap.set(CAP_PROP_POS_MSEC, 5000);
    
    // 获取视频帧率
    double fps = cap.get(CAP_PROP_FPS);
    cout << "帧率: " << fps << endl;
    
    String window_name = "Video Frame";
    namedWindow(window_name);
    
    while (true) {
        // 视频帧图像
        Mat frame;
        bool ret = cap.read(frame);
        if (!ret)
        {
            cout << "视频播放完成." << endl;
            break;
        }
        
        // 显示视频帧图像.
        imshow(window_name, frame);
        
        if (waitKey(10) == 27)
        {
            cout << "按下 ESC 键停止播放." << endl;
            break;
        }
    }
    
    return 0;
}

你只需要将上面的视频路径更改为你的播放路径,将会看到如下的效果。

代码解释

  1. 头文件导入

使用 OpenCV 时必须导入,命名空间是为了更方便的使用 OpenCV 提供的类

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;
  1. VideoCapture cap("/Users/xxx/Pictures/chengdu.mp4");

初始化 VideoCapture, 读取指定路径的视频文件。在它的析构函数中会释放打开视频文件的内存,无需显示释放内存。

  1. cap.isOpened()
if (!cap.isOpened()) {
    cout << "视频打开失败" << endl;
    cin.get();
    return -1;
}

当 VideoCapture 创建成功后,isOpened() 返回 true, 否则返回 false。

  1. cap.set(CAP_PROP_POS_MSEC, 5000)

VideoCapture 属性设置,设置成功会返回 true, 否则返回 false, 它有两个参数:

propID: VideoCapture 属性,有两个常量使用

  • CAP_PROP_POS_MSEC: 设置视频播放位置,单位为毫秒,例如: 100ms
  • CAP_PROP_POS_FRAMES: 视频播放帧相对于起始帧0, 例如: 1、2、3,...
  1. double fps = cap.get(CAP_PROP_FPS);

获取当前视频的帧率,如果不支持属性将会返回 0

propld: VideoCapture 属性,有如下常用的几个属性

  • CAP_PROP_POS_MSEC: 获取当前播放了多少毫秒
  • CAP_PROP_POS_FRAMES: 获取当前播放的视频帧,相对起始帧 0
  • CAP_PROP_FRAME_WIDTH: 获取视频帧的宽
  • CAP_PROP_FRAME_HEIGHT: 获取视频帧的高
  • CAP_PROP_FPS: 获取视频帧率
  • CAP_PROP_FOURCC: 编码器字符编码
  • CAP_PROP_FRAME_COUNT: 视频总帧数
  1. namedWindow(window_name);
void namedWindow(const String& winname, int flags = WINDOW_AUTOSIZE);

函数创建一个窗口,用作图像和图像的占位符,创建的窗口由其名称引用。

1. winname: 窗口名称,标示一个窗口
2. flags: 决定窗口的大小,在上面的例子中采用默认的方式,即为图像的尺寸。保存在枚举常量 cv::WindowFlags 中
  * WINDOW_AUTOSIZE: 用户不能调整窗口大小
  * WINDOW_NORMAL: 用户可以调整窗口大小
  ...
  1. bool ret = cap.read(frame);

读取视频帧保存到 frame 中, 读取完毕返回 false

  1. imshow(window_name, frame);
void imshow(const String& winname, InputArray mat);

在指定窗口中显示图像,如果窗口是用 WINDOW_AUTOSIZE 标志创建的,图像以原始大小显示,否则图像会根据窗口大小进行缩放显示。如果未通过 namedWindow() 函数创建窗口,imshow 函数会默认创建 WINDOW_AUTOSIZE 标志的窗口。

此函数调用之后应加上 waitKey(int) 函数调用,以便为指定的连续时间(以毫秒为单位)提供足够的时间在窗口中绘制和显示图像。如果不调用 waitKey(int) 函数, 图像不会显示在窗口中。

1. winname: 窗口名称,通过 namedWindow() 函数创建
2. mat: 图像的 Mat 对象
  1. waitKey(10) == 27

等待 10 毫秒,如果没有 ESC 按下,则继续播放下一帧,知道播放完。

从相机获取图像播放

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, const char * argv[]) {
    
    // 打开后置摄像头,捕捉视频帧.
    VideoCapture cap(0);
    
    if (!cap.isOpened())
    {
        cout << "打开相机失败." << endl;
        cin.get();
        return -1;
    }
    
    double width = cap.get(CAP_PROP_FRAME_WIDTH);
    double height = cap.get(CAP_PROP_FRAME_HEIGHT);
    cout << "视频帧分辨率: " << width << " x " << height << endl;
    
    while (true) {
        Mat frame;
        bool ret = cap.read(frame);
        if (!ret)
        {
            cout << "相机断开." << endl;
            cin.get();
            break;
        }
        
        imshow("My Camera Feed", frame);
        
        if (waitKey(10) == 27)
        {
            cout << "按下 ESC 停止播放视频." << endl;
            break;
        }
    }
   
    return 0;
}

代码解释:

  1. VideoCapture cap(0);

打开后置摄像头,传递的参数为 0 将打开默认的摄像头( 默认后置摄像头),可根据计算机设备的相机数来调整这个索引。

  1. double width = cap.get(CAP_PROP_FRAME_WIDTH); double height = cap.get(CAP_PROP_FRAME_HEIGHT);

获取相机捕捉图像的分辨率,即宽 * 高