2013-04-17 13 views
8

Obecnie pracuję z AForge i mam nowe zdarzenie frame, które umieszcza ramkę jako bitmapę w skrzynce obrazkowej. 90% czasu to działa świetnie ... JEŚLI nie bawię się z czymś na WinFormie. Zmiana pola kombi, przesuwając okno, lub coś podobnego, aby ryzyko powodowania PictureBox, aby przełączyć się z filmu na dużym próbki czerwony X. poniższy kod:Picturebox dostaje duży czerwony X, ale nie mogę go wykryć ani naprawić

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(); 
     } 
    } 

kładę przerwę na if (videoPictureBox1.Image == videoPictureBox1.ErrorImage) i wartość jest fałszywa, nawet gdy duży czerwony X jest w górze, ponieważ obraz jest faktycznie ustawiony na bitmapę. Więc cam.Stop() i cam.Start() nigdy nie działają (nie jestem pewien, czy to by nawet pomogło, ale pomyślałem, że spróbuję).

videoPictureBox1.Refresh() działa za każdym razem, ale znowu - to nie robi różnicy. Nadal mam dużą czerwoną X.

Jak już wcześniej wspomniałem: jeśli uruchomię wideo i nic nie dotknę, duże czerwone X nigdy się nie wyda. Ale w momencie, gdy zaczynam zmieniać pola kombi lub przeciągając sam formularz, szansa dużego czerwonego X rośnie wykładniczo. Czasami mogę przechodzić przez pole kombi 10-12 razy, zanim to się stanie, innym razem zdarza się, że po drugim klikam na combobox. : - \

Czy ktoś może wyjaśnić, co się tutaj dzieje i może zaproponować najlepszą metodę rozwiązania problemu? Nadal jestem bardzo nowy w tworzeniu wątków, więc staram się omijać dokładnie to, co się tutaj dzieje i najlepiej rozwiązać ten problem! Wszelkie trąby w dobrym kierunku będą ogromną pomocą!

+1

Myślę, że prawdopodobnie nie użyłbym pudełka z obrazkami. Zamiast tego użyj panelu i narysuj bitmapę w zdarzeniu farby panelu. Wymuszenie odświeżenia z unieważnieniem. –

+0

Czy obejrzałeś eventArgs.Frame podczas dużego czerwonego senario X? Również umieściłbym messagebox pod tym wyjątkiem, na wypadek gdyby wystąpił błąd. – TheKingDave

+0

Dobra, spróbuję naprawdę szybko! Dodatkowa uwaga: Poszedłem do debugowania -> wyjątki i zaznaczono wszystkie pola wyboru "Zrzucone". Nic tak nie rzuca, kiedy to się dzieje. W ogóle. –

Odpowiedz

6

W końcu, owinięty wszystko w w Handle_New_Frame w powołaniem. Całkowicie usunął na stałe duży czerwony X problem. > _>

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 
    }); 
} 
+0

Wpadłem na dokładnie to samo, a także starałem się dowiedzieć, co się dzieje, bezskutecznie. Sądzę, że jest to polityka jednowątkowa, ale ja, ponieważ nie mogłem uzyskać żadnych wyjątków ani błędów, poszedłem z twoim podejściem i teraz działa. –

+0

Witam, użyłem tego, ale kiedy próbuję zamknąć videoSource, to nie przestaje i czekać na wydanie zasobu ... Czy masz ten sam problem? – elle0087

1

spróbuj użyć klonu w miejscach, w których używasz bitmapy. Przykład:

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

Mogłoby to również doprowadzić do stanu wyścigu, czy też się mylę? Jeśli dojdzie do przerysowania pomiędzy wyrzuceniem mapy bitowej a sklonowaniem mapy bitowej, pojawi się duży czerwony X. – Hans

+0

@Hans yes, spróbuj użyć mapy bitowej przed utylizacją() – Rsouza

+0

@ Hans możesz sprawdzić kod w mojej odpowiedzi? Próbowałem wygenerować taki stan wyścigu, ale nie był w stanie. –

3

Shawn Hargreaves ma doskonałe, zwięzłe writeup z "wielkim czerwonym X zagłady". Znalazłem to bardzo pomocne w ogólnym przypadku radzenia sobie z komponentami WinForm nagle pokazując czerwony "X".

Podsumowując:

  • Spowodowane jest kontrola rzuca wyjątek z imprezy OnPaint.
  • Gdy jest wyrzucane, że kontrola będzie nadal pokazują czerwony X i pominąć wypalania OnPaint.
  • do debugowania, ustawić debugera do połowu wyjątków Common Language Runtime, a następnie zrobić cokolwiek normalnie zrobić, aby dostać czerwoną X. Debugger zatrzyma się dokładnie tam, gdzie się dzieje, co pozwoli ci zbadać i, miejmy nadzieję, znaleźć sposób, aby temu zapobiec.
0

Podsumowując, jest to testowane minimum, które nie pokazuje mi czerwonego krzyża, nawet po zmianie rozmiaru, rozpoczęcia, zakończenia lub rozdzielczości.

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); 
     }); 
     } 
    } 

Należy pamiętać, że nazywamy videoSource.Start(); z GUI- (tworzenie) -thread, ale wywołanie obsługi wywołania (Handle_Very_New_Frame) jest wywoływana z wątku wideo (pracownik).

Myślę, że właśnie dlatego potrzebujemy zarówno Invoke, jak i nowej bitmapy, więc nowa bmp będzie również generowana z wątku GUI. Ale zgaduję, bo nie mogłem wymyślić dowodu.

+0

BTW: Porzuciłem to podejście z oczywistych względów dość szybko :-) –

+0

cześć, użyłem go, ale kiedy próbuję zamknąć videoSource, to nie przestaje i pozostaje czekać na wydanie zasobu ... Czy masz ten sam problem? – elle0087

Powiązane problemy