opencv實現三幀差法解析
阿新 • • 發佈:2020-03-23
今天和大家談談三幀差法來實現運動目標檢測吧,其中運動檢測畫框實現追蹤方法多種多樣,大家可以自行百度,後面我也會一一實現,今天我先給大家玩玩三幀差法吧;;;;(註釋非常清楚哦,程式也極其簡單的)
幀差法是最為常用的運動目標檢測和分割方法之一,基本原理就是在影象序列相鄰兩幀或三幀間採用基於畫素的時間差分通過閉值化來提取出影象中的運動區域。首先,將相鄰幀影象對應畫素值相減得到差分影象,然後對差分影象二值化,在環境亮度變化不大的情況下,如果對應畫素值變化小於事先確定的閡值時,可以認為此處為背景畫素:如果影象區域的畫素值變化很大,可以認為這是由於影象中運動物體引起的,將這些區域標記為前景畫素,利用標記的畫素區域可以確定運動目標在影象中的位置。由於相鄰兩幀間的時間間隔非常短,用前一幀影象作為當前幀的背景模型具有較好的實時性,其背景不積累,且更新速度快、演算法簡單、計算量小。演算法的不足在於對環境噪聲較為敏感,閩值的選擇相當關鍵,選擇過低不足以抑制影象中的噪聲,過高則忽略了影象中有用的變化。對於比較大的、顏色一致的運動目標,有可能在目標內部產生空洞,無法完整地提取運動目標。
簡單說一下程式思路哈,參考了一下opencv官網教程
#include<iostream> #include<opencv2\core\core.hpp> #include<opencv2\highgui\highgui.hpp> #include<opencv2\imgproc\imgproc.hpp> using namespace cv; using namespace std; const unsigned char FORE_GROUD = 255;int thresh = 10; int main(int argc,char*argv[]) { VideoCapture video(argv[1]); //判斷如果video是否可以開啟 if(!video.isOpened()) return -1; //用於儲存當前幀的圖片 Mat currentBGRFrame; //用來儲存上一幀和當前幀的灰度圖片 Mat previousSecondGrayFrame; Mat previousFirstGrayFrame; Mat currentGaryFrame; //儲存兩次的幀差 Mat previousFrameDifference; //previousFrameFirst - previousFrameSecond的差分 Mat currentFrameDifference; //currentFrame - previousFrameFirst; //用來儲存幀差的絕對值 Mat absFrameDifferece; //用來顯示前景 Mat previousSegmentation; Mat currentSegmentation; Mat segmentation; //顯示前景 namedWindow("segmentation",1); createTrackbar("閾值:","segmentation",&thresh,FORE_GROUD,NULL); //幀數 int numberFrame = 0; //形態學處理用到的運算元 Mat morphologyKernel = getStructuringElement(MORPH_RECT,Size(3,3),Point(-1,-1)); for(;;) { //讀取當前幀 video >> currentBGRFrame; //判斷當前幀是否存在 if(!currentBGRFrame.data) break; numberFrame++; //顏色空間的轉換 cvtColor(currentBGRFrame,currentGaryFrame,COLOR_BGR2GRAY); if( numberFrame == 1) { //儲存當前幀的灰度圖 previousSecondGrayFrame = currentGaryFrame.clone(); //顯示視訊 imshow("video",currentBGRFrame); continue; } else if( numberFrame == 2) { //儲存當前幀的灰度圖 previousFirstGrayFrame = currentGaryFrame.clone(); //previousFirst - previousSecond subtract(previousFirstGrayFrame,previousSecondGrayFrame,previousFrameDifference,Mat(),CV_16SC1); //取絕對值 absFrameDifferece = abs(previousFrameDifference); //位深的改變 absFrameDifferece.convertTo(absFrameDifferece,CV_8UC1,1,0); //閾值處理 threshold(absFrameDifferece,previousSegmentation,double(thresh),double(FORE_GROUD),THRESH_BINARY); //顯示視訊 imshow("video",currentBGRFrame); continue; } else { //src1-src2 subtract(currentGaryFrame,previousFirstGrayFrame,currentFrameDifference,CV_16SC1); //取絕對值 absFrameDifferece = abs(currentFrameDifference); //位深的改變 absFrameDifferece.convertTo(absFrameDifferece,0); //閾值處理 threshold(absFrameDifferece,currentSegmentation,THRESH_BINARY); //與運算 bitwise_and(previousSegmentation,segmentation); //中值濾波 medianBlur(segmentation,segmentation,3); //形態學處理(開閉運算) //morphologyEx(segmentation,MORPH_OPEN,morphologyKernel,-1),BORDER_REPLICATE); morphologyEx(segmentation,MORPH_CLOSE,2,BORDER_REPLICATE); //找邊界 vector< vector<oint> > contours; vector<Vec4i> hierarchy; //複製segmentation Mat tempSegmentation = segmentation.clone(); findContours( segmentation,contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0) );//CV_RETR_TREE vector< vector<oint> > contours_poly( contours.size() ); /*儲存運動物體*/ vector<Rect> boundRect; boundRect.clear(); //畫出運動物體 for(int index = 0;index < contours.size() ;index++) { approxPolyDP( Mat(contours[index]),contours_poly[index],3,true ); Rect rect = boundingRect( Mat(contours_poly[index]) ); rectangle(currentBGRFrame,rect,Scalar(0,255,255),2); } //顯示視訊 imshow("video",currentBGRFrame); //前景檢測 imshow("segmentation",segmentation); //儲存當前幀的灰度圖 previousFirstGrayFrame = currentGaryFrame.clone(); //儲存當前的前景檢測 previousSegmentation = currentSegmentation.clone(); } if(waitKey(33) == 'q') break; } return 0; }
編譯之後,執行./main.cpp **.avi
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。