學習筆記之——Opencv視訊處理模組
阿新 • • 發佈:2018-11-03
視訊訊號是重要的視覺資訊來源。視訊由一系列影象構成,這些影象稱為幀。幀以固定的時間間隔獲取(稱為幀速率,通常用幀/秒表示)。大多數計算機視覺方面的應用都是基於視訊來處理的,為此本博文作為Opencv視訊處理模組的學習筆記~
幀的資料型別也是Mat。
讀取視訊序列。要從視訊序列讀取幀,只需建立一個cv::VideoCapture類的例項,然後再一個迴圈中提取並顯示視訊的每幀,如下面程式碼所示:
#include<opencv2\core\core.hpp> #include<opencv2\highgui\highgui.hpp> #include<iostream> using namespace cv; using namespace std; int main() { //開啟視訊檔案。建立VideoCapture類物件capture,用初始化為括號裡的視訊(VideoCapture類的建構函式)。 //VideoCapture capture("video.mp4");//建立VideoCapture類物件capture //或 VideoCapture capture; capture.open("video.mp4");//VideoCapture類的方法 //0時,開啟usb攝像頭。輸入一個正確的網址,可以載入web上的視訊 //檢查是否開啟成功 if (!capture.isOpened()) { cout << "視訊沒有開啟"<<endl; return 1; } //獲取視訊的幀速率(一般是30或者60) double frame_rate = capture.get(CV_CAP_PROP_FPS); cout << frame_rate << endl; //獲取視訊的總幀數目 long num_frame = static_cast<long>(capture.get(CV_CAP_PROP_FRAME_COUNT)); cout << num_frame << endl; //從特定幀開始 auto position = num_frame/2; capture.set(CV_CAP_PROP_POS_FRAMES, position); Mat frame; namedWindow("提取的視訊"); //根據幀速率計算幀之間的等待時間,單位ms int delat = 1000 / frame_rate; //迴圈遍歷視訊中的全部幀 while (1) { capture >> frame; if (!frame.empty())//如果讀完就結束 { imshow("提取的視訊", frame); } else { break; } waitKey(delat);//要有這句,才會輸出視訊 //在顯示每一幀都採用了延時方法。延時的時長取決於視訊的幀頻率(fps為幀速率,1000/fps為兩幀之間的毫秒數) //通過修改delat的值,可以使視訊快進或慢進 //將delat設定為0,按照使用者按鍵,才播放。 } capture.release();//不是必須的(由於在VideoCapture類的解構函式中已經呼叫了)。用於關閉視訊檔案 return 0; }
具體分析見程式碼註釋。下面再給出一些例程
移動感知(基於光流法)程式碼:
#include<opencv2\video\tracking.hpp> #include<opencv2\highgui\highgui.hpp> #include <opencv2\imgproc.hpp> #include<iostream> using namespace cv; using namespace std; static void drawOptFlowMap(const Mat & flow, Mat & cflowmap, int step, double, const Scalar & color) { for (int y = 0;y < cflowmap.rows;y += step)//光流圖的行,step為步長 { for (int x = 0;x < cflowmap.cols;x += step) { const Point2f & fxy = flow.at<Point2f>(y, x);//關於Point2f類和at操作請見下面程式補充 //移動方向線 line(cflowmap, Point(x, y), Point(cvRound(x + fxy.x), cvRound(y + fxy.y)), color);//cvRound對一個double型的數進行四捨五入,並返回一個整型數 //line函式可見下面程式補充 //綠色固定的點。關於circle函式可見下面程式補充 circle(cflowmap, Point(x, y), 2, color, -1); } } } int main() { //讀入視訊 VideoCapture cap("video.mp4"); if (!cap.isOpened()) { cout << "讀取失敗" << endl; return -1; } Mat prevgray, gray, flow, cflow, frame;//分別為:前一幀灰度圖、當前灰度圖、計算出來的光流圖、前一幀的RGB圖(畫出來的光流)、當前幀 namedWindow("flow", 1); while (1) { cap >> frame; //轉換為灰度圖 cvtColor(frame, gray, COLOR_BGR2GRAY); if (prevgray.data)//uchar型別的指標,指向Mat資料矩陣的首地址。基本就是前一幀影象prevgray有資料,則可以 { //使用Gunnar Farneback演算法計算光流(optical flow)密度 calcOpticalFlowFarneback(prevgray, gray, flow, 0.5, 3, 15, 3, 5, 1.2, 0); cvtColor(prevgray, cflow, COLOR_GRAY2BGR);//將前一幀的灰度圖轉化為RGB圖 //繪製綠點(繪製光流圖) drawOptFlowMap(flow, cflow, 16, 1.5, Scalar(0, 255, 0));//關於Scalar類見下文程式補充。 imshow("flow", cflow); } waitKey(16); //影象交換 swap(prevgray, gray);//其實就是當前幀會成為下一幀的前一幀 } return 0; }
效果如下圖所示:
處理速度比較慢~~~
對上述程式的一些補充:
Opencv中點的表示:Point類
Point point;
point.x=10;
point.y=8;
或者
Point point=Point(10,8);
另外,在OpenCV中有如下定義:
typedef Point_<int> Point2i;
typedef Point2i Point;
typedef Point_<float> Point2f;
at操作:
circle函式:
計算光流的CalcOpticalFlowFarneback() 函式:
關於line函式:
顏色表示,Scalar類:
Scalar()表示具有4個元素的陣列,在Opencv中被大量用於傳遞畫素值,如RGB顏色值。而RGB顏色值為3個引數(第四個引數沒查到)Scalar(a,b,c)紅色分量為c,綠色分量為b,藍色分量為a。