2013-05-14 100 views
1

您好,感谢您阅读我的线索!我想寻求我的代码的建议,因为经过大量的搜索,我找不到任何东西来解决这个特定的问题。我用google搜索了一下,在stackoverflow上搜索,所有的解决方案都不起作用(或者我不知道如何实现它们)。这里是我的代码:Visual C#BackgroundWorker对象目前正在其他地方使用

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using AForge.Video; 
using AForge.Video.DirectShow; 
using System.Threading ; 

    namespace Motion_Detection 
    { 
     public partial class Form1 : Form 
     { 
      private FilterInfoCollection VideoCaptureDevices; 
      private VideoCaptureDevice FinalVideo; 

     private void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs) 
     { 
      Bitmap video = (Bitmap)eventArgs.Frame.Clone(); 
      pictureBox1.Image = video; 
     } 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice); 
      foreach (FilterInfo VideoCaptureDevice in VideoCaptureDevices) 
      { 
       devicesList.Items.Add(VideoCaptureDevice.Name); 
       devicesList.SelectedIndex = 0; 
      } 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[devicesList.SelectedIndex].MonikerString); 
      FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame); 

      FinalVideo.Start(); 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
      pictureBox1.Image = null; 
      FinalVideo.Stop(); 
     } 

     private void button3_Click(object sender, EventArgs e) 
     { 
      worker.RunWorkerAsync(); 
     } 

     private void button4_Click(object sender, EventArgs e) 
     { 
      worker.CancelAsync(); 
     } 

     private void worker_DoWork(object sender, DoWorkEventArgs e) 
     { 
      while (!worker.CancellationPending) 
      { 
       Bitmap map = new Bitmap(pictureBox1.Image); // this line throws the error 

       for (int x = 0; x < pictureBox1.Width; x++) 
       { 
        for (int y = 0; y < pictureBox1.Height; y++) 
        { 
         Color pixel = map.GetPixel(x, y); 

         if (pixel.R == 255 && pixel.G == 0 && pixel.B == 0) 
         { 
          // detected red pixel 
         } 
        } 
       } 

       Thread.Sleep(100); // check every 100ms or any other given interval 
      } 
     } 
    } 
} 

所以我使用Aforge视频DLL来访问我的网络摄像头。这部分工作,我可以访问并从中读取流,当我将它转储到picturebox1时,它显示得很完美,没有任何延迟。

现在我正在进行一些运动检测,首先我想看看是否可以检测到出现在相机前面的某种颜色的像素。因为我需要遍历每个像素,所以我必须将其放在不同的线程上,否则它会冻结我的GUI并且显示开始滞后。

这个问题是因为我这样做,我不知道如何正确访问来自后台工作者的picturebox.image内容,而不会触发标题中的错误。互联网上的一些人建议使用lock(),但我从来没有这样做过,也不知道我应该在这里锁定()。我从来没有使用多线程,因为最终我永远无法处理访问违规..

为了解决这个问题,我尝试了尝试finally块,尽管即使在try块中,我也得到了相同的异常。我认为有一种更干净的方式来做我刚才提到的,但我无法真正理解哪一种可能。

我希望我在论坛上的第一篇文章尽可能清晰易懂。

谢谢问候 〜伊尔汗

回答

0

你不能/不应该,除非UI线程上访问pictureBox1。

我认为你需要做这样的事情:

private void GetImage(out Bitmap img) 
{ 
    img = new Bitmap(pictureBox1.Image); 
} 

void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    Bitmap img = null; 
    Invoke(new Action(() => GetImage(out img))); 
    // Do what you want with the bitmap 
} 

访问上一个WinForm控件是否会抛出异常它不是在UI线程。 你可以通过pictureBox1.InvokeRequired找出你是否在正确的线程上。 调用Invoke将向UI线程发送一条消息以完成传递的委托,然后它将等待传递的委托完成。调用BeginInvoke将发送消息,但不会等待。

+0

非常感谢这工作!这个援引的东西看起来..嗯奇怪我从来没有需要调用任何东西,但你可能(为我自己的好)用几句话解释究竟是什么解决方案? – Ilhan 2013-05-14 17:16:36

+0

我会给你一个镜头,任何人如果我错了或误解,我也有兴趣,请纠正我。他所做的就是调用一个后台工作者(线程)从UI线程中执行长时间运行的任务,以便您的UI可以按需要继续工作,而无需挂起。 Invoke允许你通过调用主线程上的方法从picturebox获取一个只能从UI线程访问的位图。工作线程然后等待主线程上运行的该方法返回位图。当它返回时,它会转到您的工作线程,再次从主线程处理。 – 2013-09-05 19:54:05

相关问题