OpenCv學習筆記——OpenCV捕獲視訊
本文講一下如何捕獲視訊。
從檔案中捕獲視訊
其實使用OpenCV讀取視訊相當簡單,只需要初始化一個VideoCapture物件,開啟視訊檔案,逐幀讀取。
程式
下面是簡單的OpenCV程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#include <opencv2\highgui\highgui.hpp>
#include <iostream> using
namespace
cv;
using
namespace
std;
int
main( int
argc, char
**argv)
{
//開啟視訊檔案
VideoCapture cap( "Girls'Generation.avi" );
if
(!cap.isOpened())
{
cout << "不能開啟視訊檔案"
<< endl;
return
-1;
}
//從3000ms開始播放視訊
//cap.set(CV_CAP_PROP_POS_MSEC, 3000);
//獲取視訊的幀速率
double
fps = cap.get(CV_CAP_PROP_FPS);
cout << "幀/秒:"
<< fps << endl;
namedWindow( "MyVideo" ,CV_WINDOW_AUTOSIZE);
while
( true )
{
Mat frame;
//從視訊中讀取一個幀
bool
bSuccess = cap.read(frame);
if
(!bSuccess)
{
cout << "不能從視訊檔案讀取幀" << endl;
break ;
}
//在MyVideo視窗上顯示當前幀
imshow( "MyVideo" , frame);
//如果30ms沒有按下鍵,就返回-1,當按下ESC鍵返回27
if
(waitKey(30)==27) {
cout << "按下ESC鍵"
<< endl;
break ;
}
}
return
0;
}
|
解釋
1 |
VideoCapture::VideoCapture( const
string& filename)
|
這是VideoCapture類為數不多的建構函式的一個。這個建構函式開啟視訊檔案併為讀取視訊流初始化VideoCapture物件。
這個類的解構函式會釋放物件關聯的所有記憶體。因此,不需要在程式中顯示的釋放記憶體。
1 |
bool
VideoCapture::IsOpened()
|
如果呼叫VideoCapture建構函式成功,這個方法返回true,否則返回false。
檢查VideoCapture初始化是否成功是有必要的。如果失敗,程式應該退出,否則當從VideoObject中讀取幀的時候,程式就會崩潰了。
1 |
bool
VideoCapture::set( int
propId, double
value)
|
這個方法改變VideoObject物件的屬性,如果成功,返回true,否則返回false。你應該在你的程式碼中嘗試修改視訊流的一些屬性。在我的程式碼中,我改變了CV_CAP_PROP_POS_MSEC屬性。
它的引數:
- int propID – 這個引數指定你要更改的屬性。這個引數有很多可選項,這裡列出一部分。
- CV_CAP_PROP_POS_MSEC – 視訊的當前位置(毫秒)
- CV_CAP_PROP_POS_FRAMES – 視訊的當前位置(幀)
- CV_CAP_PROP_FRAME_WIDTH – 視訊流的寬度
- CV_CAP_PROP_FRAME_HEIGHT – 視訊流的高度
- CV_CAP_PROP_FPS – 幀速率(幀/秒)
- CV_CAP_PROP_FOURCC – 編碼器的四字元編碼
- double value – 給propID分配的值。
1 |
doubleVideoCapture::get( int
propId)
|
這個函式返回指定的propId的屬性值。它的可選項和set函式的propID一樣。
1 |
bool
VideoCapture::read(Mat& image);
|
這個函式抓取視訊的下一幀,解碼並存儲在‘image’變數中。在這個函式內部會呼叫VideoCapture::grap()和VideoCapture::retrieve()。可以使用這2個函式代替VideoCapture::read()函式。如果操作成功,返回true,否則返回false。
1 |
waitKey(30)
|
這個函式等待30毫秒。如果在指定的時間按下鍵,它會返回鍵的ASCII值。如果這個值是27,程式就會執行if塊。如果在30毫秒內沒有按下鍵,程式返回-1,程式繼續while迴圈。
1 |
VideoCapture::~VideoCapture()
|
VideoCapture物件的解構函式會釋放物件所有關聯的記憶體。在程式退出main方法時,解構函式會隱式呼叫。
總結
首先,這個程式從檔案中捕獲一個視訊,然後進入一個無限迴圈。在這個迴圈中,它從捕獲的視訊中連續地抓取幀,解碼,然後顯示在視窗中並等待30毫秒。如果視訊沒有更多的幀或按下了ESC鍵,程式就會跳出無限迴圈。
注意:使用waitKey(int)函式非常重要,因為imshow(string&, MAT)函式需要時間在視窗上繪製圖像,正是waitKey(int)提供了這個時間。
從攝像頭中採集視訊
程式
下面的程式和上面的最大不同是VideoCapture建構函式的引數。這裡我給VideoCapture的建構函式提供攝像頭的編號來代替一個檔名。下面是OpenCV程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
#include <opencv2\highgui\highgui.hpp>
#include <iostream>
using
namespace
cv;
using
namespace
std;
int
main( int
argc, char
**argv)
{
// 開啟第1個攝像頭
VideoCapture cap(0);
if
(!cap.isOpened())
{
cout << "不能開啟攝像頭!"
<< endl;
return
-1;
}
//獲取視訊幀的寬度
double
dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH);
//獲取視訊幀的高度
double
dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cout << "視訊幀尺寸 : "
<< dWidth << " x "
<< dHeight << endl;
namedWindow( "MyVideo" , CV_WINDOW_AUTOSIZE);
while
(1)
{
Mat frame;
bool
bSuccess = cap.read(frame);
if
(!bSuccess)
{
cout << "不能從視訊流中讀取幀!"
<< endl;
break ;
}
imshow( "MyVideo" , frame);
if
(waitKey(30) == 27)
{
cout << "ESC鍵被按下"
<< endl;
break ;
}
}
return
0;
}
|
解釋
1 |
VideoCapture::VideoCapture( int
device)
|
這是VideoCapture 3個建構函式的一個。這個建構函式開啟給定編號的攝像頭併為讀取攝像頭的視訊流初始化VideoCapture物件。這裡的“0”表示使用編號為0的攝像頭。如果你的電腦上有多個攝像頭,可以使用1,2,3…代替0。
1 |
double
dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH)
|
這個函式獲取攝像頭輸出幀的寬(畫素)
1 |
double
dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT)
|
這個函式獲取攝像頭輸出幀的高(畫素)
其他所有的函式都跟第一個程式中一樣。