说在前面
- opencv版本:4.0.1
- 操作系统:win10
- vs版本:2017
- 官方文档:Creating a video with OpenCV
- 其他说明:自学,记录,demo
Theory
-
OpenCV中的限制
- OpenCV并不是一个处理视频流的库,所以开发者将这部分尽可能地简化。
- 文件扩展
仅支持.avi,最大视频文件2GB - 仅可处理视频轨道(什么音频啊就不支持了)
- 如果要限界解除,可以使用其他库例如FFmpeg
SourceCode
-
VideoWriter类
- 初始化
使用构造函数或者cv::VideoWriter::open
参数说明
virtual bool cv::VideoWriter::open ( const String & filename, //文件名,支持.avi后缀扩展 int fourcc, //编码格式,如果为-1,将弹出选择框(某些操作系统,这里win10 vs没有弹出) double fps, //帧率 Size frameSize, //帧大小 bool isColor = true //是否为彩色图像(单通道/多通道) ) //返回true则代表创建成功 //栗子:VideoWriter writer("test.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), // 25.0, Size(src1.cols, src1.rows)); //吐槽:官方教程里还是旧版本地写法CV_FOURCC('P','I','M,'1') 我看的明明是4.0.1的
- 获取原视频的fourcc
FOURCC-four character codec(?),用四个字符来表示编码格式,每个字符一个字节(8bits),所以刚好是一个整型(4字节)(FOURCC全部类型见 这里§( ̄▽ ̄)§ )
使用VideoCapture::get(CAP_PROP_FOURCC),其返回值为double型,我们只需要低32位即可
VideoCapture inputVideo(source); //Open input int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC));//Get Codec Type- Int form //下面是将编码格式输出需要用到的,毕竟是字符吗 //如果仅是使用,用上面那个ex就可以了 //与运算、移位 char EXT[] = {ex & 0X000000FF , (ex & 0X0000FF00) >> 8, (ex & 0X00FF0000) >> 16, (ex & 0XFF000000) >> 24, 0}; //或者使用共用体,就不需要啥与运算了,好机智啊 union { int v; char c[5];} uEx ; uEx.v = ex; // From Int to char via union uEx.c[4]='\0'; //这里好像有一些细节问题,见附
- 提取通道(看注释)
split(src, spl);//先将src分离成单通道的Mat数组spl for( int i =0; i < 3; ++i) if (i != channel)//如果不是要保留的那一个通道 spl[i] = Mat::zeros(S, spl[0].type());//就把它变成0矩阵,Size:S,type:就是类似CV_8U merge(spl, res);//重新混合成多通道的Mat
- 写入帧
我们使用操作符(重载)<<或者cv::VideoWriter::write 写入一帧
outputVideo.write(res); //or outputVideo << res;
- 小贴士✪ ω ✪
在初始化的时候我们可以将文件名的后缀改成图像后缀例如(jpg\png等)并将fourcc/fps的值置0,这样就可以得到图像序列了。举个栗子:
VideoWriter writer("test_%02d.jpg", 0, 0, Size(src1.cols, src1.rows));
- 初始化
-
Code
#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
using namespace std;
using namespace cv;
int main()
{
const string source = "1.mp4"; // the source file name
const bool askOutputType = true; // 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;
}
const string NAME = "test.mp4"; // Form the new name with container
//获取原视频FOURCC
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)
//这里win10没反应
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: " << NAME << 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; // BGR 012
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;
return 0;
}
Result
- 稍微改了下(见demo),左边提取R通道,右边原图
(板鸭就是帅)
附
END-(CSDN)2019.7.6(⊙ˍ⊙)?