Creating a video with OpenCVsh# 一.先决条件
详细教程,视频文件,源文件下载;
1.VideoWrite
Public Member Functions | |
---|---|
VideoWriter () | |
Default constructors. More… | |
VideoWriter (const String &filename, int fourcc, double fps, Size frameSize, bool isColor=true) | |
VideoWriter (const String &filename, int apiPreference, int fourcc, double fps, Size frameSize, bool isColor=true) |
Parameters
filename | Name of the output video file. 输出视频名 |
---|---|
fourcc | 4-character code of codec used to compress the frames. For example, VideoWriter::fourcc(‘P’,‘I’,‘M’,‘1’) is a MPEG-1 codec, VideoWriter::fourcc(‘M’,‘J’,‘P’,‘G’) is a motion-jpeg codec etc. List of codes can be obtained at Video Codecs by FOURCC page. FFMPEG backend with MP4 container natively uses other values as fourcc code: see ObjectType, so you may receive a warning message from OpenCV about fourcc code conversion. 用于压缩帧的4字符编解码器 |
fps | Framerate of the created video stream. 创建的视频流的帧率 |
frameSize | Size of the video frames. 视频尺寸 |
isColor | If it is not zero, the encoder will expect and encode color frames, otherwise it will work with grayscale frames (the flag is currently supported on Windows only). 是否为彩色图像,非0为彩色 |
2.对于视频的初步认识
首先,你需要知道一个视频文件是什么样子的。每一个视频文件本质上都是一个容器,文件的扩展名只是表示容器格式(例如 avi , mov ,或者mkv )而不是视频和音频的压缩格式。容器里可能会有很多元素,例如视频流,音频流和一些字幕流等等。这些流的储存方式是由每一个流对应的编解码器(codec)决定的。通常来说,视频流很可能使用mp3或 aac 格式来储存。而视频格式就更多些,通常是 XVID , DIVX , H264 或 LAGS (Lagarith Lossless Codec)等等。具体你能够使用的编码器种类可以在操作系统的编解码器列表里找到
二.示例介绍
1.命令行输入的参数
第一个参数为可执行文件
第二个参数为输入视频路径
第三个参数为需要分离的颜色通道,取RGB中的一个
第四个参数为Y
或N
,表明视频格式,N时与输入视频一致("Y"时会报错,一脸闷逼,可能还是没看明白)
2.注意事项
(1)如你所见,视频文件确实比图像文件要复杂很多。然而OpenCV只是个计算机视觉库而不是一个视频处理编码库。所以开发者们试图将这个部分尽可能地精简,结果就是OpenCV能够处理的视频只剩下avi 扩展名的了。另外一个限制就是你不能创建超过2GB的单个视频,还有就是每个文件里只能支持一个视频流,不能将音频流和字幕流等其他数据放在里面。尽管如此,任何系统支持的编解码器在这里应该都能工作。如果这些视频处理能力不够你使用的话,我想你应该去找一些专门处理视频的库例如FFMpeg 或者更多的编解码器例如 HuffYUV , CorePNG 和 LCL 。你可以先用OpenCV创建一个原始的视频流然后通过其他编解码器转换成其他格式并用VirtualDub 和 AviSynth 这样的软件去创建各种格式的视频文件
(2)所以,这个视频只是简单处理,如果需要处理别的格式或者比较大的视频,需要使用别的库
三.源码分析
话不多说了,直接上源码
#include <iostream> // for standard I/O
#include <string> // for strings
#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat)
#include <opencv2/videoio.hpp> // Video write
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
static void help()
{
cout
<< "------------------------------------------------------------------------------" << endl
<< "This program shows how to write video files." << endl
<< "You can extract the R or G or B color channel of the input video." << endl
<< "Usage:" << endl
<< "./video-write <input_video_name> [ R | G | B] [Y | N]" << endl
<< "------------------------------------------------------------------------------" << endl
<< endl;
}
void videoPlay(string NAME)
{
VideoCapture output(NAME);
Mat frame;
for(;;)
{
output>>frame;
if(frame.empty())
{cout<<"game over";break;}
namedWindow("NewVideo");
imshow("NewVideo",frame);
if(waitKey(100)==27)break;
}
}
int main(int argc, char *argv[])
{
help();
if (argc != 4)
{
cout << "Not enough parameters" << endl;
return -1;
}
const string source = argv[1]; // the source file name
const bool askOutputType = argv[3][0] =='Y'; // If false it will use the inputs codec type
VideoCapture inputVideo(source); // Open input
if (!inputVideo.isOpened())
{
cout << "Could not open the input video: " << source << endl;
return -1;
}
string::size_type pAt = source.find_last_of('.'); // Find extension point
//得到新视频名称
const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi"; // Form the new name with container
//得到4个字符的视频解码器代码
int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC)); // Get Codec Type- Int form
// Transform from int to char via Bitwise operators
//把数字转换为字符,使用移动操作
char EXT[] = {(char)(ex & 0XFF) , (char)((ex & 0XFF00) >> 8),(char)((ex & 0XFF0000) >> 16),(char)((ex & 0XFF000000) >> 24), 0};
Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH), // Acquire input size
(int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));
VideoWriter outputVideo; // Open the output
if (askOutputType)
//name,视频编码,帧率,尺寸,不为零,彩色帧;否则灰色帧
outputVideo.open(NAME, ex=-1, inputVideo.get(CAP_PROP_FPS), S, true);
else
outputVideo.open(NAME, ex, inputVideo.get(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(CAP_PROP_FRAME_COUNT) << endl;
cout << "Input codec type: " << EXT << endl;
int channel = 2; // Select the channel to save
switch(argv[2][0])
{
case 'R' : channel = 2; break;
case 'G' : channel = 1; break;
case 'B' : channel = 0; break;
}
Mat src, res;
vector<Mat> spl;
for(;;) //Show the image captured in the window and repeat
{
inputVideo >> src; // read
if (src.empty()) break; // check if at end
split(src, spl); // process - extract only the correct channel
for (int i =0; i < 3; ++i)
if (i != channel)
spl[i] = Mat::zeros(S, spl[0].type());
merge(spl, res);
//outputVideo.write(res); //save or
outputVideo << res;
}
cout << "Finished writing" << endl;
videoPlay(NAME);
return 0;
}