使用OpenCV的VideoCapture播放视频文件示例

OpenCV计算机视觉开发实践:基于Qt C++ - 商品搜索 - 京东

构造VideoCapture对象

类VideoCapture既支持从视频文件(.avi 、*.mp4、.mpg等格式)读取,也支持直接从摄像机(比如计算机自带的摄像头)中读取。要想获取视频,需要先创建一个VideoCapture对象。VideoCapture对象的创建方式有以下3种:

(1)从视频文件中读取视频。如果是从文件(.mpg或.avi格式)中读取视频,则在定义对象的时候,可以把视频文件的路径作为参数传给构造函数。对象创建以后,OpenCV将会打开该视频文件并做好准备读取它,并且VideoCapture提供了成员函数isOpened来判断文件是否打开成功,如果成功将返回true(建议在打开视频或摄像头时都使用该成员函数判断是否打开成功)。用于读取视频文件的构造函数如下:

VideoCapture (const String &filename, int apiPreference=CAP_ANY);

其中参数filename是视频文件的文件名(可以包含路径),如果不包含路径,则在当前路径下打开文件; apiPreference表示首选使用的后端捕获API,默认是使用任意捕获API,用宏CAP_ANY来表示。比如我们定义一个VideoCapture对象并打开D盘上的test.avi文件:

cv::VideoCapture capture("D:/test.avi");  // 从视频文件读取

(2)从摄像机中读取视频。如果是从摄像机中读取视频,这种情况下,构造函数会给出一个整型索引参数,用于表示想要访问的摄像机。对于摄像机而言,这个索引参数就是一个标志数字,如果只有1个摄像机,那么索引参数就是0;如果系统中有多个摄像机,那么只要将其值向上增加即可。读取摄像头中的视频的构造函数如下:

VideoCapture (int index, int apiPreference=CAP_ANY);

其中参数index表示要打开的视频捕获设备(摄像头)的ID,如果使用默认后端的默认摄像头,只需传递0;apiPreference表示首选使用的后端捕获API,默认是使用任意捕获API,用宏CAP_ANY来表示,多数情况下,由于我们只有一个摄像机,因此没必要指定摄像机的域,此时使用cv::CAP_ANY是一种高效的方式。参数apiPreference表示摄像机的类型,这个域值可以是下面任意一个预定义常量:

CAP_ANY:自动选择API

CAP_DSHOW:通过视频输入,例如,摄像头输入

CAP_FFMPEG:使用FFMPEG库

CAP_IMAGES:打开一个图像序列(例如,img_%02d.jpg)

(3)不带参数构造一个VideoCapture对象。使用类VideoCapture的不带参数的构造函数来创建一个VideoCapture对象,然后用成员函数open打开一个视频文件或摄像头。open函数声明如下:

virtual bool open (const String &filename, int apiPreference=CAP_ANY);

virtual bool open (int index, int apiPreference=CAP_ANY);

两个open函数的参数和前面两个构造函数的参数含义一样,这里不再赘述。

判断视频是否打开成功

当我们打开一个视频文件或摄像头视频后,可以用成员函数isOpened来判断是否打开成功。该函数声明如下:

virtual bool isOpened() const;

若打开成功,则返回true,否则返回false。

比如:

VideoCapture capture;

capture.open(0, CAP_DSHOW);    // 打开摄像头

    if (!capture.isOpened())    // 判断打开是否成功

        puts("open failed");

12.5  读取视频帧

要播放视频,肯定要把每一帧视频图像都读出来,然后显示出来。读取方式有两种,一种是用运算符>>,直接输出视频帧到Mat对象中。>>是一个重载运算符,定义如下:

virtual VideoCapture& operator >> (CV_OUT Mat& image);

例如:

Mat frame;

VideoCapture capture("test.mp4");

while (1) {

    capture >> frame;           // 输出一帧到Mat对象中

    if (frame.empty()) {       // 播放完就退出

        printf("播放完成\n");

        break;

    }

    imshow("读取视频", frame);   // 显示帧

    waitKey(20);

}

当输出完一帧后,下次就会输出下一帧。

另外一种方式是通过成员函数read,该函数声明如下:

virtual bool read(OutputArray image);

参数image用来存放读取到的当前视频帧。若读取成功,则返回true,否则返回false。例如:

Mat frame;

VideoCapture capture(0, CAP_DSHOW);

while (capture.read(frame))

{

    imshow("video-demo", frame);

    char c = waitKey(66);

    if (c == 27)  break;

}

播放视频文件

播放视频文件的基本步骤就是先构造VideoCapture对象,再打开视频文件,接着用一个循环逐帧读取并显示读取到的视频帧,然后间隔一段时间读取下一个视频帧并显示,依次循环,直到全部视频帧读取完毕。

【例12.1】播放MP4视频文件

   新建一个控制台工程,工程名是conplay。

   打开main.cpp,并输入如下代码:

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

void play(const char *filename)
{
    Mat frame;
    int i=0;
    VideoCapture capture(filename);
    if (!capture.isOpened())
    {
        printf("open %s failed",filename);
        return;
    }
    // 获取整个视频帧数
    long  totalFrameNumber = capture.get(CAP_PROP_FRAME_COUNT);
    qDebug()<<"整个视频帧数:"<<totalFrameNumber;
    while (i<totalFrameNumber) {
        capture >> frame;
        if (frame.empty()) break; 	// 播放结束就跳出循环
        imshow("read video", frame);	// 显示帧
         waitKey(1);
        i++;
    }
     qDebug()<<"播放完成\n";
}
int main() {
    play("/root/hd.mp4");
}

在上述代码中,我们首先定义了一个VideoCapture对象capture,并传入视频文件的文件名;然后利用成员函数get获取视频的帧数,这样在后面的while循环中可以控制播放的帧数。当frame为空时,说明视频帧没有了,也就是播放完毕了,此时跳出循环。每一帧其实就是一幅图片,可以用imshow函数把图片显示出来。当显示速度很快时,多个图片连续显示,看起来就是视频了。这里我们设置每个帧的显示间隔时间是1毫秒。

   保存工程并运行,结果如图12-2所示。

图12-2

播放摄像头视频的主要流程与之类似,只不过在调用open的时候,需要修改一下传入的整型数据。读者可以准备一个USB接口的计算机摄像头,然后把USB口插入计算机的USB插槽中,通常是不需要安装驱动程序的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值