2013-04-15 16 views
9

Ok, ho cercato di fare qualcosa di specifico con il video da una webcam. Ho un microscopio Lumenera Infinity 2 di cui sto cercando di prelevare il feed, e voglio essere in grado di modificare il feed così com'è. Poiché non riuscivo a trovare un modo per farlo usando il Video Source Player, ho deciso di tira ogni fotogramma (max di 15fps per la fotocamera) come bitmap in modo da poter apportare le mie modifiche lì.Perdita di memoria nel codice webcam

Il problema è: ho una perdita di memoria ENORME. Quando eseguo il video usando solo videoSourcePlayer, si aggira sull'utilizzo di circa 30 mega. Quando eseguo il pull dei frame come bitmap, si interrompe 1 gigabyte di memoria in pochi secondi.

Cosa mi manca, qui? Ho pensato che la raccolta automatica dei rifiuti avrebbe recuperato i vecchi fotogrammi non appena fossero diventati inaccessibili. Dovrei provare a forzare la garbage collection su bitmap? O è qualcosa di completamente diverso e mi manca assurdamente.

FilterInfoCollection captureDevices; 
VideoCaptureDevice cam; 
Bitmap bitmap; 

public Form1() 
{ 
    InitializeComponent(); 
} 

private void Form1_Load(object sender, EventArgs e) 
{ 
    try 
    { 
    captureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice); 

    if (captureDevices.Count == 0) 
     throw new ApplicationException(); 

    CameraSelectComboBox.Items.Clear(); 

    foreach (FilterInfo device in captureDevices) 
    { 
     CameraSelectComboBox.Items.Add(device.Name); 
    } 

    CameraSelectComboBox.SelectedIndex = 0; 
    CameraSelectComboBox.Enabled = true; 
    } 
    catch (ApplicationException) 
    { 
    CameraSelectComboBox.Enabled = false; 
    } 
} 

private void connectButton_Click(object sender, EventArgs e) 
{ 
    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); 
    videoSourcePlayer1.Visible = false; 
    cam.Start(); 

    //videoPictureBox1.Visible = false; 
    //videoSourcePlayer1.VideoSource = new VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString); 
    //videoSourcePlayer1.Start(); 
} 

private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs) 
{ 
    bitmap = (Bitmap)eventArgs.Frame.Clone(); 

    videoPictureBox1.Image = bitmap; 
} 
+8

'Bitmap' è' IDisposable' – I4V

+0

Solo una rapida ipotesi: forse l'evento Handle New Frame? sta clonando un frame, quante volte e quanto velocemente viene chiamato questo evento? – Max

+0

Sto assumendo per ogni frame, quindi un massimo di (basato sull'hardware) 15 volte al secondo. Controllerò e assicurarmi che sia la –

risposta

2

Prova questa:

ha risolto alcune delle perdite di memoria che ho sperimentato con Aforge e PictureBoxes, ma il VideoSourcePlayer è molto meglio in cui il consumo di memoria è interessato.

+0

Fantastico! Questo dovrebbe aiutare un sacco! Tuttavia, sto riscontrando un problema con esso, ottenendo un errore di cross thread sul videoPictureBox1.Image.Dispose(). "Operazione cross-thread non valida: controllo 'videoPictureBox1' accessibile da un thread diverso dal thread su cui è stato creato." –

+0

Ti sei imbattuto in questo problema quando stavi lavorando con questo, per caso? –

+0

ah giusto sì, avresti bisogno di usare Invoke. Ho modificato la mia risposta, quindi dovrebbe correggere l'errore cross-thread. –

2

Penso che questo è un settore che può usare miglioramento:

cam = new 
    VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString); 

cam.NewFrame -= Handle_New_Frame; // you're pointing to the new instance of VCD, so this will have no effect. 

cam.NewFrame += new AForge.Video.NewFrameEventHandler(Handle_New_Frame); 
videoSourcePlayer1.Visible = false; 
cam.Start(); 

Questo blocco di codice è il sanguinamento memoria ogni volta che si preme il pulsante di connessione.

Hai praticamente bisogno di avere un riferimento al VCD al livello principale. Quindi definire una variabile membro a livello di classe Form1:

private VideoCaptureDevice _cameraContext; 

E nel gestore evento connect, fare questo:

if (_camerContext != null) 
{ 
    _cameraContext.NewFrame -= Handle_New_Frame; 
} 
_cameraContext = new VideoCaptureDevice(blah blah blah); 
_cameraContext.NewFrame += Handle_New_Frame; 
videoSourcePlayer1.Visible = false; 
_cameraContext.Start(); 

BTW, io ti sto assumendo stai .NET 3.5 o versione successiva, quindi la nuova sintassi dell'assegnazione dei delegati.

+0

Nota: questa è solo una _one_ area di codice che vedo una perdita evidente. Considerando che la perdita di memoria è significativa, è necessario considerare anche come viene smaltita la bitmap. – code4life

+0

Fantastico! Grazie mille per questa informazione. E sì, la tua ipotesi è corretta- Sto usando 4.5 –