Как написать видео файл с OpenCV? - PullRequest
14 голосов
/ 02 февраля 2011

Я пытаюсь написать программу для анализа эмоциональных выражений, таких как слезы.Как часть моего трекера, я использую OpenCV для записи образцов видео.В частности, я не уверен в том, как правильно выбрать FPS (кажется, 10FPS должен работать).Я также не уверен, какой кодек мне следует использовать в OS X, я перепробовал все возможные 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 ]

19 голосов
/ 03 февраля 2011

Посмотрите здесь рекомендуемые кодеки для использования.

В основном:

  • Вы можете использовать -1 вместо CV_FOURCC(...) только если вы работаете в Windows (см. руководство ).Поскольку вы используете OSX, вы не можете его использовать .
  • Используйте CV_FOURCC('I', 'Y', 'U', 'V') для кодирования с использованием yuv420p в несжатый контейнер AVI - это рекомендуемый подход
  • Если вам нужно сжатое видео, то вы можете использовать такие инструменты, как ffmpeg, чтобы сжимать вывод AVI с помощью OpenCV

Причина, по которой OpenCV не рекомендует использовать кодеки сжатия, вероятно, заключается в том, что каждый кодек имеетбольшое количество специфичных для кодека опций, и работа со всеми из них через простой интерфейс OpenCV Video Writer была бы невозможна.

EDIT

У меня есть плохие новости :

К сожалению, у нас до сих пор нет работающего (т. е. собственного) средства записи видео для Mac OS X. Если вам нужна запись видео, в настоящее время вам необходимо настроить ffmpeg или xine и отключить QuickTime.

Похоже, вам может понадобиться переконфигурировать и перекомпилировать библиотеку.

РЕДАКТИРОВАТЬ 2

В качестве альтернативы, вы можете просто написать каждый кадрв файл JPEGи затем вставьте эти файлы JPEG в фильм, используя ffmpeg (это должно работать в OS / X).Во всяком случае, это, по сути, MJPEG.Однако вы, вероятно, получите более высокие коэффициенты сжатия с кодеками, которые используют временную избыточность (например, MPEG4, H.264 и т. Д.).

3 голосов
/ 04 августа 2011

Утверждение предполагает, что существует несоответствие размера между изображением, отправляемым на устройство записи видео, и размером, указанным при инициализации устройства записи видео. Я бы предложил добавить несколько операторов отладки следующим образом:

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. Вместо использования macports вы можете напрямую загрузить opencv2.2 из sourceforge и использовать 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 голосов
/ 10 ноября 2014

У меня была такая же проблема.Я решил это с помощью Planar RGB Codec.

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

Размер вывода важен, но он работает без установки чего-либо.

0 голосов
/ 23 мая 2014

Прочитав ответ Миши. Я решил эту проблему в Mac OS 10.9 Mavericks и XCode 5, переустановив opencv с помощью Homebrew.

brew install opencv --with-ffmpeg

0 голосов
/ 06 мая 2011

Я думаю, это из-за размера видео - попробуйте другие, более распространенные, такие как 640X480 или 320X240.

Это работает для меня.

0 голосов
/ 03 февраля 2011

Я думаю, что строка CV_FOURCC может быть неправильной. аналогичный вопрос предлагает использовать -1 в качестве CV_FOURCC тестового значения, чтобы предложить вам рабочий выбор в вашей системе.

Можете ли вы попытаться скомпилировать программу из этого вопроса и сказатьнам если значение -1 вместо V_FOURCC('M', 'J', 'P', 'G') записывает AVI-файл?

...