10

我目前正在使用 AForge,并且有一个 on new frame 事件将帧作为位图发布到图片框中。90% 的时间它工作得很好......除非我在 winform 上摆弄一些东西。更改组合框、移动窗口或任何类似的操作都有可能导致图片框从视频切换到大红色 X。代码示例如下:

    private void connectButton_Click(object sender, EventArgs e)
    {
        try
        {
            cam = new VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString);
            cam.NewFrame -= Handle_New_Frame; //Just to avoid the possibility of a second event handler being put on
            cam.NewFrame += new AForge.Video.NewFrameEventHandler(Handle_New_Frame);
            cam.Start();
        }
        catch
        {
            MessageBox.Show("An error has occured with connecting to the specified webcam. The application will now close!");
            Application.Exit();
        }
    }

    private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
    {

        try
        {
            if (bitmap != null)
                bitmap.Dispose(); //Without this, memory goes nuts
            bitmap = new Bitmap(eventArgs.Frame);
        }
        catch { }

        //Draw some stuff on the images
        bitmap = AdjustBrightness(bitmap, brightnessMeter);
        bitmap = ApplyContrast(contrastMeter, bitmap);
        bitmap = Draw_Top_Line(bitmap);
        bitmap = Draw_Bottom_Line(bitmap);

        //Set the image into the picturebox
        this.Invoke((MethodInvoker)delegate
        {
            videoPictureBox1.Image = bitmap;
            frameRate++; //Keep track of the frame rate
        });

        GC.Collect(); //Without this, memory goes nuts

        this.Invoke((MethodInvoker)delegate {
            videoPictureBox1.Refresh(); //NOT NECESSARY. JUST TRYING TO FIX THE BIG RED X!
        });

        if (videoPictureBox1.Image == videoPictureBox1.ErrorImage)
        {
            cam.Stop(); //ALSO NOT NECESSARY> AGAIN, JUST TRYING TO FIX THE BIG RED X!
            cam.Start();
        }
    }

我在 if (videoPictureBox1.Image == videoPictureBox1.ErrorImage) 上放了一个中断,它评估为假,即使大红色 X 向上,因为图像实际上被设置为位图。所以 cam.Stop() 和 cam.Start() 永远不会运行(不确定这是否会有所帮助,但我想我会试一试)。

videoPictureBox1.Refresh() 每次都在运行,但同样 - 它没有任何区别。还是有大红色的X。

正如我之前所说:如果我开始播放视频并且什么都不触摸,那么大红色 X 将永远不会发生。但是,当我开始更改组合框或拖动表单本身时,出现大红色 X 的机会呈指数级增长。有时我可以在组合框发生之前翻阅 10-12 次,其他时候它会在我单击组合框的第二次发生。:-\

任何人都可以解释这里发生了什么,并可能就修复它的最佳方法提供建议吗?我对线程仍然很陌生,所以我一直在努力弄清楚这里发生了什么以及解决问题的最佳方法!朝着正确方向的任何推动都将是一个巨大的帮助!

4

4 回答 4

6

最后,我在调用中将所有内容都包含在 Handle_New_Frame 中。它完全永久地消除了大红色 X 问题。>_>

private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
{
  this.Invoke((MethodInvoker)delegate
  {
    try
    {
        if (bitmap != null)
        {
            bitmap.Dispose(); //Without this, memory goes nuts
        }

        bitmap = new Bitmap(eventArgs.Frame);
    }
    catch { }

    //Draw some stuff on the images
    bitmap = AdjustBrightness(bitmap, brightnessMeter);
    bitmap = ApplyContrast(contrastMeter, bitmap);
    bitmap = Draw_Top_Line(bitmap);
    bitmap = Draw_Bottom_Line(bitmap);

    //Set the image into the picturebox
    this.Invoke((MethodInvoker)delegate
    {
        videoPictureBox1.Image = bitmap;
        frameRate++; //Keep track of the frame rate
    });

    GC.Collect(); //Without this, memory goes nuts
  });
}
于 2013-04-22T19:41:57.873 回答
6

肖恩·哈格里夫斯 (Shawn Hargreaves )对“厄运的大红色 X”有出色而简洁的描述。我发现它在处理突然显示红色“X”的 WinForm 组件的一般情况下非常有用。

总之:

  • 这是由控件从OnPaint事件中抛出异常引起的。
  • 一旦被抛出,该控件将继续显示红色 X 并跳过射击OnPaint.
  • 要进行调试,请将调试器设置为捕获公共语言运行时异常,然后执行您通常执行的任何操作以获取红色 X。调试器将在它发生的地方停止,让您进行调查并希望找到防止它的方法。
于 2015-04-22T21:26:00.053 回答
1

尝试在使用位图的地方使用克隆。 例如

videoPictureBox1.Image = (Bitmap)bitmap.Clone();
于 2013-04-18T19:37:16.507 回答
0

总结一下,这是一个经过测试的最低限度,即使在调整大小、开始、停止或分辨率改变时,对我来说也没有红叉。

   public partial class PictureBoxVideo : Form
   {
      public PictureBoxVideo()
      {
         InitializeComponent();
         var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
         var videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);
         videoSource.NewFrame += Handle_Very_New_Frame;
         videoSource.Start();
      }

      private void Handle_Very_New_Frame(object sender, NewFrameEventArgs eventArgs)
      {
         this.Invoke((MethodInvoker)delegate {
            pictureBox.Image = new Bitmap(eventArgs.Frame);
         });
      }
   }

请注意,我们调用 videoSource.Start(); 来自 GUI-(创建)线程,但回调处理程序(Handle_Very_New_Frame)是从视频(工作)线程调用的。

我认为这就是我们需要调用和新位图的原因,因此新的 bmp 也将从 gui 线程生成。但我只是在这里猜测,因为我无法拿出证据。

于 2017-03-11T19:44:28.360 回答