基於幀間差分法的運動目標檢測
阿新 • • 發佈:2019-02-17
環境 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 }