使用后台工作线程高效地写入GUI线程
本文关键字:线程 GUI 高效 后台 工作 | 更新日期: 2023-09-27 18:05:25
我使用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); }));
}
问题是,最终调整或移动窗体周围我的屏幕将抛出异常System.InvalidOperationException
与pbCameraFeed.Image = tmp;
行上的消息Additional information: Object is currently in use elsewhere.
我假设库正在尝试画一些与PictureBox有关的东西,同时我的while循环是,所以我切换到上面注释掉的this.BeginInvoke
实现。不幸的是,这大大降低了我的帧率。我在一台非常慢的Mini PC上运行这个代码,这可能是导致问题的原因。
我真正想要的是一种方法来更新我的GUI与图像可靠,不降低我的帧率近一半。还有其他标准的方法吗?一个BW线程似乎完美的这个应用程序,但我错过了什么?
谢谢
如果我是你,我一定会去AForge看看。净框架。没有必要重新发明轮子;)
http://www.aforgenet.com/framework/samples/video.htmlAForge。. NET是一个开源的c#框架,专为开发人员和计算机视觉和人工智能领域的研究人员智能——图像处理,神经网络,遗传算法,模糊逻辑、机器学习、机器人等
框架由一组库和示例组成展示其特性的应用程序:
AForge。成像。带有图像处理例程和过滤器的库;
AForge。视觉-计算机视觉库;
AForge。视频——视频处理库集;
…
我建议不要使用PictureBox,而是直接绘制到UserControl表面。这可以通过向UserControl的Paint和Invalidate事件添加代码来轻松完成。
下面的例子,创建了一个用户控件,它有一个位图属性,每次控件失效时,它都会被绘制到它的表面。因此,例如,要从文件夹D:' myppictures中随机渲染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上测试