OpenCV入门教程(8)-视频文件的读取和存储
来源:互联网 发布:自制mac安装盘 编辑:程序博客网 时间:2024/06/07 01:33
1 编解码器
视频的压缩算法称为编码器;那么,与之对应的解压缩算法就是解码器。想要了解详细的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入门教程(8)-视频文件的读取和存储
- OpenCV入门教程(7)-图像文件的读取和存储
- OpenCV学习(二)读取视频文件和摄像头
- Opencv(四):读取视频文件和摄像头
- 读取视频文件(基于OpenCV 的C++程序)
- OpenCV学习笔记(4)视频文件的读取与保存
- opencv学习笔记(2)视频文件的读取与保存
- 数据库读取和存储大型数据(图片、音视频文件)的函数封装
- OpenCV自学笔记8:读取视频文件
- OpenCV读取视频文件方法
- OpenCV读取视频文件
- opencv读取摄像头图像和读取视频文件图像
- OpenCV学习笔记-读取视频文件
- opencv学习心得四----读取视频文件
- opencv读取图片,视频文件,摄像头
- opencv 读取、修改、保存视频文件
- opencv读取摄像头或视频文件
- OpenCV学习笔记(4)视频文件的读取与保存(2010-01-23 更新)
- __int64
- LeetCode - 122. Best Time to Buy and Sell Stock II - 思路详解 - C++
- UVALive4886 E - Page Count 模拟
- 第1章 python-环境的搭建
- Java 反射
- OpenCV入门教程(8)-视频文件的读取和存储
- opencv学习(二十五)之开运算、闭运算、形态梯度、顶帽、黑帽
- php+二维码图片生成封装成对象类
- network_questions
- leetcode-404-Sum of Left Leaves
- android.support.v7.app.AlertDialog 使用报错
- 帮你理解学习lambda式
- http://www.cnblogs.com/GnagWang/archive/2011/03/31/2001067.html
- Windows和Linux下安装JDK