2010-10-28 74 views
1

这里是问题:我有一个自定义的硬件设备,我必须在C#/ WPF中从它抓取图像,并将它们显示在一个窗口中,全部使用120+ FPS。显示高帧率的图像

问题是没有事件表明图像已准备好,但我必须不断查询设备并检查是否有任何新图像,然后下载它们。

显然有很多方法可以做到这一点,但我还没有找到合适的方法。

这里是我的尝试:

  • 一个简单的定时器(或DispatcherTimer) - 伟大工程较慢的帧速率,但我不能让它过去我们说,60 FPS。

  • 单线程无限循环 - 相当快,但我必须把DoEvents /它的WPF等价物放在循环中才能重绘窗口;这有一些其他有害(怪)的后果,如从没有被解雇等一些控制按键事件...

  • 做轮询/下载在另一个线程和UI线程显示,像这样:

    new Thread(() => 
         { 
          while (StillCapturing) 
          { 
           if (Camera.CheckForAndDownloadImage(CameraInstance)) 
           { 
            this.Dispatcher.Invoke((Action)this.DisplayImage); 
           } 
          } 
         }).Start(); 
    

    好吧,这个工作相对比较好,但是会给CPU带来相当大的负担,当然如果它没有超过一个CPU /内核就会完全死机,这是不可接受的。另外,我这里有大量的线程争用。

问题是显而易见的 - 有没有更好的选择,或者是这种情况下去这种情况下呢?

更新:
不知何故,我忘了提,(嗯,忘了想想在写这个问题),但当然我并不需要显示所有框架,但是我仍然需要捕获所有这些数据,以便将它们保存到硬盘中。

UPDATE2: 我发现该DispatcherTimer方法是不是因为它不能处理一切速度不够快,而是因为DispatcherTimer等待发射Tick事件之前下一个垂直同步;这在我的情况下确实很好,因为在tick事件中,我可以将所有待处理图像保存到内存缓冲区(用于将图像保存到磁盘)并显示最后一个。

至于旧计算机被捕获完全“杀死”,似乎WPF回落到软件渲染非常缓慢。我可能无能为力。

感谢您的所有答案。

+1

120+ FPS?你使用什么样的显示技术作为我的TFT显示器(高清晰度)不会超过60Hz,因此无论如何它会丢失一半的帧数。 – Jaydee 2010-10-28 12:16:59

+0

谢谢。你是绝对正确的。不知道我怎么没有想到这件事(嗯,我做到了,但它在我脑海中滑落)。我仍然需要将它们全部捕获到内存中(为了将它们保存到磁盘)并显示让我们说一半 - 我会用计时器来尝试它,看看是否会通过。 – 2010-10-28 12:41:47

+0

虽然显示每隔4帧就足够了(30FPS),并可能有助于CPU负载。你捕获什么决议?硬件设备的接口是否可拆分地连接到记录计算机的第二个连接到用户界面计算机? – Jaydee 2010-10-28 15:58:28

回答

1

我认为你在尝试过于简单的方法。这是我会做的。

a)在您的轮询循环中放置一个Thread.Sleep(5),它应该允许您接近120fps,同时仍然保持CPU时间低。

b)每隔5帧左右更新一次显示。这将减少处理量,因为我不确定WPF是否可以处理远远超过60fps的处理量。

c)使用ThreadPool为每个帧产生一个子任务,然后将其保存到磁盘(每帧单独一个文件),这样你就不会受到磁盘性能的限制。额外的帧将堆积在内存中。

就我个人而言,我会按顺序实施它们。机会是a或b会解决你的问题。

+0

谢谢!我已经使用了方法c),并与DispatcherTimer一起实现了方法b)(请参阅我对原始文章的最新更新),目前我对结果非常满意。 – 2010-10-28 19:15:41

-1

你可以做以下的(所有伪码): 1.有工作线程运行处理捕获过程:

List<Image> _captures = new List<Image>(); 
new Thread(() => 
    { 
     while (StillCapturing) 
     { 
      if (Camera.CheckForAndDownloadImage(CameraInstance)) 
      { 
       lock(_locker){_captures.Add(DisplayImage); 


      } 
     } 
    }).Start(); 
  1. 有调度计时器线程为最新拍摄的图像(显然这自上次打勾后将错过一些捕捉)并显示。因此,UI线程受到限制并尽可能少地执行,它不会完成所有“捕获”,这是由工作线程完成的。对不起,我不能让这个位格式化(但你的想法):

    void OnTimerTick(can't remember params) 
    

    { 图片imageToDisplay; lock(_locker){imageToDisplay = _captures [k.Count - 1]; DisplayFunction(imageToDisplay); }

  2. 它可能是该列表是一个队列,另一个线程用于排出队列并写入磁盘或任何其他线程。

+0

如果某个其他线程将锁持续时间过长,该锁可能会导致跳过帧。另外,它仍不能解决OP提到的高CPU负载问题。 – 2010-10-28 13:23:42

+0

锁定不会导致图像被跳过。一个线程将捕获所有图像。调度程序线程在计划时会渲染最新的图像(显然会跳过图像,因为这是重点)。 – dashton 2010-10-28 13:29:41