Opencv媒体与GUI---利用Opencv创建视频

代码

#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)
{
    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
    int ex = static_cast<int>(inputVideo.get(CV_CAP_PROP_FOURCC));     // Get Codec Type- Int form

    // Transform from int to char via Bitwise operators
    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));    

    VideoWriter outputVideo;                                        // Open the output
    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;
    }

    union { int v; char c[5];} uEx ;
    uEx.v = ex;                              // From Int to char via union
    uEx.c[4]='\0';

    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(argv[2][0])
    {
    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;              // 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;
}

解释

  • 首先,你需要知道一个视频文件是什么样子的。每一个视频文件本质上都是一个容器,文件的扩展名只是表示容器格式(例如 avi , mov ,或者 mkv )而不是视频和音频的压缩格式。容器里可能会有很多元素,例如视频流,音频流和一些字幕流等等。这些流的储存方式是由每一个流对应的编解码器(codec)决定的。通常来说,视频流很可能使用 mp3 或 aac 格式来储存。而视频格式就更多些,通常是 XVID , DIVX , H264 或 LAGS(Lagarith Lossless Codec)等等。具体你能够使用的编码器种类可以在操作系统的编解码器列表里找到。

  • OpenCV只是个计算机视觉库而不是一个视频处理编码库。所以开发者们试图将这个部分尽可能地精简,结果就是OpenCV能够处理的视频只剩下 avi 扩展名的了。另外一个限制就是你不能创建超过2GB的单个视频,还有就是每个文件里只能支持一个视频流,不能将音频流和字幕流等其他数据放在里面。尽管如此,任何系统支持的编解码器在这里应该都能工作。

VideoWriter 类

  • 输出的文件名中包含了容器的类型,当然在现在仅仅支持 avi 格式。在这个例子中我们会使用输入文件名+通道名+avi来创建输出文件名。
  • 然后决定使用的编解码器,现在所有的视频编解码器都使用最多四个字节的名称来标识,例如 XVIDDIVX, 和 H264 等。这个被称作FourCC(four character code)。你可以通过 get 函数来向视频询问这个编码, get 函数会返回一个double数,仅仅是因为double包含了64位数据而已,由于FourCC编码只占据了其中低位的4个字节,所以可以直接通过强制转换成int型来扔掉高位的四个字节。
  • OpenCV内部使用这个int数来当作第二个参数,这里会使用两种方法来将这个整型数转换为字符串:位操作符和联合体。前者可以用&操作符并进行移位操作,以便从int里面释放出字符:
  • 也可以使用 联合体 来做到
  • :
  • 如果传入的参数是一个负数的话,就会在执行时弹出一个对话框,在里面包括了所有已安装的编码器类型,你可以在里面选择一个并使用之。
  1. 输出视频的帧率,也就是每秒需要绘制的图像数,在这里我让输出视频的帧率与输入视频相同,输入视频的帧率可以由 get 函数来获得。
  2. 输出视频的尺寸,在这里我同样保持和输入视频一样的大小,这个大小同样也可以由 get 函数来获得。
  3. 最后一个参数是一个可选参数。默认下它是true,来表示输出的视频是彩色的(所以你需要传给它三通道的图像),如果想创建一个灰度视频就传入false。
  • 具体实现请看下面的例子:
  • 最好使用 isOpened() 函数来检查是不是成功打开。在成功打开时视频后,就可以用 write 函数向这个对象按照序列发送一些图像帧了,另外使用重载操作符 << 也可以完成这些操作。最后,视频会在 VideoWriter 对象析构时自动关闭。
  • 要“释放”出某个通道,又要保持视频为彩色,实际上也就意味着要把未选择的通道都设置为全0。这个操作既可以通过手工扫描整幅图像来完成,又可以通过分离通道然后再合并来做到,具体操作时先分离三通道图像为三个不同的单通道图像,然后再将选定的通道与另外两张大小和类型都相同的黑色图像合并起来。

结果

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值