1. 程式人生 > >學習筆記之——Opencv視訊處理模組

學習筆記之——Opencv視訊處理模組

視訊訊號是重要的視覺資訊來源。視訊由一系列影象構成,這些影象稱為。幀以固定的時間間隔獲取(稱為幀速率,通常用幀/秒表示)。大多數計算機視覺方面的應用都是基於視訊來處理的,為此本博文作為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。