Как записать видеофайл с OpenCV?

Я пытаюсь написать программу для анализа эмоциональных выражений, таких как слезы. В рамках моего трекера я использую 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;   
}

person CCS    schedule 02.02.2011    source источник
comment
Можете ли вы отредактировать вопрос, чтобы включить сообщение об ошибке, напечатанное в консоли/терминале после SIGABRT? Это поможет нам больше узнать об ошибке.   -  person speciousfool    schedule 03.02.2011


Ответы (6)


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

В основном:

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

ИЗМЕНИТЬ

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

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

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

ИЗМЕНИТЬ 2

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

person mpenkov    schedule 03.02.2011
comment
Спасибо вам за ваши предложения. Однако я пробовал с CV_FOURCC('I', 'Y', 'U', 'V'), включая все FOURCC, перечисленные в документе, но безуспешно. Есть ли способ в OS X открыть диалоговое окно, подобное тому, как WIndows делает с -1 или CV_FOURCC_PROMPT? - person CCS; 03.02.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, в этом случай 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);
}
person cooplogic    schedule 03.08.2011

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

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

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

person net_programmer    schedule 10.11.2014

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

Меня устраивает.

person Francisco Calderon    schedule 05.05.2011

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

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

person speciousfool    schedule 03.02.2011
comment
Уважаемые, спасибо за отзыв. Я изменил значение на -1 вместо V_FOURCC('M', 'J', 'P', 'G'). Теперь программа может быть выполнена и завершена со значением состояния: 0. Однако программа сохранила файл фильма в формате AVI (8 КБ на диске), который, по-видимому, пуст. Я использую код OS X/X/OpenCV 2.2. У вас есть рабочий код с cvWriteFrame? Спасибо, что нашли время взглянуть на мою проблему! - person CCS; 03.02.2011
comment
У меня та же проблема, что и у @CCS - person Lepi; 25.11.2011
comment
Проголосовали против, потому что это, похоже, не отвечает на вопрос. - person JohnAllen; 24.09.2016

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

варить установить opencv --with-ffmpeg

person user2218016    schedule 23.05.2014