opencv實現(xiàn)三幀差法解析
今天和大家談?wù)勅龓罘▉韺崿F(xiàn)運動目標(biāo)檢測吧,其中運動檢測畫框?qū)崿F(xiàn)追蹤方法多種多樣,大家可以自行百度,后面我也會一一實現(xiàn),今天我先給大家玩玩三幀差法吧;;;;(注釋非常清楚哦,程序也極其簡單的)
幀差法是最為常用的運動目標(biāo)檢測和分割方法之一,基本原理就是在圖像序列相鄰兩幀或三幀間采用基于像素的時間差分通過閉值化來提取出圖像中的運動區(qū)域。首先,將相鄰幀圖像對應(yīng)像素值相減得到差分圖像,然后對差分圖像二值化,在環(huán)境亮度變化不大的情況下,如果對應(yīng)像素值變化小于事先確定的閡值時,可以認(rèn)為此處為背景像素:如果圖像區(qū)域的像素值變化很大,可以認(rèn)為這是由于圖像中運動物體引起的,將這些區(qū)域標(biāo)記為前景像素,利用標(biāo)記的像素區(qū)域可以確定運動目標(biāo)在圖像中的位置。由于相鄰兩幀間的時間間隔非常短,用前一幀圖像作為當(dāng)前幀的背景模型具有較好的實時性,其背景不積累,且更新速度快、算法簡單、計算量小。算法的不足在于對環(huán)境噪聲較為敏感,閩值的選擇相當(dāng)關(guān)鍵,選擇過低不足以抑制圖像中的噪聲,過高則忽略了圖像中有用的變化。對于比較大的、顏色一致的運動目標(biāo),有可能在目標(biāo)內(nèi)部產(chǎn)生空洞,無法完整地提取運動目標(biāo)。
簡單說一下程序思路哈,參考了一下opencv官網(wǎng)教程
#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;
//用于保存當(dāng)前幀的圖片
Mat currentBGRFrame;
//用來保存上一幀和當(dāng)前幀的灰度圖片
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);
//幀數(shù)
int numberFrame = 0;
//形態(tài)學(xué)處理用到的算子
Mat morphologyKernel = getStructuringElement(MORPH_RECT,Size(3,3),Point(-1,-1));
for(;;)
{ //讀取當(dāng)前幀
video >> currentBGRFrame;
//判斷當(dāng)前幀是否存在
if(!currentBGRFrame.data)
break;
numberFrame++;
//顏色空間的轉(zhuǎn)換
cvtColor(currentBGRFrame,currentGaryFrame,COLOR_BGR2GRAY);
if( numberFrame == 1) {
//保存當(dāng)前幀的灰度圖
previousSecondGrayFrame = currentGaryFrame.clone();
//顯示視頻
imshow("video",currentBGRFrame); continue; }
else if( numberFrame == 2)
{
//保存當(dāng)前幀的灰度圖
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,Mat(),CV_16SC1);
//取絕對值
absFrameDifferece = abs(currentFrameDifference);
//位深的改變 absFrameDifferece.convertTo(absFrameDifferece,CV_8UC1,1,0);
//閾值處理
threshold(absFrameDifferece,currentSegmentation,double(thresh),double(FORE_GROUD),THRESH_BINARY); //與運算
bitwise_and(previousSegmentation,currentSegmentation,segmentation); //中值濾波
medianBlur(segmentation,segmentation,3); //形態(tài)學(xué)處理(開閉運算)
//morphologyEx(segmentation,segmentation,MORPH_OPEN,morphologyKernel,Point(-1,-1),1,BORDER_REPLICATE);
morphologyEx(segmentation,segmentation,MORPH_CLOSE,morphologyKernel,Point(-1,-1),2,BORDER_REPLICATE);
//找邊界
vector< vector<oint> > contours;
vector<Vec4i> hierarchy;
//復(fù)制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);
//保存當(dāng)前幀的灰度圖
previousFirstGrayFrame = currentGaryFrame.clone();
//保存當(dāng)前的前景檢測
previousSegmentation = currentSegmentation.clone();
}
if(waitKey(33) == 'q')
break;
}
return 0;
}
編譯之后,運行./main.cpp **.avi
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
深入C++拷貝構(gòu)造函數(shù)的總結(jié)詳解
本篇文章是對C++中拷貝構(gòu)造函數(shù)進(jìn)行了總結(jié)與介紹。需要的朋友參考下2013-05-05

