web-dev-qa-db-fra.com

OpenCV: VideoCapture :: get (CV_CAP_PROP_FPS) retourne FPS

J'essaie d'obtenir les images par seconde de ma caméra afin de pouvoir les transmettre à la variable VideoWriter pour la sortie de la vidéo. Cependant, je reçois 0 ips en appelant VideoCapture::get(CV_CAP_PROP_FPS) à partir de mon appareil photo. Si je la code en dur, ma vidéo risque d’être trop lente ou trop rapide.

#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);
}

Comment puis-je obtenir VideoCapture::get(CV_CAP_PROP_FPS) pour renvoyer le bon nombre d'images par seconde ou un attribut à la VideoWriter qui fonctionne de manière universelle pour toutes les webcams?

10
swtdrgn

CV_CAP_PROP_FPS ne fonctionne que sur les vidéos pour autant que je sache. Si vous souhaitez capturer des données vidéo à partir d'une webcam, vous devez chronométrer vous-même correctement. Par exemple, utilisez une minuterie pour capturer une image de la webcam toutes les 40 ms, puis enregistrez une vidéo à 25 images par seconde.

4
littleimp

Vous pouvez utiliser VideoCapture::set(CV_CAP_PROP_FPS) pour définir le FPS souhaité pour une webcam. Cependant, vous ne pouvez pas utiliser get pour une raison quelconque.

Notez que parfois le pilote choisira un autre FPS que celui que vous avez demandé en fonction des limitations de la webcam.

Ma solution de contournement: capturer des images pendant quelques secondes (4 convient dans mes tests, avec 0,5 seconde de retard initial), et estimer le nombre d'images par seconde des sorties de la caméra.

2
Jose Gómez

Je n'ai jamais vu CV_CAP_PROP_FPS fonctionner. J'ai essayé avec différentes versions d'OpenCV 2.4.x (actuellement la version 2.4.11) en utilisant des entrées de fichier.

Comme solution de contournement dans un scénario, j'ai directement utilisé libavformat (de ffmpeg) pour obtenir la fréquence d'images, que je peux ensuite utiliser dans mon autre code 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;
}

En dehors de cela, l'une des méthodes les plus lentes possible (bien que sûr de fonctionner) pour obtenir le nombre moyen d'images par seconde, serait de parcourir chaque image et de diviser le numéro de l'image actuelle par l'heure actuelle:

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 ...
}

Vous ne voudrez probablement faire ce dernier que si les autres méthodes de recherche directe de la vitesse par seconde échouent. De plus, il n'y avait pas de meilleur moyen d'obtenir de manière sommaire des informations globales sur la durée et le nombre de trames.

L'exemple ci-dessus fonctionne sur un fichier - pour s'adapter à une caméra, vous pouvez utiliser le temps écoulé depuis l'horloge murale depuis le début de la capture, au lieu d'obtenir CV_CAP_PROP_POS_MSEC. Ensuite, le nombre moyen par seconde pour la session serait le temps écoulé de l’horloge murale divisé par le nombre de vues actuel.

1
Jameson

Pour la vidéo en direct de la webcam, utilisez cap.get (cv2.CAP_PROP_FPS).

0
Athul Soori