首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在C#中实时采集视频时保持稳定的每秒帧数

如何在C#中实时采集视频时保持稳定的每秒帧数
EN

Stack Overflow用户
提问于 2013-08-15 08:15:20
回答 2查看 763关注 0票数 1

我已经写了一个C#程序,它通过相机制造商的专有应用程序接口从一个专门的相机捕获视频。我可以通过FileStream对象将捕获的帧写入磁盘,但当涉及到帧率时,我受制于相机和磁盘I/O。

确保以所需的帧率写入磁盘的最佳方法是什么?是否有某种算法可以计算实时平均帧率,然后添加/丢弃帧以保持特定的期望帧率?

EN

回答 2

Stack Overflow用户

发布于 2013-08-15 09:08:26

在这种缺乏信息的情况下,很难说出任何事情。

格式是什么?有压缩吗?

摄像头API是如何发送帧的?它们是否计时,所以摄像头将发送您要求的帧速率?如果是这样的话,您实际上是在处理I/O速度。

如果您需要高质量,并且在没有压缩的情况下写入,您可以尝试一些无损压缩算法来平衡处理和驱动器I/O。如果驱动器I/O处的瓶颈很高,您可以获得如此高的速度。

对于框架,有一些方法可以实现这一点。正常情况下,帧有时间戳,您应该搜索时间戳,并丢弃距离其他帧太近的帧。假设你想要60fps,那么帧之间的间隔是1000/ 60 =16ms,如果你得到的帧有时间戳,比如说最后一帧后13ms,你可以丢弃它,不写入磁盘。

票数 0
EN

Stack Overflow用户

发布于 2022-01-10 00:39:40

在理想的情况下,您应该检查第一秒,它给出了您的系统支持的每秒帧数。

假设你的相机拍摄速度是60帧/秒,但你的电脑只能处理45帧/秒。你要做的就是每秒跳过15帧才能跟上。到目前为止,这已经很简单了。

这种基本情况下的数学运算是:

代码语言:javascript
复制
60 / 15 = 4

因此,每四个传入帧跳过一帧,就像这样(保留标记有X的帧,跳过其他帧):

代码语言:javascript
复制
000000000011111111112222222222333333333344444444445555555555
012345678901234567890123456789012345678901234567890123456789

XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX

当然,你很可能不会得到这样一个清晰的案例。数学仍然是一样的,只是你最终会在看起来不同的时间点跳过帧:

代码语言:javascript
复制
// simple algorithm based on fps from source & destination
// which fails to keep up long term
double camera_fps = 60.0;
double io_fps = camera_fps;

for(;;)
{
  double frames_step = camera_fps / io_fps;

  double start_time = time(); // assuming you get at least ms precision
  double frame = 0.0;
  for(int i(0); i < camera_fps; ++i)
  {
    buffer frame_data = capture_frame();
    if(i == (int)frame)  // <- part of the magic happens here
    {
      save_frame(frame_data);
    }
    frame += frames_step;
  }

  double end_time = time();
  double new_fps = camera_fps / (end_time - start_time);

  if(new_fps < io_fps)
  {
    io_fps = new_fps;
  }
}

如此算法所示,您希望随着时间的推移调整fps。在第一秒内,由于各种原因,它可能会给你一个无效的结果。例如,对磁盘的写入可能会被缓冲,所以速度非常快,看起来就像你可以支持60fps。稍后,fps会变慢,您可能会发现最大I/O速度为57fps。

这个基本算法的一个问题是,你可以很容易地减少帧的数量,使其在1秒内工作,但它只会减少fps (即,我只在new_fps较小时更新io_fps )。如果您找到了io_fps的正确数字,就可以了。这是因为当(end_time - start_time)恰好为1秒时,new_fps将为1.0,这意味着您没有花费太多时间来捕获和保存传入的帧。

这个问题的解决方案是对save_frame()函数进行计时。如果内部循环中的总帧数小于1秒,则可以增加可以保存的帧数。如果你可以使用两个线程,这将会工作得更好。一个线程读取帧,将帧推入内存中的FIFO,另一个线程从该FIFO中检索帧。这意味着捕获一帧的时间量不会(很大程度上)影响保存帧所需的时间。

代码语言:javascript
复制
bool stop = false;

// capture
for(;;)
{
  buffer frame_data = capture_frame();
  fifo.push(frame_data);
  if(stop)
  {
    break;
  }
}

// save to disk
double expected_time_to_save_one_frame = 1.0 / camera_fps;
double next_start_time = time();
for(;;)
{
  buffer frame_data = fifo.pop();
  double start_time = next_start_time;
  save_frame(frame_data);
  next_start_time = time();
  double end_time = time();
  if(start_time - end_time > expected_time_to_save_one_frame)
  {
    fifo.pop();  // skip one frame
  }
}

这只是伪代码,我可能犯了一些错误。它还期望start_timeend_time之间的间隔不会超过一帧(即,如果您有这样一种情况,即捕获速度为60 fps,而I/O支持不到30 fps,则通常必须连续跳过两帧)。

对于正在压缩帧的人,请记住,一次调用save_frame()的时间会有很大不同。有时,框架可以很容易地压缩(没有水平移动),有时它真的很慢。这就是这种活力可以提供极大帮助的地方。假设在记录过程中没有发生太多其他事情,那么一旦达到支持的最大速度,磁盘I/O应该不会有太大变化。

重要说明:这些算法假设相机fps是固定的;这可能不是很正确;您也可以对相机计时并相应地调整camera_fps参数(这意味着expected_time_to_save_one_frame变量也可以随时间变化)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18244394

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档