C# 使用后台工作程序高效地写入GUI线程

C# 使用后台工作程序高效地写入GUI线程,c#,multithreading,winforms,webcam,C#,Multithreading,Winforms,Webcam,我正在使用BackgroundWorker从相机中提取视频,并将其写入WinForms窗体上的PictureBox。在BW线程中,我只需从相机中拉出一个帧,将其放入PictureBox,睡眠,然后继续: while (CaptureThreadRunning) { Thread.Sleep(5); Image tmp = Camera.GetFrame(500); pbCameraFeed.Image = tmp; //this.BeginInvoke(new M

我正在使用BackgroundWorker从相机中提取视频,并将其写入WinForms窗体上的PictureBox。在BW线程中,我只需从相机中拉出一个帧,将其放入PictureBox,睡眠,然后继续:

while (CaptureThreadRunning)
{
    Thread.Sleep(5);
    Image tmp = Camera.GetFrame(500);
    pbCameraFeed.Image = tmp;
    //this.BeginInvoke(new MethodInvoker(delegate { pbCameraFeed.Image = Camera.GetFrame(500); }));
}
问题是,最终在我的屏幕上调整或移动表单将引发异常
系统。InvalidOperationException
带有消息
附加信息:对象当前正在其他地方使用。
pbCameraFeed.Image=tmp

我假设库试图在while循环的同时绘制与PictureBox有关的内容,因此我切换到上面注释掉的
this.BeginInvoke
实现。不幸的是,这大大降低了我的帧率。我在一台非常慢的迷你电脑上运行这段代码,这可能是导致问题的原因

我真正想要的是一种用图像可靠地更新GUI的方法,它不会使我的帧速率下降近一半。是否有其他标准方法可以做到这一点?BW线程似乎非常适合此应用程序,但我是否遗漏了什么


谢谢

如果我是你,我一定会查看AForge.NET框架。无需重新发明车轮;)

NET是一个开源的C#框架,专为开发人员和 计算机视觉和人工视觉领域的研究人员 智能-图像处理,神经网络,遗传算法, 模糊逻辑、机器学习、机器人学等

该框架由一组库和示例组成 演示其功能的应用程序:

图像处理程序和过滤器库

视觉-计算机视觉图书馆

a org.Video-用于视频处理的库集


我建议不要使用PictureBox,而是直接绘制到UserControl图面。这可以通过向绘制中添加代码并使UserControl的事件无效来轻松完成

下面的示例创建了一个用户控件,该控件具有位图属性,每次控件失效时都会将其绘制到其表面。 例如,要从文件夹D:\MyPictures随机渲染JPG图像,可以执行以下操作:

using System.Windows.Forms;
using System.Drawing;

void Main()
{
    var pictures = Directory.GetFiles(@"D:\MyPictures", "*.jpg");
    var rnd = new Random();
    var form = new Form();
    var control = new MyImageControl() { Dock = DockStyle.Fill };
    form.Controls.Add(control);

    var timer = new System.Windows.Forms.Timer();
    timer.Interval = 50;
    timer.Tick += (sender, args) => 
    {
        if (control.BitMap != null)
            control.BitMap.Dispose();
        control.BitMap = new Bitmap(pictures[rnd.Next(0, pictures.Length)]);
        control.Invalidate();
    };
    timer.Enabled = true;
    form.ShowDialog();
}

public class MyImageControl : UserControl // or PictureBox
{
    public Bitmap BitMap { get; set; }
    public MyImageControl()
    {
        this.Paint += Graph_Paint;
        this.Resize += Graph_Resize;
    }
    private void Graph_Paint(object sender, PaintEventArgs e)
    {
        if (this.BitMap != null)
        {
            lock (this.BitMap)
            {
                Graphics g = e.Graphics;
                g.DrawImage(this.BitMap, this.ClientRectangle);
            }
        }
    }
    private void Graph_Resize(object sender, System.EventArgs e)
    {
        this.Invalidate();
    } 
}
我认为这可以很容易地更改为渲染相机图像,而不是图片文件


代码是在

上测试的,如果您只是用
try{}catch{}
捕获此异常会怎么样?您是否尝试保持
开始唤醒
但增加了
睡眠
时间?5毫秒低于
线程的精度。Sleep
(大约15毫秒,取决于操作系统上的活动),因此您可以肯定地提高它。这将有助于减少负载/延迟。增加睡眠时间将减少延迟?我认为在PictureBox更新之间增加更多的时间会进一步降低帧速率(即使是很小的一部分)。我将尝试调整睡眠时间,看看这能给我带来什么。@Fabjan不是一个好的建议。例外情况的存在是有原因的。它说你做错了什么,应该被修复,而不是隐藏在try/catch后面。@user912447相反,你当前正在告诉UI线程“嘿,停止你正在做的事情,为我更新图片框”,每5毫秒一次。如果你在更新上放松一点,UI将有更多的时间来做更多的事情,比如重新绘制自己和响应用户的交互。这也是为什么在BW上放置长时间运行的操作;因此,UI可以做其他事情并保持响应速度。因此,如果你把睡眠时间设定在33毫秒左右,你应该得到相当于30帧的速度。听起来很有趣。使用UserControl界面比使用PictureBox有什么好处?我原以为使用UserControl会更有效,但我对此没有把握。尝试将
MyImageControl:UserControl
更改为
MyImageControl:PictureBox
。这应该行得通。阿佛格看起来真不错。我认为需要一些时间来使用这个框架,而不仅仅是使用我的小while循环。不过,看起来AForge可以相对轻松地解决我遇到的FPS问题。作为一个小的更新,我确实出于不相关的原因开始使用AForge,但不幸的是,AForge似乎没有办法与DirectShow不起作用的摄像头接口。我最初使用的是非DirectShow摄像头,所以如果我想继续使用Forge,我也必须切换摄像头。。。