使用后台工作程序有效地写入GUI线程

时间:2015-07-28 21:15:47

标签: c# multithreading winforms webcam

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

Total runtime: 1564.444 ms

问题是,最终在我的屏幕上调整或移动表单会抛出异常while (CaptureThreadRunning) { Thread.Sleep(5); Image tmp = Camera.GetFrame(500); pbCameraFeed.Image = tmp; //this.BeginInvoke(new MethodInvoker(delegate { pbCameraFeed.Image = Camera.GetFrame(500); })); } ,并在System.InvalidOperationException

行上显示消息Additional information: Object is currently in use elsewhere.

我假设该库试图在我的while循环的同时绘制与PictureBox有关的东西,所以我切换到上面注释掉的pbCameraFeed.Image = tmp;实现。不幸的是,这显着降低了我的帧率。我在非常慢的Mini PC上运行此代码,这可能导致了这个问题。

我真正想要的是一种用可靠的图像更新我的GUI的方法,这种方法不会使我的帧率降低近一半。还有其他标准方法吗? BW线程似乎非常适合这个应用程序,但我错过了什么?

由于

2 个答案:

答案 0 :(得分:3)

If I were you I would definitely check out the AForge.NET Framework. No need to reinvent the wheel ;)

http://www.aforgenet.com/framework/samples/video.html

AForge.NET is an open source C# framework designed for developers and researchers in the fields of Computer Vision and Artificial Intelligence - image processing, neural networks, genetic algorithms, fuzzy logic, machine learning, robotics, etc.

The framework is comprised by the set of libraries and sample applications, which demonstrate their features:

AForge.Imaging - library with image processing routines and filters;

AForge.Vision - computer vision library;

AForge.Video - set of libraries for video processing;

...

答案 1 :(得分:0)

我建议不要使用PictureBox,而是直接绘制到UserControl表面。这可以通过addig代码轻松完成UserControl的Paint和Invalidate事件。

下面的示例创建了一个用户控件,该控件具有BitMap属性,每次控件失效时,它都会绘制到其表面。 因此,例如,要从文件夹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();
    } 
}

我认为可以轻松更改以渲染相机图像而不是图片文件。

代码在LinqPad

上进行了测试