2011-12-12 49 views
8

我想請您幫助我使用Emgu CV獲取視頻文件中的所有幀。我知道我可以使用Capture類和它的QueryFrame()方法,但是這隻返回一個幀。獲取所有幀的最簡單方法是什麼? (並將其保存到例如Image<Bgr, Byte>[])我需要所有幀進行更多處理(更具體地說:視頻摘要的關鍵幀提取)。Emgu CV從視頻文件中獲取所有幀

非常感謝您的幫助。

回答

13

見我的答案在這裏以供參考Emgu Capture plays video super fast

但是當你問我用一個列表來存儲您可以使用數組的圖片,但你需要知道你的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(); 
    { 
} 

這被設計爲允許在播放視頻文件以一個負責任的速度,但作爲簡單的轉換,你可以很容易地像這樣使用Application.Idle方法...

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 
    } 

} 

你必須小心文件錯誤的結束,否則您將收到錯誤。您總是可以使用try catch語句來捕獲它將給出的具體錯誤,而不是簡單地終止轉換。

如果您使用圖像數組,您將不得不遍歷文件遞增變量並計數幀,然後在將視頻文件轉換爲數組之前創建圖像數組。


[編輯]

按照要求,這是從視頻文件中檢索所有幀的方法的版本,因爲我預計該計劃將自崩潰我還沒有一個大的視頻文件測試這它將需要大量的內存。

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

或者我知道你可能希望記錄說視頻10秒從攝像頭所以這種方法能做到這一點,我用秒錶作爲while循環禁止使用定時器,除非你的多線程化應用

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

,這將被稱爲像這樣:

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

希望這可以幫助,

乾杯,

克里斯

+0

謝謝,我只是不想在'Application.Idle'中使用它。我只想擁有一個我可以隨時撥打的功能,它會返回給定視頻輸入的圖像列表。 – tom

+0

嗨我已經添加到可以調用的方法中的代碼,我希望這是你的後,如果不讓我知道乾杯 – Chris

+0

@Chris你能幫我嗎 http://stackoverflow.com/questions/31259051/detect - 手 - 從 - 網絡攝像頭 - emgu-CV – gihansalith

0

即使我面臨着同樣的issue.So我初始化另一個定時器和提供的視頻保存代碼there.And該定時器啓動,只有當錄音鍵[單擊錄製視頻時窗體上的按鈕]被點擊。現在,我可以捕捉視頻,但音頻沒有被錄製。