2013-04-17 25 views
8

Attualmente sto lavorando con AForge e ho un nuovo evento frame che inserisce il frame, come bitmap, in una picturebox. Il 90% delle volte funziona alla grande ... A MENO CHE non mangio qualcosa sulla winform. Modifica di una casella combinata, spostando la finestra, o qualcosa di simile rischia di causare il Picturebox per passare dal video per un grande campione di rosso X. Code di seguito:Picturebox diventa rosso grande X ma non riesco a rilevarlo o correggerlo

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

ho messo una pausa sul se (videoPictureBox1.Image == videoPictureBox1.ErrorImage) e sta valutando false, anche quando la grande X rossa è attiva, perché l'immagine viene effettivamente impostata sulla bitmap. Quindi cam.Stop() e cam.Start() non hanno mai funzionato (non sono sicuro se ciò sarebbe di aiuto, ma ho pensato di fare un tentativo).

videoPictureBox1.Refresh() è in esecuzione ogni volta, ma ancora una volta- non fa la differenza. Ancora il grande rosso X.

Come ho detto prima: se avvio il video e non tocco nulla, la grande X rossa non accadrà mai. Ma nel momento in cui comincio a cambiare le caselle combinate, o trascinando il modulo stesso in giro, le possibilità della grande X rossa aumentano esponenzialmente. A volte riesco a sfogliare la casella combinata 10-12 volte prima che accada, altre volte succede il secondo quando clicco sulla casella combinata. : - \

Qualcuno può spiegare cosa sta succedendo qui e forse offrire un suggerimento sul metodo migliore per risolvere il problema? Sono ancora molto nuovo al threading, quindi mi sono sforzato di capire esattamente cosa sta succedendo qui e il modo migliore per risolvere il problema! Qualsiasi suggerimento nella giusta direzione sarebbe di grande aiuto!

+1

Penso che probabilmente non userò una scatola di immagini. Usa invece un pannello e disegna la bitmap nell'evento paint del pannello. Forzare un aggiornamento con invalidare. –

+0

Hai visto l'eventArgs.Frame durante il grande X senario rosso? Inoltre metterei una messagebox sotto quell'eccezione nel caso in cui è dove si verifica l'errore. – TheKingDave

+0

Va bene, ti darò una prova davvero veloce! Un'ulteriore nota: sono andato a eseguire il debug -> eccezioni e ho controllato tutte le caselle di controllo "generate". Nulla getta quando ciò accade. Affatto. –

risposta

6

Alla fine, avvolto in TUTTO nel Handle_New_Frame in invocare. Ha rimosso completamente il grande problema X rosso, in modo permanente. > _>

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

Mi sono imbattuto nella stessa identica cosa e ho anche cercato di capire cosa sta succedendo, senza successo. Immagino che sia una politica a thread singolo, ma non potendo ottenere eccezioni o errori di sorta, sono andato con il tuo approccio e ora funziona. –

+0

ciao, l'ho usato, ma quando provo a chiudere videoSource non si ferma e resta in attesa di rilasciare la risorsa ... hai lo stesso problema? – elle0087

1

provare a utilizzare il clone nei punti in cui si utilizza la bitmap. Es:

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

Questo potrebbe anche portare a una condizione di competizione o sbaglio? Se si verifica un nuovo aggiornamento tra la disposizione della bitmap e la clonazione della bitmap, verrà visualizzata la X rossa grande. – Hans

+0

@Hans sì, provare a utilizzare la bitmap prima di disporne() – Rsouza

+0

@Hans potresti verificare il codice nella mia risposta? Ho provato a generare una tale condizione di competizione ma non sono riuscito a farlo. –

3

Shawn Hargreaves ha un ottimo, concisa writeup della "grande X rossa di sventura". L'ho trovato molto utile nel caso generale di gestione dei componenti WinForm che mostravano improvvisamente la "X" rossa.

In sintesi:

  • Questo è causato da un controllo un'eccezione fuori della manifestazione OnPaint.
  • Una volta che si getta, che il controllo continuerà a mostrare la X rossa e saltare sparare OnPaint.
  • Per eseguire il debug, impostare il debugger per intercettare le eccezioni Common Language Runtime, e poi fare tutto ciò che si fa normalmente per ottenere la X rossa Il debugger si fermerà esattamente dove sta accadendo, permettendoti di investigare e, si spera, di trovare un modo per prevenirlo.
0

Solo per riassumere, questo è un minimo indispensabile testato che non mostra alcuna croce rossa per me, anche quando ridimensionato, avviato, arrestato o risoluzione modificata.

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

Si prega di notare che si chiama videoSource.Start(); dal GUI- (creation) -thread, ma il callback handler (Handle_Very_New_Frame) viene chiamato dal thread video (worker).

Penso che sia per questo che abbiamo bisogno di entrambi, l'Invoke e la nuova Bitmap, quindi il nuovo bmp verrà generato anche dal gui-thread. Ma sto solo indovinando qui, perché non sono riuscito a trovare una dimostrazione.

+0

BTW: Ho abbandonato questo approccio per ovvi motivi abbastanza rapidamente :-) –

+0

ciao, l'ho usato, ma quando provo a chiudere videoSource non si ferma e resta in attesa di rilasciare la risorsa ... hai avuto lo stesso problema? – elle0087