【问题标题】:OpenCV: VideoCapture::get(CV_CAP_PROP_FPS) returns 0 FPSOpenCV:VideoCapture::get(CV_CAP_PROP_FPS) 返回 0 FPS
【发布时间】:2013-11-08 20:13:12
【问题描述】:

我正在尝试从我的相机中获取 fps,以便我可以将其传递给 VideoWriter 以输出视频。但是,通过从我的相机调用VideoCapture::get(CV_CAP_PROP_FPS),我得到了 0 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 或为 VideoWriter 提供适用于所有网络摄像头的 fps?

【问题讨论】:

    标签: c++ windows opencv camera avi


    【解决方案1】:

    据我所知,CV_CAP_PROP_FPS 仅适用于视频。如果您想从网络摄像头捕获视频数据,您必须自己正确计时。例如,使用计时器每 40 毫秒从网络摄像头捕获一帧,然后保存为 25fps 视频。

    【讨论】:

    • 该提议几乎可以保证会产生不流畅的视频,因为视频中捕获的 fps 与网络摄像头的捕获 fps 不匹配。
    • 你能详细说明一下吗?为什么会产生生涩的视频?
    • 网络摄像头使用固定或定义的帧率进行捕捉。对于给定的分辨率,捕获将以 15 fps、25 fps、60 fps... 这取决于网络摄像头的速度、链接的带宽、驱动程序和设置。如果网络摄像头的帧率与您拍摄的帧不匹配,有时您可能会两次拍摄同一帧,有时您可能会跳帧,因此运动会不流畅。
    • 获得平滑运动的方法是设置所需的 FPS(如果驱动程序允许,请参阅我在 stackoverflow.com/a/22920585/1816603 中的回复)并以网络摄像头提供的帧速率(或分隔线)进行捕捉其中,例如 60 -> 30, 50 -> 25, 30 -> 15)。
    • 好的,谢谢您的解释。不过,我仍然需要手动计时,对吧?
    【解决方案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 将是经过的挂钟时间除以当前帧数。

      【讨论】:

      • 有用的信息。但是,该问题将(网络)摄像头称为输入,而不是使用视频文件。
      • @JoseGómez 最后一段不是为你做的,嗯?
      • 是的,我错过了那个;这听起来很合理。基本上,您建议的是计算有效帧率,对吗?这是我最终采用的类似方法。请注意,我必须在初始延迟后才开始计算帧速率,以使数字准确(可能是由于一些初始化)。似乎很奇怪,为了像从网络摄像头获取视频流设置的当前帧速率这样简单的事情,必须经历这么多麻烦。
      • 通常等待第一帧的时间最长。我在几个网络摄像头上测量了它,如果我们从第一帧开始 开始测量实时时间(不是墙上时间 - CPU 时间),则间隔非常一致。另请注意,有时cap.set(CV_CAP_PROP_FPS, /*someting*/) 有效。例如。在具有 V4L2 的 Linux 上,但前提是相机可以在物理上带来那么多 FPS。
      【解决方案4】:

      对于来自网络摄像头的实时视频,请使用 cap.get(cv2.CAP_PROP_FPS)

      【讨论】:

      • 这就是 OP 所做的。这将返回 0。
      猜你喜欢
      • 2012-03-13
      • 1970-01-01
      • 2011-10-25
      • 2015-01-24
      • 1970-01-01
      • 2015-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多