OpenCV入门教程(8)-视频文件的读取和存储
2017-01-16 23:52
751 查看
1 编解码器
视频的压缩算法称为编码器;那么,与之对应的解压缩算法就是解码器。想要了解详细的codec编解码器知识,可以参考FOURCC网站。
在了解编解码器之前,我们先来学习一个概念:FourCC。它的全称是Four Charactors Code,称为四字符码,是一种独立标示视频数据流格式。在FOURCC网站你可以得到完整的基于FourCC的各种各样的编解码器。
我们通过这个标识符,就可以寻找与 FourCC 代码相关联的视频解码器来播放特定的视频流。
FOURCC的定义如下:
一般用宏生成FOURCC,FOURCC是由4个字符拼接而成的,生成FOURCC的传统方法是:
这种方法的意思显而易见,我们可以使用下面一个模型进行操作:
因为宏能生成常量,符合case 的条件。
难道要退回古老的宏?当然不是,C++的模板机制给程序员带来的无限的空间,它不光能让类型作为参数,还能将常量作为参数(这一点常常被人遗忘),而且这一切都是编译期决定的!这是我们用它来生成FOURCC的第1个基础。
于是,我们迫不及待地利用模板来改写上面的函数:
可是错误照旧。虽然这次可以保证返回值能在编译期计算出来,但可惜的是那个return语句却要等到运行才能运行(也有可能在优化阶段就能消除这个语句,但肯定不能再编译期就全部完成)。
别急,还有第2个基础才可以。那是什么?是一个从C语言继承来的东西――enum。很多朋友认为,它不是很重要,因为很多情况下可以用别的方法来取代它,比如const。但是它有一个经常被人忽略的特性,而且这个特性非常重要,那就是――它的值必须在编译期就得出,即它是个编译期常量!这不是正符合我们的需要吗?请看下面的模板:
核心还是和上面一样,通过表达式(ch0 << 0) + (ch1 << 8) + (ch2 << 16) + (ch3 << 24)计算FOURCC(那当然是一样的)。但是计算的时机从运行期或者优化期移到了编译期。编译器在编译时,通过模板带入的char常量计算出表达式的值,并把它保存在枚举值value里。看看现在的代码:
成功了,MakeFOURCC模板顺利地完成了任务。FOURCC的模板生成法既让我们抛弃了那个不安全的宏,又让我们看到了inline的局限性,还让我们重新认识了enum的一些特性。其它许多类似的问题也能通过template + enum来解决。
OpenCV 2 中提供了两个类来实现视频的读写:读视频的类是 VideoCapture;写视频的类是 VideoWriter。
2 读视频
VideoCapture 既可以从视频文件读取图像,也可以从摄像头读取图像。可以使用该类的构造函数打开视频文件或者摄像头。如果 VideoCapture 对象已经创建,也可以使VideoCapture::open()打开,VideoCapture::open()函数会自动调用VideoCapture::release()函数,先释放已经打开的视频,然后再打开新视频。
如果要读一帧,可以使用 VideoCapture::read()函数。VideoCapture 类重载了>>操作符,实现了读视频帧的功能。下面的例程演示了使用 VideoCapture 类读视频。
下图是运行结果,打开视频和摄像头是一样的(下图是我本人的图像):
3 写视频
使用 OpenCV 创建视频也非常简单,与读视频不同的是,你需要在创建视频时设置一系列参数,包括:文件名,编解码器,帧率,宽度和高度等。编解码器使用四个字符表示,可以是CV_FOURCC(‘M’,’J’,’P’,’G’)、
CV_FOURCC(‘X’,’V’,’I’,’D’)及CV_FOURCC(‘D’,’I’,’V’,’X’)等。如果使用某种编解码器无法创建视频文件,请尝试其他的编解码器。
将图像写入视频可以使用 VideoWriter::write()函数,VideoWriter 类中也重载了<<操作符,使用起来非常方便。另外需要注意:待写入的图像尺寸必须与创建视频时指定的尺寸一致。
下面例程演示了如何写视频文件。本例程将生成一个视频文件,视频的第 0帧上是一个红色的“0”,第 1 帧上是个红色的“1”,以此类推,共 100 帧。生成视频的播放效果如下图所示。
下面是视频截图:
视频的压缩算法称为编码器;那么,与之对应的解压缩算法就是解码器。想要了解详细的codec编解码器知识,可以参考FOURCC网站。
在了解编解码器之前,我们先来学习一个概念:FourCC。它的全称是Four Charactors Code,称为四字符码,是一种独立标示视频数据流格式。在FOURCC网站你可以得到完整的基于FourCC的各种各样的编解码器。
我们通过这个标识符,就可以寻找与 FourCC 代码相关联的视频解码器来播放特定的视频流。
FOURCC的定义如下:
typedef unsigned int FOURCC;
一般用宏生成FOURCC,FOURCC是由4个字符拼接而成的,生成FOURCC的传统方法是:
#define MAKE_FOURCC(a,b,c,d) \ (((uint32_t)d) | (((uint32_t)c) << 8) | (((uint32_t)b) << 16) | (((uint32_t)a) << 24))
这种方法的意思显而易见,我们可以使用下面一个模型进行操作:
switch(val) { case MAKE_FOURCC('f','m','t',' '): ..... break; case MAKE_FOURCC('Y','4','4','2'): .... break; ... }
因为宏能生成常量,符合case 的条件。
难道要退回古老的宏?当然不是,C++的模板机制给程序员带来的无限的空间,它不光能让类型作为参数,还能将常量作为参数(这一点常常被人遗忘),而且这一切都是编译期决定的!这是我们用它来生成FOURCC的第1个基础。
于是,我们迫不及待地利用模板来改写上面的函数:
template <char ch0, char ch1, char ch2, char ch3>inline FOURCC MakeFOURCC() { return (ch0 << 0) + (ch1 << 8) + (ch2 << 16) + (ch3 << 24); }
可是错误照旧。虽然这次可以保证返回值能在编译期计算出来,但可惜的是那个return语句却要等到运行才能运行(也有可能在优化阶段就能消除这个语句,但肯定不能再编译期就全部完成)。
别急,还有第2个基础才可以。那是什么?是一个从C语言继承来的东西――enum。很多朋友认为,它不是很重要,因为很多情况下可以用别的方法来取代它,比如const。但是它有一个经常被人忽略的特性,而且这个特性非常重要,那就是――它的值必须在编译期就得出,即它是个编译期常量!这不是正符合我们的需要吗?请看下面的模板:
template <char ch0, char ch1, char ch2, char ch3> struct MakeFOURCC { enum { value = (ch0 << 0) + (ch1 << 8) + (ch2 << 16) + (ch3 << 24) }; };
核心还是和上面一样,通过表达式(ch0 << 0) + (ch1 << 8) + (ch2 << 16) + (ch3 << 24)计算FOURCC(那当然是一样的)。但是计算的时机从运行期或者优化期移到了编译期。编译器在编译时,通过模板带入的char常量计算出表达式的值,并把它保存在枚举值value里。看看现在的代码:
const FOURCC fccFMT = MakeFOURCC<'f', 'm', 't', ' '>::value; const FOURCC fccDATA = MakeFOURCC<'d', 'a', 't', 'a'>::value; switch (val) { case fccFMT: //... break; case fccDATA: //... break; }
成功了,MakeFOURCC模板顺利地完成了任务。FOURCC的模板生成法既让我们抛弃了那个不安全的宏,又让我们看到了inline的局限性,还让我们重新认识了enum的一些特性。其它许多类似的问题也能通过template + enum来解决。
OpenCV 2 中提供了两个类来实现视频的读写:读视频的类是 VideoCapture;写视频的类是 VideoWriter。
2 读视频
VideoCapture 既可以从视频文件读取图像,也可以从摄像头读取图像。可以使用该类的构造函数打开视频文件或者摄像头。如果 VideoCapture 对象已经创建,也可以使VideoCapture::open()打开,VideoCapture::open()函数会自动调用VideoCapture::release()函数,先释放已经打开的视频,然后再打开新视频。
如果要读一帧,可以使用 VideoCapture::read()函数。VideoCapture 类重载了>>操作符,实现了读视频帧的功能。下面的例程演示了使用 VideoCapture 类读视频。
#include <QCoreApplication> #include <iostream> #include "opencv2/opencv.hpp" using namespace std; using namespace cv; int main(void) { //打开第一个摄像头 VideoCapture cap(0); //打开视频文件 //VideoCapture cap("myvideo.avi"); //检查是否成功打开 if(!cap.isOpened()) { cerr << "Can not open a camera or file." << endl; return -1; } Mat edges; //创建窗口 namedWindow("edges",1); for(;;) { Mat frame; //从 cap 中读一帧,存到 frame cap >> frame; //如果未读到图像 if(frame.empty()) break; //将读到的图像转为灰度图 cvtColor(frame, edges, CV_BGR2GRAY); //进行边缘提取操作 Canny(edges, edges, 0, 30, 3); //显示结果 imshow("edges", edges); //等待 30 秒,如果按键则推出循环 if(waitKey(30) >= 0) break; } //退出时会自动释放 cap 中占用资源 return 0; }
下图是运行结果,打开视频和摄像头是一样的(下图是我本人的图像):
3 写视频
使用 OpenCV 创建视频也非常简单,与读视频不同的是,你需要在创建视频时设置一系列参数,包括:文件名,编解码器,帧率,宽度和高度等。编解码器使用四个字符表示,可以是CV_FOURCC(‘M’,’J’,’P’,’G’)、
CV_FOURCC(‘X’,’V’,’I’,’D’)及CV_FOURCC(‘D’,’I’,’V’,’X’)等。如果使用某种编解码器无法创建视频文件,请尝试其他的编解码器。
将图像写入视频可以使用 VideoWriter::write()函数,VideoWriter 类中也重载了<<操作符,使用起来非常方便。另外需要注意:待写入的图像尺寸必须与创建视频时指定的尺寸一致。
下面例程演示了如何写视频文件。本例程将生成一个视频文件,视频的第 0帧上是一个红色的“0”,第 1 帧上是个红色的“1”,以此类推,共 100 帧。生成视频的播放效果如下图所示。
#include <stdio.h> #include <iostream> #include "opencv2/opencv.hpp" using namespace std; using namespace cv; // 25帧/s #define FRM_PER_SEC (25) int main(void) { //定义视频的宽度和高度 Size s(320, 240); //创建 writer,并指定 FOURCC 及 FPS 等参数 VideoWriter writer = VideoWriter("myvideo.avi",CV_FOURCC('M','J','P','G'), FRM_PER_SEC, s); //检查是否成功创建 if(!writer.isOpened()) { cerr << "Can not create video file.\n" << endl; return -1; } //视频帧 Mat frame(s, CV_8UC3); for(int i = 0; i < 100; i++) { //将图像置为黑色 frame = Scalar::all(0); //将整数 i 转为 i 字符串类型 char text[128]; snprintf(text, sizeof(text), "%d", i); //将数字绘到画面上 putText(frame, text, Point(s.width/3, s.height/3), FONT_HERSHEY_SCRIPT_SIMPLEX, 3,Scalar(0,0,255), 3, 8); //将图像写入视频 writer << frame; } //退出程序时会自动关闭视频文件 return 0; }
下面是视频截图:
相关文章推荐
- OpenCV入门教程(7)-图像文件的读取和存储
- OpenCV入门系列(7):读取摄像头,保存为视频文件
- opencv之视频读取与文件存储
- 如何解决opencv读取avi视频文件一闪而过
- 读取视频文件存盘(学习openCV课后题2.3)
- opencv读取摄像头图像和读取视频文件图像
- OpenCV笔记3:视频文件的读取与保存
- OpenCV学习笔记(4)视频文件的读取与保存
- Opencv(四):读取视频文件和摄像头
- OpenCV学习笔记(4)视频文件的读取与保存(2010-01-23 更新)
- AVI编码方式及OpenCV读取AVI文件-解决opencv无法读AVI视频的问题
- 基于OpenCV+MFC的AVI视频文件读取及运动检测
- centos下opencv无法读取视频文件
- OpenCV_读取文件夹下的图片生成视频文件
- vs2005入门 .Net2.0视频教程 之 浅尝存储过程[视频]
- vs2005入门 .Net2.0视频教程 之 创建读取文本文件[视频]
- 如何解决opencv读取avi视频文件一闪而过
- opencv支持多种流行视频格式文件的读取
- [转载][教程]vs2005入门 之 文件上传控件(FileUpLoad)[视频]
- 韩顺平_php从入门到精通_视频教程_第2讲_html运行原理②_html文件基本结构_html元素和属性_学习笔记_源代码图解_PPT文档整理