OpenCV视频篇——VideoCapture类和VideoWriter类


前面已经提到过一部分的视频读写:OpenCV--012:视频读写

\color{#74d}{一、OpenCV视频I/O概述}

来自:OpenCV视频I/O概述

OpenCV视频I/O模块是一组用于读取和写入视频或图像序列的类和功能。

基本上,该模块将cv :: VideoCapture和cv :: VideoWriter类作为2层接口提供给许多用作后端的视频I / O API。


在这里插入图片描述
  • 某些后端,例如(DSHOW)Direct Show,Windows视频(VFW),Microsoft Media Foundation(MSMF),Video 4 Linux(V4L)等,是操作系统提供的视频I / O库的接口。
  • 其他一些后端,例如用于Kinect的OpenNI2,英特尔感知计算SDK,GStreamer,XIMEA相机API等,都是专有驱动程序或外部库的接口。

notice:
每个后端以不同的方式支持设备属性(cv::VideoCaptureProperties),或者可能根本不支持任何属性。

运行时选择后端:
OpenCV运行时自动选择并使用第一个可用的后端(apiPreference=cv::CAP_ANY);

用于可以根据需要,选择要运行的后端。
例如:

  1. 使用Dirtect Show作为后端从默认摄像头抓取:
    //声明一个捕获对象
    cv :: VideoCapture cap(0 + cv :: CAP_DSHOW);
    //或使用open指定apiPreference
    cap.open(0 + cv :: CAP_DSHOW);
    
  2. 如果要使用Direct Show作为后端从文件中抓取:
    //声明一个捕获对象
    cv :: VideoCapture cap(filename,cv :: CAP_DSHOW);
    //或使用open指定apiPreference
    cap.open(文件名,cv :: CAP_DSHOW);
    

使用第三方驱动程序或照相机:
许多工业相机或者某些视频I/O设备不提供操作系统的标准驱动程序接口。因此,不能再这些设备上直接使用VideoCapture或者VideoWriter。为了访问他们的设备,制造商提供了自己的C++ API和库。

FFmpeg库:
OpenCV可以使用FFmpeg库作为后端来记录,转换和流式传输音频和视频。FFMpeg是完整的交叉引用解决方案。如果在配置OpenCV时启用FFmpeg,则CMake将下载二进制文件并将其安装在OPENCV_SOURCE_CODE/3rdparty/ffmpeg/中。要在运行时使用FFMpeg,必须将FFMepg二进制文件与应用程序一起部署。

\color{#74d}{二、VideoCapture结构体}

VideoCapture结构体,可以读取文件视频、网页视频流和摄像头的数据。

❶先看一下构造函数:
  • 1、默认构造函数:
VideoCapture() 
  • 2、使用API首选项打开视频文件或捕获设备或IP视频流以进行视频捕获。
VideoCapture (const String &filename, int apiPreference=CAP_ANY)

\color{red}{filename可选值}

  • 影片档案名称(例如video.avi)
  • 图片序列(例如img_%02d.jpg,将读取像这样的样本img_00.jpg, img_01.jpg, img_02.jpg, ...)
  • 视频流的网址(例如protocol://host:port/script_name?script_params|auth)。请注意,每个视频流或IP摄像机源均具有其自己的URL方案。请参考源流的文档以了解正确的URL。

    \color{red}{apiPreference:}
    首选使用的Capture API后端。如果有多个可用的读取器实现,则可以用于实施特定的读取器实现。
    设置读取的摄像头编号,默认CAP_ANY=0,自动检测摄像头。多个摄像头时,使用索引0,1,2,...进行编号调用摄像头。 apiPreference = -1时单独出现窗口,选取相应编号摄像头。
  • 3、打开相机进行视频拍摄。
VideoCapture (int index, int apiPreference=CAP_ANY)

\color{red}{index参数:}
要打开的视频捕获设备的ID。要使用默认后端打开默认摄像头,只需传递0。
——> 当apiPreference为CAP_ANY时,使用camera_id + domain_offset(CAP_ *)向后兼容有效
\color{red}{apiPreference:}
首选使用的Capture API后端。如果有多个可用的读取器实现,则可用于实施特定的读取器实现:例如cv :: CAP_DSHOW或cv :: CAP_MSMF或cv :: CAP_V4L。

\color{blue}{通常使用 `bool isOpened()`判断是否打开视频或摄像头成功。}

VideoCaptureAPIs的取值:OpenCV视频篇——VideoCaptureAPIs

❷ VideoCapture中其他函数
  • 1、返回特殊的VIdeoCApture属性信息。
virtual double  get (int propId) const

\color{red}{propId:}
来自cv :: VideoCaptureProperties的属性标识符(例如cv :: CAP_PROP_POS_MSEC,cv :: CAP_PROP_POS_FRAMES,...)或视频I / O API后端的附加标志中的一个。

指定属性的值。查询VideoCapture实例使用的后端不支持的属性时,返回值0 。

读/写属性涉及许多层。在此链上可能会发生一些意外的结果。
VideoCapture- > API 后端 ->操作系统->设备驱动程序->设备硬件
返回的值可能与设备实际使用的值不同,或者可以使用设备相关的规则(例如,步骤或百分比)对其进行编码。有效行为取决于设备驱动程序和API后端。

VideoCaptureProperties的取值:OpenCV视频篇——VideoCaptureProperties

  • 2、在VideoCapture中设置属性。
virtual bool cv::VideoCapture::set(int propId, double   value ) 

\color{red}{ propId:}
来自cv :: VideoCaptureProperties的属性标识符(例如cv :: CAP_PROP_POS_MSEC,cv :: CAP_PROP_POS_FRAMES,...)或视频I / O API后端的附加标志中的一个
\color{red}{value:}
属性的值。
\color{red}{返回值:}
如果该属性由VideoCapture实例使用的后端支持,则返回true。

\color{blue}{即使返回true,也不能确保捕获设备已接受该属性值。}

  • 3、返回使用的后端API名称。
String  getBackendName () const

流应先打开。

  • 4、从视频文件或捕获设备中获取下一帧。
virtual bool    grab ()

该方法/函数从视频文件或摄像机中获取下一帧,并在成功的情况下返回true(非零)。

该功能的主要用途是在多相机环境中,尤其是在相机没有硬件同步的情况下。也就是说,您为每个摄像机调用VideoCapture :: grab(),然后调用较慢的方法VideoCapture :: retrieve()解码并从每个摄像机获取帧。这样,消除了去马赛克或运动jpeg压缩等方面的开销,并且从不同摄像机检索到的帧将在时间上更近。

\color{red}{返回:}
true (非零)(如果成功)。

另外,当连接的摄像机是多头摄像机(例如,立体摄像机或Kinect设备)时,从中检索数据的正确方法是先调用VideoCapture :: grab(),然后再调用VideoCapture :: retrieve()使用不同的channel参数值一次或多次。

  • 5、如果视频捕获已经初始化,则返回true。
virtual bool    isOpened () const

\color{blue}{如果先前对VideoCapture构造函数或VideoCapture :: open()调用成功,则该方法返回true。}

  • 6、打开视频文件或捕获设备或IP视频流以进行视频捕获。
virtual bool    open (const String &filename, int apiPreference=CAP_ANY)
 
virtual bool    open (int index, int apiPreference=CAP_ANY)

参数与构造函数VideoCapture相同,此处不再重复。

\color{red}{返回:}
true:如果文件已成功打开

\color{blue}{该方法首先调用VideoCapture :: release以关闭已打开的文件或摄像机。}

  • 7、抓取,解码并返回下一个视频帧。
virtual bool    read (OutputArray image)

该方法/函数在一次调用中将VideoCapture :: grab()和VideoCapture :: retrieve()组合在一起。这是读取视频文件或从解码捕获数据并返回刚抓取的帧的最方便的方法。如果没有抓取任何帧(相机已断开连接,或者视频文件中没有其他帧),则该方法返回false,并且该函数返回空图像(使用cv :: Mat,使用Mat :: empty()进行测试) 。

\color{red}{image:}
视频帧将返回此处。如果没有抓取帧,image将为空。
\color{red}{返回:}
false:如果没有抓取帧

  • 8、关闭视频文件或捕获设备。
virtual void    release ()

该方法由随后的VideoCapture :: open和VideoCapture析构函数自动调用。

\color{blue}{C函数还会取消分配内存并清除* capture指针。}

  • 9、解码并返回抓取的视频帧。
virtual bool    retrieve (OutputArray image, int flag=0)

该方法解码并返回刚抓取的帧。如果没有抓取任何帧(摄像机已断开连接,或者视频文件中没有其他帧),则该方法返回false,并且该函数返回空图像(使用cv :: Mat,使用Mat :: empty()测试它)。

\color{red}{image:}
视频帧将返回此处。如果没有抓取帧,image将为空。
\color{red}{flag:}
它可以是帧索引或驱动程序特定标志。
\color{red}{返回值:}
false 如果没有抓取帧。

  • 10、流运算符读取下一个视频帧。
virtual VideoCapture &  operator>> (Mat &image)
 
virtual VideoCapture &  operator>> (UMat &image)
❸读取视频基本步骤
1、读取视频

一般采用构造函数进行视频或者摄像头的预处理。

2、下一帧

读取下一帧:

  • 使用重载运算符>>
  • 使用read 、grab 、retrieve函数

视频帧读取的方式:

读取方式 使用方式
cap.read(frame) 结合grab和retrieve的功能,抓取下一帧并解码
cap.grap() 从设备或视频获取下一帧,获取成功返回true否则false
cap.retrieve(frame) 在grab后使用,对获取到的帧进行解码,也返回true或false

\color{blue}{retrieve速度比grab慢很多,有时可以通过grab跳过不需要的帧,而不需要用read解码每一帧。}

3、释放

release()在使用完后进行手动释放VideoCapture对象。

int main(int, char**)
{
    Mat frame;
    //--- INITIALIZE VIDEOCAPTURE
    VideoCapture cap;
    // open the default camera using default API
    // cap.open(0);
    // OR advance usage: select any API backend
    int deviceID = 0;             // 0 = open default camera
    int apiID = cv::CAP_ANY;      // 0 = autodetect default API
    // open selected camera using selected API
    cap.open(deviceID + apiID);
    // check if we succeeded
    if (!cap.isOpened()) {
        cerr << "ERROR! Unable to open camera\n";
        return -1;
    }
    //--- GRAB AND WRITE LOOP
    cout << "Start grabbing" << endl
        << "Press any key to terminate" << endl;
    for (;;)
    {
        // wait for a new frame from camera and store it into 'frame'
        cap.read(frame);
        // check if we succeeded
        if (frame.empty()) {
            cerr << "ERROR! blank frame grabbed\n";
            break;
        }
        // show live and wait for a key with timeout long enough to show images
        imshow("Live", frame);
        if (waitKey(5) >= 0)
            break;
    }
    // the camera will be deinitialized automatically in VideoCapture destructor
    return 0;
}

\color{#74d}{ 三、VideoWriter类}

❶构造函数

  • 1、默认构造函数:
VideoWriter ()
  • 2、构造函数
VideoWriter (const String &filename, int fourcc, double fps, Size frameSize, bool isColor=true)

\color{red}{filename:}
输出视频文件的名称。
\color{red}{fourcc:}
用于压缩帧的编解码器的4个字符的代码。
例如:
VideoWriter :: fourcc('P','I','M','1')是MPEG-1编解码器;
VideoWriter :: fourcc('M','J','P','G ')是动态jpeg编解码器等。
可以在FOURCC页面的“ 视频编解码器”中获取代码列表。带有MP4容器的FFMPEG后端本机使用其他值作为fourcc代码:请参见ObjectType,因此您可能会从OpenCV收到有关fourcc代码转换的警告消息。
\color{red}{fps:}
创建的视频流的帧率。
\color{red}{frameSize:}
视频帧的大小。
\color{red}{isColor:}
如果它不为零,则编码器将期望并编码彩色帧,否则它将与灰度帧一起使用(仅Windows当前支持该标志)。

  • 3、构造函数
VideoWriter (const String &filename, int apiPreference, int fourcc, double fps, Size frameSize, bool isColor=true)

❷ 成员函数

  • 1、返回指定的VideoWriter属性
virtual double  get (int propId) const

\color{red}{propId:}
来自cv :: VideoWriterProperties的属性标识符或视频I / O API后端的其他标志之一。
\color{red}{返回值:}
指定属性的值。查询VideoWriter实例使用的后端不支持的属性时,返回值0 。

  • 2、 在VideoWriter中设置属性。
virtual bool    set (int propId, double value)

\color{red}{propId:}
来自cv :: VideoWriterProperties的属性标识符或视频I / O API后端的其他标志之一。
\color{red}{value:}
属性的值。

\color{red}{返回值:}
true:如果该属性由VideoWriter实例使用的后端支持。

  • 3、 返回使用的后端API名称。。
String  getBackendName () const

注意:流应打开。

  • 4、 如果视频编写器已成功初始化,则返回true。
virtual bool    isOpened () const
  • 5、 初始化或重新初始化视频编写器。
virtual bool open(const String &filename,int fourcc, double fps,Size frameSize,bool isColor=true)

bool open (const String &filename, int apiPreference, int fourcc, double fps, Size frameSize, bool isColor=true)

参数与构造函数VideoWriter :: VideoWriter中的参数相同。

\color{red}{返回值:}
true:视频编写器是否已成功初始化

\color{blue}{该方法首先调用VideoWriter :: release以关闭已打开的文件。}

  • 6.1、 流运算符写入下一个视频帧。
virtual VideoWriter &operator<<(const Mat &image)
virtual VideoWriter &operator<<(const UMat &image)
  • 6.2、 写入下一个视频帧。
virtual void    write (InputArray image)

该功能/方法将指定的图像写入视频文件。它的大小必须与打开视频编写器时指定的大小相同。

\color{red}{image:}
待写的帧。通常,彩色图像应采用BGR格式。

  • 7、 关闭视频编写器。
virtual void    release ()

此方法由随后的VideoWriter :: open和VideoWriter析构函数自动调用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342