2013年8月30日 星期五

EmguCV Image Process: Process Video Sequences part 1


EmguCV Image Process: Process Video Sequences

參考OpenCV 2 Computer Vision Application Programming Cookbook第十章

介紹內容如下:

Reading video sequences

Processing the video frames

Writing video sequences

Tracking feature points in video

Extracting the foreground objects in video

這次要來介紹如何透過EmguCV來處理視訊檔案

在視訊的訊號中,包含了連續的影像

稱之為:frame

frame與frame之間的固定間隔時間則稱為:frame rate

當這些frame在非常快速的變換之下

內容看起來就像是會動一樣

但其實這過程只是將一張一張的frame不斷地呈現出來而已

過去受限於電腦硬體,要處理視訊檔案是非常棘手的一件事

但由於現在電腦的強度越來越強,速度越來越快

視訊處理已經變得越來越熱門,也越來越容易

本章節將會介紹如何讀取、控制、儲存影片視訊檔案


透過EmguCV中capture這個類別

可以非常簡單的取出影片的frame

甚至還提供了許多基本的控制功能,相當實用

下面來看如何取出frame

//Open the video file
Capture capture = new Capture(@"video.avi");
            
//Get the frame rate
double rate = capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FPS);

//Delay between each frame in ms
//corresponds to video frame rate
int delay = (int)(1000 / rate);
bool stop = false;
//current video frame
Image<Bgr, Byte> frame;
string windowTitle = "video window";
CvInvoke.cvNamedWindow(windowTitle);
while (!stop)
{
    //read next frame if any
    frame = capture.QueryFrame();  
    if (frame == null)
    {
        break;
    }

    CvInvoke.cvShowImage(windowTitle, frame);

    //introduce a delay
    //or press key to stop
    if (CvInvoke.cvWaitKey(delay) >= 0)
    {
        stop = true;
    }
}
CvInvoke.cvDestroyWindow(windowTitle);
//Close the video file.
//Not required since called by destructor
capture.Dispose();
這邊先建立一個Capture的類別

建構式中帶入視訊檔案的完整錄影檔名

然後去取出這段影片的frame rate
(capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FPS))

利用一個while迴圈

不斷的去呼叫capture.QueryFrame()取出最新的一張frame

直到影片播完,取不到frame時,就跳出while

這裡利用CvInvoke.cvNamedWindow(windowTitle)建立一個視窗

利用這個視窗來顯示frame

透過指定window的title來顯示CvInvoke.cvShowImage(windowTitle, frame);

並做frame與frame之間的延遲,CvInvoke.cvWaitKey(delay)

顯示結果就像這樣:

可以看到左上方的title為video window


Capture這個類別提供了很多功能可玩

像是可以取出整部影片的所有frame數量

double totalFrames = capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_COUNT);

那也可以取出當前的frame的index

也可以跳到你指定的index來撥放

這兩個方法搭配起來,就可以實作快轉的功能

double frameCount = capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_POS_FRAMES);
capture.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_POS_FRAMES, frameCount + 30);

將每次frame播完後就往後跳30張frame的快轉!!


Capture提供的功能很多

有興趣的人可以到EmguCV官網的文件查詢

而這個功能還可以擷取電腦上的USB camera,或是筆電上的web cam

只要在Capture的建構式不帶入參數,或是帶入index

代表第一支camera、第二支camera等

Capture capture = new Capture();
或是
Capture capture = new Capture(0);

都是取出預設第一支camera

有一點要提醒的是

USB camera跟web cam是沒有所謂的FPS

所以在 capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FPS)

取出來的值會為0

因此可將那段程式碼改成

int delay = (rate > 0) ? (int)(1000 / rate) : 1;

這樣就沒問題啦!!


下一篇將介紹如何透過包裝來彈性的處理視訊檔案

沒有留言:

張貼留言