视频文件的结构:
每一个视频文件本质上都是一个容器,文件的扩展名只是表示容器格式(例如 avi , mov ,或者 mkv )而不是视频和音频的压缩格式。
容器里可能会有很多元素,例如视频流,音频流和一些字幕流等等。这些流的储存方式是由每一个流对应的编解码器(codec)决定的。通常来说,音频流很可能使用 mp3 或 aac 格式来储存。而视频格式就更多些,通常是 XVID , DIVX , H264 或 LAGS (Lagarith Lossless Codec)等等。
视频文件比图像文件要复杂很多。然而OpenCV只是个计算机视觉库而不是一个视频处理编码库。所以开发者们试图将这个部分尽可能地精简,结果就是OpenCV能够处理的视频只剩下 avi 扩展名的了。
另外一个限制就是不能创建超过2GB的单个视频,还有就是每个文件里只能支持一个视频流,不能将音频流和字幕流等其他数据放在里面。
关于视频编解码器:
编码解码器的主要作用是对视频信号进行压缩和解压缩。计算机工业定义通过24位测量系统的真彩色,这就定义了百万种颜色,接近人类视觉的极限。现在,最基本的VGA显示器就有640×480像素。这意味着如果视频需要以每秒30帧的速度播放,则每秒要传输高达27MB的信息。在如此速度下,1GB容量的硬盘仅能存储约37秒的视频信息。因而必须对信息进行压缩处理。通过抛弃一些数字信息或精选出容易被我们的眼睛和大脑常忽略的可视化信息的方法,使视频消耗的硬盘容量减小。这个视频压缩过程就是编码解码器。编码解码器的压缩率从一般的2:1~100:1不等,使处理大量的视频数据成为可能。
如果是用在数字多媒体上,解码器则包括视频解码器和音频解码器.数字媒体的图象和声音都使用特殊的软件编码格式,像视频的mpeg4,音频的mp3,ac3,dts等,这些编码器可以将原始数据压缩存放,刚才都是常用的编码格式,还有些专业的编码格式,一般家庭基本不会用到。为了在家用设备或者电脑上重放这些视频和音频则需要用到解码软件,一般称为插件。比如mpeg4解码插件ffdshow,ac3解码插件ac3fliter等。只有装了各种解码插件你的电脑才能重放这些图像和声音。
用OpenCv创建视频:
1.其操作在 VideoWriter 类中,open 函数来打开, write 函数向这个对象按照序列发送一些图像帧。
2.下面的程序代码做的工作主要有这几样:
(1):创建一个视频文件
(2):获取视频的解码器
编解码器,现在所有的视频编解码器都使用最多四个字节的名称来标识,例如 XVID, DIVX, 和 H264 等。这个被称作FourCC(four character code)。你可以通过 get 函数来向视频询问这个编码, get 函数会返回一个double数,仅仅是因为double包含了64位数据而已,由于FourCC编码只占据了其中低位的4个字节,所以可以直接通过强制转换成int型来扔掉高位的四个字节。详细代码见下面的程序。
(3): 释放视频文件当中的某个颜色通道
程序代码,详细注释在代码中:
// 055 用OpenCv创建视频.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream> // for standard I/O
#include <string> // for strings
#include <opencv2/core/core.hpp> // Basic OpenCV structures (cv::Mat)
#include <opencv2/highgui/highgui.hpp> // Video write
using namespace std;
using namespace cv;
int main(int argc, char *argv[], char *window_name)
{
//读取视频
const string source="Megamind.avi";
VideoCapture inputVideo(source);
//判断是否读取成功
if ( !inputVideo.isOpened())
{
cout << "Could not open the input video." << endl;
return -1;
}
//// 查找最后出现的字符 '.'的位置,pAT值为8
//size_type 由string类类型和vector类类型定义的类型,用以保存任意string对象或vector对象的长度,本质上来说,是一个整型数
string::size_type pAt = source.find_last_of('.');
//新视频文件的名字
char channelNum;
cout<<"Please input the number of channel you want to release(R,G,B): ";
cin>>channelNum;
const string NAME = source.substr(0, pAt) +channelNum + ".avi"; // Form the new name with container
//得到编码器的int表达式, 编码器的名称如XVID, DIVX, 和 H264,保存在整型的后四个字节
int ex = static_cast<int>(inputVideo.get(CV_CAP_PROP_FOURCC)); // Get Codec Type- Int form
//int型ex,取出后四个字节代表的字符即编码器的名称
//ex & 0XFF是将ex用二进制表示,与0XFF与,求出ex低八位所表示的整数,转成char型即对应的ASCII码
char EXT[] = {ex & 0XFF , (ex & 0XFF00) >> 8,(ex & 0XFF0000) >> 16,(ex & 0XFF000000) >> 24,0};
//得到输入视频的尺寸
Size S = Size((int) inputVideo.get(CV_CAP_PROP_FRAME_WIDTH), //Acquire input size
(int) inputVideo.get(CV_CAP_PROP_FRAME_HEIGHT));
//输入选择
char choice;
cout<<"Please input yes 'Y' or no 'N'(N:使用视频输入格式来创建输出文件,Y:弹出一个对话框来让你选择编码器。):"<<endl;
cin>>choice;
const bool askOutputType=choice=='Y';
//开始用VideoWriter 类的对象创建视频
VideoWriter outputVideo; // Open the output
//'Y'表示自己选择编码器创建视频,ex=-1.帧数,尺寸均一样。true表示视频为彩色。
if (askOutputType)
outputVideo.open(NAME , ex=-1, inputVideo.get(CV_CAP_PROP_FPS),S, true);
else
outputVideo.open(NAME , ex, inputVideo.get(CV_CAP_PROP_FPS),S, true);
if (!outputVideo.isOpened())
{
cout << "Could not open the output video for write: " << source << endl;
return -1;
}
//输出视频尺寸和帧数
cout << "Input frame resolution: Width=" << S.width << " Height=" << S.height
<< " of nr#: " << inputVideo.get(CV_CAP_PROP_FRAME_COUNT) << endl;
//输出编码器类型
cout << "Input codec type: " << EXT << endl;
int channel = 2; // Select the channel to save
switch(channelNum)
{
case 'R' : {channel = 2; break;}
case 'G' : {channel = 1; break;}
case 'B' : {channel = 0; break;}
}
Mat src,res;
vector<Mat> spl; //存储分割后的单通道图像
while( true) //Show the image captured in the window and repeat
{
inputVideo >> src; //传一帧给src
if( src.empty()) break; // check if at end
// // 通道分割,spl[0]为B,spl[1]为G,spl[2]为R
split(src, spl);
// //将非用户选择的通道置空
for( int i =0; i < 3; ++i)
if (i != channel)
spl[i] = Mat::zeros(S, spl[0].type());
//和平处理后的图像到res
merge(spl, res);
//处理后的一帧图片存入创建的视频
//outputVideo.write(res);
outputVideo << res;
}
cout << "Finished writing" << endl;
return 0;
}
运行结果: