1. 程式人生 > >基於幀間差分法的運動目標檢測

基於幀間差分法的運動目標檢測

環境 win7 + vs2015 + Opencv2.4.13

一、運動目標一般涉及一下物件:  

 1)運動目標:需要研究的運動物體; 

 2)背景噪聲:沒有被檢測出來的運動目標區域。 

 3)前景噪聲:前景噪聲是指被認定已發生了影象變化,然而並不包含任何運動目標的區域。 

 4)反射:在物體的邊緣,或反射能力強的物體(如地板,鋼管等)表面,由於光線極其不穩定而被當成變化物體檢測出來。 

 5)陰影:運動目標在地面等物體上產生陰影,也被當成運動目標檢測出來。

 6)鬼影:過去某時刻的運動目標進入背景模型,在當前時刻被當成運動目標檢測出來。 

 7)干擾:對檢測結果可能產生影響的因素,如攝像機自身抖動、以及背景中出現的運動的物體,如晃動的樹木,閃爍的顯示屏,噴泉等。


二、原理

    攝像機採集的視訊序列具有連續性的特點。如果場景內沒有運動目標,則連續幀的變化很微弱,如果存在運動目標,則連續的幀和幀之間會有明顯地變化。

    幀間差分法就是借鑑了上述思想。由於場景中的目標在運動,目標的影像在不同影象幀中的位置不同。該類演算法對時間上連續的兩幀或三幀影象進行差分運算,不同幀對應的畫素點相減,判斷灰度差的絕對值,當絕對值超過一定閾值時,即可判斷為運動目標,從而實現目標的檢測功能


程式碼實現

#include "opencv2/opencv.hpp"  
#include <iostream>  
using namespace cv;
using namespace std;

//運動物體檢測函式
Mat MoveDetect(Mat temp, Mat frame);

int main(int argc, char** argv)
{

	VideoCapture video("video.avi");//定義VideoCapture類video  

	Mat frame;//儲存幀  
	Mat temp;//儲存前一幀影象  
	Mat result;//儲存結果影象  

	int i = 0;

	while (1) {
		video >> frame;//讀幀進frame  
		imshow("frame", frame);
		waitKey(30);


		if (i == 0)//如果為第一幀(temp還為空)  
		{
			result = MoveDetect(frame, frame);//呼叫MoveDetect()進行運動物體檢測,返回值存入result  
			i++;
		}
		else//若不是第一幀(temp有值了)  
		{
			result = MoveDetect(temp, frame);//呼叫MoveDetect()進行運動物體檢測,返回值存入result  

		}
		imshow("result", result);

		temp = frame.clone();
	}

	return 0;
}
Mat MoveDetect(Mat temp, Mat frame)
{
	Mat result = frame.clone();
	//1.將background和frame轉為灰度圖  
	Mat gray1, gray2;
	cvtColor(temp, gray1, CV_BGR2GRAY);
	cvtColor(frame, gray2, CV_BGR2GRAY);
	//2.將background和frame做差  
	Mat diff;
	absdiff(gray1, gray2, diff);
	imshow("diff", diff);
	//3.對差值圖diff_thresh進行閾值化處理  
	Mat diff_thresh;
	threshold(diff, diff_thresh, 10, 255, CV_THRESH_BINARY);
	imshow("diff_thresh", diff_thresh);

	GaussianBlur(diff_thresh, diff_thresh, Size(3, 3), 0, 0);

	//4.腐蝕  
	Mat kernel_erode = getStructuringElement(MORPH_RECT, Size(3, 3));
	Mat kernel_dilate = getStructuringElement(MORPH_RECT, Size(5, 5));
	erode(diff_thresh, diff_thresh, kernel_erode);
	//imshow("erode", diff_thresh);
	//5.膨脹  
	dilate(diff_thresh, diff_thresh, kernel_dilate);
	imshow("dilate", diff_thresh);
	//6.查詢輪廓並繪製輪廓  
	vector<vector<Point>> contours;
	findContours(diff_thresh, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
	//drawContours(result, contours, -1, Scalar(0, 0, 255), 2);//在result上繪製輪廓  
	//7.查詢正外接矩形  
	vector<Rect> boundRect(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		boundRect[i] = boundingRect(contours[i]);
		rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);//在result上繪製正外接矩形  
	}
	return result;//返回result  
}