2011-12-12 41 views
8

Vorrei chiedere aiuto per ottenere tutti i frame dal file video utilizzando Emgu CV. So che posso usare la classe Capture e il suo metodo QueryFrame(), ma questo restituisce solo un fotogramma. Qual è il modo più semplice per ottenere tutti i frame? (e salvarlo ad esempio su Image<Bgr, Byte>[]) Ho bisogno di tutti i frame per fare un po 'più di elaborazione (per essere più specifici: estrazione dei fotogrammi chiave per il riepilogo dei video).Emgu CV recupera tutti i fotogrammi dal file video

Grazie mille per il vostro aiuto.

risposta

13

Vedere la mia risposta qui per riferimento Emgu Capture plays video super fast

ma questo dovrebbe fare come si chiede ho usato un elenco per archiviare le immagini è possibile utilizzare una matrice, ma è necessario sapere quanto è grande il file AVI è.

Timer My_Time = new Timer(); 
int FPS = 30; 
List<Image<Bgr,Byte>> image_array = new List<Image<Bgr,Byte>>(); 
Capture _capture;  

public Form1() 
{ 
    InitializeComponent(); 

    //Frame Rate 
    My_Timer.Interval = 1000/FPS; 
    My_Timer.Tick += new EventHandler(My_Timer_Tick); 
    My_Timer.Start() 
    _capture = new Capture("test.avi"); 
} 

private void My_Timer_Tick(object sender, EventArgs e) 
{ 
    Image<Bgr, Byte> frame = _capture.QueryFrame(); 
    if (frame != null) 
    { 
     imageBox.Image = _capture.QueryFrame(); 
     image_array.Add(_capture.QueryFrame().Copy()); 
    } 
    else 
    { 
     My_Timer.Stop(); 
    { 
} 

questo è stato progettato per consentire la riproduzione del file video a una velocità responsabile, ma come semplice conversione è possibile utilizzare il metodo Application.Idle altrettanto facilmente come questo ...

List<Image<Bgr,Byte>> image_array = new List<Image<Bgr,Byte>>(); 
Capture _capture; 

public Form1() 
{ 
    InitializeComponent(); 

    //Frame Rate 
    _capture = new Capture("test.avi"); 
    Application.Idle += ProcessFrame; 
} 

private void ProcessFrame(object sender, EventArgs arg) 
{ 
    Image<Bgr, Byte> frame = _capture.QueryFrame(); 
    if (frame != null) 
    { 
     image_array.Add(frame.Copy()); 
    } 
    else 
    { 
     Application.Idle -= ProcessFrame;// treat as end of file 
    } 

} 

È Dovrai fare attenzione alla fine dell'errore del file riceverai un errore. È sempre possibile utilizzare un'istruzione try catch per rilevare l'errore specifico che verrà fornito invece di terminare semplicemente la conversione.

Se si utilizza un array di immagini, è necessario scorrere ciclicamente il file incrementando una variabile e contando i frame e quindi creare l'array di immagini prima di convertire il file video in un array.


[EDIT]

Come richiesto questa è una versione metodo per il recupero di tutti i frame da un file video non ho ancora testato questo su un file video di grandi dimensioni come mi aspetto che il programma potrebbe andare in crash in quanto richiederà molta memoria.

private List<Image<Bgr, Byte>> GetVideoFrames(String Filename) 
    { 
     List<Image<Bgr,Byte>> image_array = new List<Image<Bgr,Byte>>(); 
     Capture _capture = new Capture(Filename); 

     bool Reading = true; 

     while (Reading) 
     { 
      Image<Bgr, Byte> frame = _capture.QueryFrame(); 
      if (frame != null) 
      { 
       image_array.Add(frame.Copy()); 
      } 
      else 
      { 
       Reading = false; 
      } 
     } 

     return image_array; 
    } 

In alternativa mi rendo conto che si potrebbe desiderare di registrare dire 10 secondi di video da una webcam in modo da questo metodo lo farà, ho usato un cronometro come il ciclo il tempo proibisce l'uso di un timer a meno che il multi threading la applicazione

private List<Image<Bgr, Byte>> GetVideoFrames(int Time_millisecounds) 
    { 
     List<Image<Bgr,Byte>> image_array = new List<Image<Bgr,Byte>>(); 
     System.Diagnostics.Stopwatch SW = new System.Diagnostics.Stopwatch(); 

     bool Reading = true; 
     Capture _capture = new Capture(); 
     SW.Start(); 

     while (Reading) 
     { 
      Image<Bgr, Byte> frame = _capture.QueryFrame(); 
      if (frame != null) 
      { 
       image_array.Add(frame.Copy()); 
       if (SW.ElapsedMilliseconds >= Time_millisecounds) Reading = false; 
      } 
      else 
      { 
       Reading = false; 
      } 
     } 

     return image_array; 
    } 

e questo sarebbe stato chiamato in questo modo:

List<Image<Bgr, Byte>> Image_Array = GetVideoFrames(10000); //10 Secounds 

Speranza questo aiuta,

Cheers,

Chris

+0

Grazie, non voglio usarlo in 'Application.Idle'. Voglio semplicemente avere una funzione che posso chiamare ogni volta che voglio e che mi restituisce la lista dei fotogrammi Image dal dato input video. – tom

+0

Ciao ho aggiunto al codice in un metodo che puoi chiamare, spero che questo sia quello che fai dopo se non me lo faccia sapere Cheers – Chris

+0

@Chris puoi aiutarmi http://stackoverflow.com/questions/31259051/detect -hand-da-web-camera-emgu-cv – gihansalith

0

Anche ho affrontato lo stesso issue.So i inizializzato un altro timer e fornito il video salvare codice there.And questo timer è abilitato solo quando il pulsante di registrazione [ Viene cliccato il pulsante sul modulo su cui è stato registrato il video]. Ora posso acquisire video ma l'audio non viene registrato.

Problemi correlati