Picturebox получает большой красный X, но я не могу его обнаружить или исправить

в настоящее время я работаю с AForge и имею событие on new frame, которое публикует кадр в виде растрового изображения в 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 вверх, потому что изображение фактически устанавливается в растровое изображение. Так Кэм.Стоп () и Кэм.Start () никогда не запускается (не уверен, что это даже поможет, но я решил, что попробую).

videoPictureBox1.Refresh() запускается каждый раз, но опять же - это не имеет значения. Еще есть большой красный X.

Как я уже говорил раньше: если я начну видео и ничего не трогаю, большой красный X никогда не произойдет. Но в тот момент, когда я начинаю менять комбо-боксы, или перетаскивая саму форму, вероятность большого красного X растет экспоненциально. Иногда я могу пролистать поле со списком 10-12 раз, прежде чем это произойдет, в других случаях это происходит в секунду, когда я нажимаю combobox. :-

может ли кто-нибудь объяснить, что здесь происходит, и, возможно, предложить лучший метод для его исправления? Я все еще очень новичок в threading, поэтому я изо всех сил пытаюсь обернуть голову вокруг того, что здесь происходит, и лучший способ исправить проблему! Любые толчки в правильном направлении будут огромной помощью!

4 ответов


в конце концов, я завернул все в Handle_New_Frame в invoke. Он полностью удалил проблему big red 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
  });
}

Шон Харгривз имеет отличный, краткий рецензия "большой красный крест судьбы". Я нашел это очень полезным в общем случае работы с компонентами WinForm, внезапно показывающими красный "X".

в итоге:

  • это связано с контролем исключения из OnPaint событие.
  • как только он будет брошен, этот элемент управления будет продолжать показывать красный X и пропустить стрельбу OnPaint.
  • для отладки, отладчик чтобы поймать исключения Общеязыковой среды выполнения, а затем сделать все, что вы обычно делаете, чтобы получить красный X. отладчик остановится прямо там, где это происходит, что позволит вам исследовать и, надеюсь, выяснить способ предотвратить это.

попробуйте использовать клон в местах, где вы используете растровое изображение. Ex:

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

чтобы подвести итог, это проверенный минимум, который не показывает Красный Крест для меня, даже если размер, начатый, остановленный или разрешение изменилось.

   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-(creation)-thread, но обработчик обратного вызова (Handle_Very_New_Frame) вызывается из потока video (worker).

Я думаю, поэтому нам нужны оба, Invoke и новое растровое изображение, поэтому новый bmp также будет создан из gui-потока. Но я просто догадываюсь, так как я не смог придумать доказательства.