如何用OpenCV编写视频文件?

时间:2011-02-02 08:51:58

标签: macos opencv video-capture

我正在尝试编写一个程序来分析情感表达,比如眼泪。作为我的跟踪器的一部分,我使用OpenCV来录制示例视频。特别是,我不确定如何正确选择FPS(10FPS似乎应该工作)。我也不确定哪个 我应该在OS X上使用的编解码器,我已经尝试了here中所有可能的CV_FOURCC但是返回了以下错误:

Stream #0.0: Video: rawvideo, yuv420p, 640x480, q=2-31, 19660 kb/s, 90k tbn, 10 tbc
Assertion failed: (image->imageSize == avpicture_get_size( (PixelFormat)input_pix_fmt, image->width, image->height )), function writeFrame, file /opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_graphics_opencv/work/OpenCV-2.2.0/modules/highgui/src/cap_ffmpeg.cpp, line 1085.

你们都有一些使用cvWriteFrame的工作代码吗?感谢您花时间看看我的问题!

对于那些感兴趣的人,整个计划是:

#include <cv.h>
#include <cxcore.h>
#include <highgui.h>

int main (int argc, const char * argv[]) 
{
    CvCapture *capture;
    IplImage  *img;
    int       key = 0;
    CvVideoWriter *writer;

    // initialize camera
    capture = cvCaptureFromCAM( 0 );
    // capture = cvCaptureFromAVI("AVIFile");

    // always check
    assert( capture );

    // create a window
    cvNamedWindow( "video", 1 );

    int color = 1; // 0 for black and white

    // get the frame size
    CvSize size = cvSize((int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_WIDTH),(int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_HEIGHT));

    writer = cvCreateVideoWriter(argv[1], -1 , 10 , size, color);

    while( key != 'q' ) {
        // get a frame
        img = cvQueryFrame( capture );

        // always check
        if( !img ) break;

        cvWriteFrame( writer, img );        
        cvShowImage("video", img );

        // quit if user press 'q'
        key = cvWaitKey( 5 );
    }

    // free memory
    cvReleaseVideoWriter( &writer );
    cvReleaseCapture( &capture );
    cvDestroyWindow( "video" );

    return 0;   
}

6 个答案:

答案 0 :(得分:19)

查看here以了解推荐使用的编解码器。

基本上:

  • 只有在Windows上时才能使用-1代替CV_FOURCC(...) (请参阅manual)。由于您使用的是OSX,无法使用
  • 使用CV_FOURCC('I', 'Y', 'U', 'V')使用yuv420p对未压缩的AVI容器进行编码 - 这是推荐的方法
  • 如果您想要压缩视频,那么您可以使用ffmpeg等工具来压缩OpenCV的AVI输出

OpenCV不建议使用压缩编解码器的原因可能是因为每个编解码器都有大量特定于编解码器的选项,并且通过简单的OpenCV视频编写器接口处理所有这些选项是不可能的。

修改

我有一些bad news

  

不幸的是,我们仍然没有适用于Mac OS X的工作(即原生)视频编写器。如果您需要视频编写,您当前应配置ffmpeg或xine并禁用QuickTime。

听起来您可能需要重新配置并重新编译库。

编辑2

或者,您可以将每个帧写入JPEG文件,然后使用ffmpeg将这些JPEG文件拼接成电影(应该适用于OS / X)。无论如何,这基本上就是MJPEG。但是,使用利用时间冗余的编解码器(例如MPEG4,H.264等)可能会获得更好的压缩率。

答案 1 :(得分:3)

断言表明发送到视频编写器的图像与初始化视频编写器时指定的大小之间存在大小不匹配。我建议添加一些调试语句如下:

cout << "Video Size: " << size.width << "," << size.height << endl;
cout << "Image Size: " << img.cols << "," << img.rows << endl;

这应该可以帮助您了解尺寸是否不同。

关于fourcc问题,看起来你使用的是cap_ffmpeg而不是cap_qtkit。您可能希望尝试使用ffmpeg关闭重新编译,因为捕获的qtkit版本在OS X上运行良好。您可以直接从sourceforge下载opencv2.2并使用ccmake配置opencv不使用ffmpeg, case qtkit将是默认值。

如果你使用qtkit,那么你需要使用fourcc('j','p','e','g');

帧速率应与输入的帧速率匹配。您可以使用属性来获得与帧宽和高度相似的帧速率,但是,由于您是从相机捕获的,因此您可能必须通过在代码中使用计时器并从中估计来测试捕获率。这一点。

这是一个基于starter_video.cpp的示例,它将与qtkit一起使用:

/*
* starter_video_write.cpp
*
*  Created on: Nov 23, 2010
*      Author: Ethan Rublee
*  Modified on: Aug 3, 2011 by David Cooper
*
* A starter sample for using opencv, get a video stream and display the images
* easy as CV_PI right?
* edited to add writing capability for OS X using qtkit.
*/
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <vector>
#include <stdio.h>

using namespace cv;
using namespace std;



//hide the local functions in an anon namespace
namespace {
    void help(char** av) {
        cout << "\nThis program justs gets you started reading images from video\n"
            "Usage:\n./" << av[0] << " <video device number>\n"
            << "q,Q,esc -- quit\n"
            << "space   -- save frame\n\n"
            << "\tThis is a starter sample, to get you up and going in a copy pasta fashion\n"
            << "\tThe program captures frames from a camera connected to your computer.\n"
            << "\tTo find the video device number, try ls /dev/video* \n"
            << "\tYou may also pass a video file, like my_vide.avi instead of a device number"
            << endl;
    }

    int process(VideoCapture& capture) {
        int n = 0;
        char filename[200];
        string window_name = "video | q or esc to quit";
        cout << "press space to save a picture. q or esc to quit" << endl;
        namedWindow(window_name, CV_WINDOW_KEEPRATIO); //resizable window;
        Mat frame;
    double frameRate = 15.0;
    capture >> frame;
    VideoWriter* writer = NULL;
    // FIXME: need to change this to an absolute path that exists on this system
    string outputFile = "/tmp/test.mov";
    writer = new VideoWriter(outputFile,
                 CV_FOURCC('j','p','e','g'),
                 frameRate,Size(frame.cols,frame.rows));


        for (;;) {
            capture >> frame;
            if (frame.empty())
                continue;
            imshow(window_name, frame);
        writer->write(frame);
            char key = (char)waitKey(5); //delay N millis, usually long enough to display and capture input
            switch (key) {
        case 'q':
        case 'Q':
        case 27: //escape key
          if(writer != NULL) {
        delete writer;
          }
          return 0;
        case ' ': //Save an image
          sprintf(filename,"filename%.3d.jpg",n++);
          imwrite(filename,frame);
          cout << "Saved " << filename << endl;
          break;
        default:
          break;
            }
        }
        return 0;
    }

}

int main(int ac, char** av) {

    if (ac != 2) {
        help(av);
        return 1;
    }
    std::string arg = av[1];
    VideoCapture capture(arg); //try to open string, this will attempt to open it as a video file
    if (!capture.isOpened()) //if this fails, try to open as a video camera, through the use of an integer param
        capture.open(atoi(arg.c_str()));
    if (!capture.isOpened()) {
        cerr << "Failed to open a video device or video file!\n" << endl;
        help(av);
        return 1;
    }
    return process(capture);
}

答案 2 :(得分:2)

我遇到了同样的问题。 我使用Planar RGB Codec解决了这个问题。

outputVideo.open(PathName, CV_FOURCC('8','B','P','S'), myvideo.get(CV_CAP_PROP_FPS),CvSize(outputframe.size()));

输出大小很重要,但无需安装任何内容即可。

答案 3 :(得分:0)

我认为CV_FOURCC行可能不正确。 similar question建议使用-1作为CV_FOURCC测试值来提示您系统上的工作选择。

您是否可以尝试从该问题编译该程序,并告诉我们使用-1而不是V_FOURCC('M', 'J', 'P', 'G')的值是否写入了AVI文件?

答案 4 :(得分:0)

我认为这是因为视频的大小 - 尝试其他人,更常见的是640X480320X240

它对我有用。

答案 5 :(得分:0)

读完misha的回答后。 我通过使用Homebrew重新安装opencv在Mac OS 10.9 Mavericks和XCode 5下解决了这个问题。

brew install opencv --with-ffmpeg