OpenCV не сообщает точную частоту кадров / количество - PullRequest
13 голосов
/ 04 декабря 2010

У меня есть 33-секундное видео, которое я пытаюсь обработать с помощью OpenCV.Моя цель - определить, какому экземпляру по времени (относительно начала видео) соответствует каждый кадр.Я делаю это для того, чтобы иметь возможность сравнивать кадры из видео той же сцены, которые были записаны с различной частотой кадров.

Что работает:

  • FPS правильносообщается как 59,75.Это согласуется с тем, что сообщает ffprobe, поэтому я рад, что это правильно.

Проблемы, с которыми я сталкиваюсь:

  • CAP_PROP_POS_MSEC возвратневерные значения.К концу видео оно достигает 557924 мс (более 9 минут).Для видео 33-х это не может быть правильным.
  • CAP_PROP_FRAME_COUNT также неверно.Сообщается, что это 33371, что при 59,75 кадрах в секунду даст отснятый материал за 9 минут.В соответствии с вышеуказанной ошибкой, но все же неверно.
  • CAP_PROP_POS_FRAME аналогично неверно.

Видео можно найти здесь (около 10 МБ).

Есть идеи, что может быть не так?

ffprobe вывод:

FFprobe version SVN-r20090707, Copyright (c) 2007-2009 Stefano Sabatini
  libavutil     49.15. 0 / 49.15. 0
  libavcodec    52.20. 0 / 52.20. 1
  libavformat   52.31. 0 / 52.31. 0
  built on Jan 20 2010 00:13:01, gcc: 4.4.3 20100116 (prerelease)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/misha/Dropbox/Public/sequence.mp4':
  Duration: 00:00:33.37, start: 0.000000, bitrate: 2760 kb/s
    Stream #0.0(und): Video: h264, yuv420p, 1920x1080, 59.75 tbr, 1k tbn, 2k tbc
    Stream #0.1(und): Audio: aac, 44100 Hz, stereo, s16

Полный код:

#include <iostream>
#include <assert.h>

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

#include <cmath>
#include <iostream>
#include <string.h>
#include <stdio.h>

extern "C"
{
#include "options.h"
}

using namespace std;

#define DEBUG 0

static void
print_usage(char *argv0)
{
    cerr << "usage: " << argv0 << " video.avi [options]" << endl;
}

int main(int argc, char** argv)
{
    if (argc < 2)
    {
        print_usage(argv[0]);
        return -1;
    }

    int           step      = 30;
    struct Option options[] =
    {
        { "step",        1, &step },
        { NULL,          0, NULL }
    };

    int ret = parse_options(2, argc, argv, options);
    if (ret == 0)
    {
        print_usage(argv[0]);
        return -1;
    }

    CvCapture *capture = cvCaptureFromFile(argv[1]);
    int counter = 0;
    while (cvGrabFrame(capture))
    {
        ++counter;

        IplImage *frame = cvRetrieveFrame(capture);
        double millis   = cvGetCaptureProperty(capture, CV_CAP_PROP_POS_MSEC);
        double current  = cvGetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES);
        double total    = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT);
        printf("%d %d/%d %f\n", counter, (int)current, (int)total, millis);
        int min = (int)(millis/1000/60);
        millis -= min*60000;
        int sec = (int)(millis/1000);
        millis -= sec*1000;

        printf("%d %02d:%02d:%f\n", counter, min, sec, millis);
    }
    cvReleaseCapture(&capture);

    return 0;
}

1 Ответ

5 голосов
/ 04 декабря 2010

Всегда сообщайте версию программного обеспечения, которую вы используете: какую версию OpenCV вы используете для этого?Ваша версия может быть старой, поэтому, если возможно, обновите ее до самой последней версии.

Если ваш видеофайл является частью какого-то другого более крупного видео, эта информация может быть правильной, поскольку:

CV_CAP_PROP_POS_MSEC - film current position in milliseconds or video capture timestamp

OpenCV может просто читать все эти вещи из заголовка файла, что, очевидно, неправильно.Это может произойти, если кто-то использовал топор (или другой средневековый инструмент), чтобы убрать этот фрагмент из исходного видео.

Вам следует попробовать сделать видео, которые вы сделали, и вы знаете, что они не были подделаны.

В худшем случае вам придется реализовать эти функции самостоятельно.Не важно.

РЕДАКТИРОВАТЬ: @misha Сначала я не заметил, что вы используете:

CvCapture *capture = cvCaptureFromFile(argv[1]);

Замените его на cvCaptureFromAVI () если можете, и ВСЕГДА проверьте возвращаемое значение вызовов OpenCV:

CvCapture *capture = cvCaptureFromAVI(argv[1]);
if(!capture) 
{
    printf("!!! cvCaptureFromAVI failed (file not found?)\n");
    return -1; 
}

Несколько дней назад я поделился кодом, что использует OpenCV для чтения видеофайлаа затем сохранить кадры в виде изображений JPG на диске .Он также сообщает текущий FPS с использованием традиционного cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);, поэтому вам будет интересно взглянуть на это.Проверьте это.

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

Вы также должны проверить эту тему о количестве кадров с помощью OpenCV;

ByКстати, я только что обновил некоторые библиотеки в своей системе Ubuntu и перекомпилировал OpenCV-2.1.0.tar.bz2 (используя cmake ).Я изменил свой исходный код (который использует cvCaptureFromAVI () ) для печати материала с использованием вашего метода отладки в каждом кадре.Кажется, это работает:

* Filename: sequence.mp4
* FPS: 59
...
...
...
17 00:00:567.000000
18 601/33371 601.000000
18 00:00:601.000000
19 634/33371 634.000000
19 00:00:634.000000
20 668/33371 668.000000
20 00:00:668.000000
21 701/33371 701.000000
21 00:00:701.000000
22 734/33371 734.000000
22 00:00:734.000000
23 768/33371 768.000000
23 00:00:768.000000
24 801/33371 801.000000
24 00:00:801.000000
25 835/33371 835.000000
25 00:00:835.000000
26 868/33371 868.000000
26 00:00:868.000000
27 901/33371 901.000000
27 00:00:901.000000
28 935/33371 935.000000
... 
...