web-dev-qa-db-ja.com

OpenCV:VideoCapture :: get(CV_CAP_PROP_FPS)は0FPSを返します

ビデオを出力するためにVideoWriterに渡すことができるように、カメラからfpsを取得しようとしています。ただし、カメラからVideoCapture::get(CV_CAP_PROP_FPS)を呼び出すと0fpsになります。ハードコーディングすると、ビデオが遅すぎたり速すぎたりする可能性があります。

_#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を返すか、すべてのWebカメラで普遍的に機能するVideoWriterにfpsを与えるにはどうすればよいですか?

11
swtdrgn

CV_CAP_PROP_FPSは、私が知る限り、ビデオでのみ機能します。ウェブカメラからビデオデータをキャプチャしたい場合は、自分で正しく時間を計る必要があります。たとえば、タイマーを使用して40ミリ秒ごとにWebカメラからフレームをキャプチャし、25fpsのビデオとして保存します。

4
littleimp

VideoCapture::set(CV_CAP_PROP_FPS)を使用して、Webカメラに必要なFPSを設定できます。ただし、何らかの理由でgetを使用できません。

ウェブカメラの制限によっては、ドライバーが要求したものとは異なるFPSを選択する場合があることに注意してください。

私の回避策:数秒間フレームをキャプチャし(私のテストでは4で問題ありませんが、初期遅延は0.5秒です)、カメラが出力するfpsを推定します。

2
Jose Gómez

CV_CAP_PROP_FPSが機能するのを見たことがありません。ファイル入力を使用して、OpenCV 2.4.x(現在は2.4.11)のさまざまなフレーバーを試してみました。

1つのシナリオでの回避策として、(ffmpegからの)libavformatを直接使用してフレームレートを取得しました。これを他の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を取得するための最も遅い(確実に機能する)方法の1つは、各フレームをステップスルーし、現在のフレーム番号を現在の時間で除算することです。

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は、壁時計の経過時間を現在のフレーム番号で割ったものになります。

1
Jameson

ウェブカメラからのライブビデオには、cap.get(cv2.CAP_PROP_FPS)を使用します

0
Athul Soori