Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Picturebox变大了,但我可以';无法检测或修复它_C#_Winforms_Thread Safety_Picturebox_Aforge - Fatal编程技术网

C# Picturebox变大了,但我可以';无法检测或修复它

C# Picturebox变大了,但我可以';无法检测或修复它,c#,winforms,thread-safety,picturebox,aforge,C#,Winforms,Thread Safety,Picturebox,Aforge,我目前正在使用AForge,并且有一个关于新帧的事件,该事件将帧作为位图发布到picturebox中。90%的时间它工作得很好。。。除非我在winform上摆弄什么东西。更改组合框、移动窗口或诸如此类的操作可能会导致Picturebox从视频切换到一个大的红色X。下面的代码示例: private void connectButton_Click(object sender, EventArgs e) { try { cam

我目前正在使用AForge,并且有一个关于新帧的事件,该事件将帧作为位图发布到picturebox中。90%的时间它工作得很好。。。除非我在winform上摆弄什么东西。更改组合框、移动窗口或诸如此类的操作可能会导致Picturebox从视频切换到一个大的红色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)上加了一个中断,它的计算结果为false,即使在红色大X出现时也是如此,因为图像实际上被设置为位图。所以cam.Stop()和cam.Start()永远不会运行(不确定这是否有用,但我想我会尝试一下)

videoPictureBox1.Refresh()每次都在运行,但同样,这并没有什么不同。还有红色的大X

正如我之前所说:如果我启动视频,什么都不碰,那么红色的大X永远不会发生。但当我开始改变组合框,或者拖动表单本身时,出现红色大X的几率呈指数增长。有时,我可以在组合框出现之前将其翻转10-12次,其他情况下,在我单击组合框时,它就会出现。:-\


有人能解释一下这里发生了什么,也许能提供一个关于解决问题的最佳方法的建议吗?我还是一个线程新手,所以我一直在努力思考这里到底发生了什么,以及解决这个问题的最佳方法!任何朝正确方向的轻推都将是巨大的帮助

在使用位图的位置尝试使用克隆。 Ex

videoPictureBox1.Image = (Bitmap)bitmap.Clone();

最后,我将所有内容包装在调用的Handle\u New\u框架中。它彻底地永久性地消除了大红色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
  });
}

肖恩·哈格里夫斯(Shawn Hargreaves)的《末日的大红色X》(big red X of doom)一书精妙、简洁。我发现它在处理WinForm组件突然显示红色“X”的一般情况下非常有用

总之:

  • 这是由控件在
    OnPaint
    事件中抛出异常引起的
  • 一旦抛出该控件,该控件将继续显示红色X,并跳过在绘制时触发。
  • 要进行调试,请将调试器设置为捕获公共语言运行时异常,然后执行您通常执行的任何操作以获取红色X。调试器将在发生错误的地方停止,从而允许您进行调查,并希望找到防止错误发生的方法

总而言之,这是一个经过测试的最小值,即使在调整大小、启动、停止或分辨率更改时,对我来说也不会显示任何红十字

   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)是从视频(worker)线程调用的


我认为这就是为什么我们需要调用和新位图,因此新的bmp也将从gui线程生成。但我只是在猜测,因为我找不到证据。

我想我可能只是不使用图片框。改为使用面板,并在面板的绘制事件中绘制位图。使用invalidate强制刷新。在大红色X senario期间,您看过eventArgs.Frame吗?另外,我会在异常下放置一个messagebox,以防出现错误。好的,我会很快尝试一下!另一个注意事项:我转到debug->exceptions并选中了所有“抛出”复选框。当这种情况发生时,什么也不会发生。好的,金戴夫,我现在也要试试!谢谢我添加了一个面板,将“videoPictureBox1.Image=bitmap”更改为“panel3.BackGroundImage=bitmap;panel3.Invalidate();”。移动表单时,我再次得到了红色的大X:(我还在那个catch中添加了一条消息-它从来没有被调用过!这是我引入的一个令人困惑的小错误!如果修复它就像创建它一样简单,那就好了!lol!这也可能会导致竞争条件,或者我错了吗?如果在处理位图和克隆位图之间发生重画,那么会出现红色的大X。@Hans是的,尝试使用位图处置前@Hans,你能检查一下我答案中的代码吗?我试图生成这样一个竞争条件,但没有成功。我遇到了完全相同的事情,也试图弄清楚发生了什么,但没有结果。我猜这是一些单线程策略,但我没有得到任何异常或错误消息,我采用了你的方法,现在它工作了.hi,我使用了它,但当我尝试关闭videoSource时,它不会停止并等待释放资源…您是否遇到了相同的问题?关于您对GC.Collect()的评论。位图的继承链实现了IDisposable。GC问题可能是由于您缺少调用Dispose。请尝试使用块或手动调用Bitmap.Dispose().BTW:我很快就放弃了这种方法,原因很明显:-)嗨,我用过它,但当我试图关闭videoSource时,它不会停下来等待释放资源…你有同样的问题吗?链接断了。更新的链接:@TobiasKnauss谢谢!我在答案中更新了链接。