How to write a video file with OpenCV?

北城余情 提交于 2019-11-28 20:42:30

Have a look here for the recommended codecs to use.

Basically:

  • You can use -1 instead of CV_FOURCC(...) only if you're on Windows (see the manual). Since you're on OSX, you can't use it.
  • Use CV_FOURCC('I', 'Y', 'U', 'V') to encode using yuv420p into an uncompressed AVI container -- this is the recommended approach
  • If you want compressed video, then you can use tools like ffmpeg to compress the AVI output by OpenCV

The reason OpenCV doesn't recommend using compressor codecs is probably because each codec has a large number of codec-specific options, and dealing with all of them through the simple OpenCV video writer interface would be impossible.

EDIT

I have some bad news:

Unfortunately, we still have no working (i.e. native) video writer for Mac OS X. If you need video writing, you should currently configure for ffmpeg or xine and disable QuickTime.

Sounds like you may need to reconfigure and recompile your library.

EDIT 2

Alternatively, you could just write each frame to a JPEG file, and then stitch those JPEG files into a movie using ffmpeg (that should work on OS/X). This is essentially what MJPEG is, anyway. You'll probably get better compression rates with codecs that exploit temporal redundancy (e.g. MPEG4, H.264, etc), though.

The assertion suggests that there is a size mismatch between the image being sent to the video writer, and the size specified when initializing the video writer. I would suggest adding some debug statements as follows:

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

That should help you find out if the sizes are different.

With regard to the fourcc question, it looks like you are using cap_ffmpeg instead of cap_qtkit. You may want to try recompiling with ffmpeg off, since the qtkit version of capture works pretty well on OS X. Rather than using macports, you can directly download opencv2.2 from sourceforge and use ccmake to configure opencv not to use ffmpeg, in that case qtkit will be the default.

If you do use qtkit, then you need to use the fourcc('j','p','e','g');

The frame rate should match the frame rate of the input. You can use the properties to get the frame rate similar to the way you got the frame width and height, however since you are capturing from the camera, you will probably have to test the capture rate by using a timer in your code and estimating from that.

Here is an example based on starter_video.cpp that will work with 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);
}
net_programmer

I had the same problem. I solved it by using the Planar RGB Codec.

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

The output size is important, but it works without installing anything.

Francisco Calderon

I think that's because of the size of the video - try others, more common like 640X480 or 320X240.

It works for me.

speciousfool

I think the CV_FOURCC line may be incorrect. A similar question suggests using -1 as a CV_FOURCC test value to prompt you with the working choices on your system.

Can you try to compile the program from that question and tell us if using a value of -1 instead of V_FOURCC('M', 'J', 'P', 'G') writes an AVI file?

After reading misha's answer. I resolved this problem under Mac OS 10.9 Mavericks and XCode 5 by reinstall opencv using Homebrew.

brew install opencv --with-ffmpeg

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!