【opencv/videoio module】(二)Creating a video with OpenCV

说在前面

Theory

  • 视频文件结构

在这里插入图片描述

  • OpenCV中的限制

    • OpenCV并不是一个处理视频流的库,所以开发者将这部分尽可能地简化。
    1. 文件扩展
      仅支持.avi,最大视频文件2GB
    2. 仅可处理视频轨道(什么音频啊就不支持了)
    • 如果要限界解除,可以使用其他库例如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(⊙ˍ⊙)?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值