OpenCV: VideoCapture:: get (CV_CAP_PROP_FPS) возвращает 0 FPS

Я пытаюсь получить fps с камеры, чтобы передать его в VideoWriter для вывода видео. Тем не менее, я получаю 0 кадров в секунду, вызывая VideoCapture::get(CV_CAP_PROP_FPS) с моей камеры. Если я его скопирую, мое видео может быть слишком медленным или слишком быстрым.

#include "opencv2/opencv.hpp"
#include <stdio.h>
#include <stdlib.h>

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    cv::VideoCapture cap;
    int key = 0;

    if(argc > 1){
        cap.open(string(argv[1]));
    }
    else
    {
        cap.open(CV_CAP_ANY);
    }
    if(!cap.isOpened())
    {
        printf("Error: could not load a camera or video.\n");
    }

    Mat frame;
    cap >> frame;
    waitKey(5);

    namedWindow("video", 1);
    double fps = cap.get(CV_CAP_PROP_FPS);
    CvSize size = cvSize((int)cap.get(CV_CAP_PROP_FRAME_WIDTH),(int)cap.get(CV_CAP_PROP_FRAME_HEIGHT));

    int codec = CV_FOURCC('M', 'J', 'P', 'G');
    if(!codec){ waitKey(0); return 0; }
    std::cout << "CODEC: " << codec << std::endl;
    std::cout << "FPS: " << fps << std::endl;
    VideoWriter v("Hello.avi",-1,fps,size);
    while(key != 'q'){
        cap >> frame;
        if(!frame.data)
        {
            printf("Error: no frame data.\n");
            break;
        }
        if(frame.empty()){ break; }
        v << frame;
        imshow("video", frame);
        key = waitKey(5);
    }
    return(0);
}

Как я могу получить VideoCapture::get(CV_CAP_PROP_FPS), чтобы вернуть правый fps или дать fps для VideoWriter, который работает универсально для всех веб-камер?

Ответ 1

CV_CAP_PROP_FPS работает только с видео, насколько мне известно. Если вы хотите захватить видеоданные с веб-камеры, вы должны своевременно ее правильно. Например, используйте таймер для захвата кадра с веб-камеры каждые 40 мс, а затем сохраните его как видео с частотой 25 кадров в секунду.

Ответ 2

Вы можете использовать VideoCapture::set(CV_CAP_PROP_FPS) для установки желаемого FPS для веб-камеры. Однако по какой-то причине вы не можете использовать get.

Обратите внимание, что иногда драйвер выбирает другой FPS, чем тот, который вы запросили, в зависимости от ограничений веб-камеры.

Мое обходное решение: захватить кадры в течение нескольких секунд (4 в моих тестах, с 0,5 секундами начальной задержки) и оценить fps выходы камеры.

Ответ 3

Я никогда не видел CV_CAP_PROP_FPS для работы. Я пробовал с различными вариантами OpenCV 2.4.x(в настоящее время 2.4.11), используя входы файлов.

Как обходной путь в одном сценарии, я напрямую использовал libavformat (из ffmpeg), чтобы получить частоту кадров, которую затем я могу использовать в своем другом коде OpenCV:

static double get_frame_rate(const char *filePath) {
    AVFormatContext *gFormatCtx = avformat_alloc_context();
    av_register_all();

    if (avformat_open_input(&gFormatCtx, filePath, NULL, NULL) != 0) {
        return -1;
    } else if (avformat_find_stream_info(gFormatCtx, NULL) < 0) {
        return -1;
    } 

    for (int i = 0; i < gFormatCtx->nb_streams; i++) {
        if (gFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            AVRational rate = gFormatCtx->streams[i]->avg_frame_rate;
            return (double)av_q2d(rate);
        }
    }

    return -1;
}

Помимо этого, несомненно, одним из самых медленных (хотя и уверенных в работе) методов получения среднего значения fps было бы пройти через каждый кадр и разделить текущий номер кадра на текущее время:

for (;;) {
    currentFrame = cap.get(CV_CAP_PROP_POS_FRAMES);
    currentTime = cap.get(CV_CAP_PROP_POS_MSEC);
    fps = currentFrame / (currentTime / 1000);

    # ... code ...
    # stop this loop when you're satisfied ...
}

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

В приведенном выше примере работает над файлом - чтобы адаптироваться к камере, вы можете использовать истекшее время стенограммы с момента начала захвата, вместо получения CV_CAP_PROP_POS_MSEC. Тогда среднее значение fps для сеанса будет временем прошедшего настенного времени, деленным на текущий номер кадра.

Ответ 4

Для живого видео с веб-камеры используйте cap.get(cv2.CAP_PROP_FPS)