📄 single-gaussian model for the algorithm to do the moving target detection.cpp
字号:
/************************************************** * 背景建模,运动物体检测 * **************************************************/#ifdef _CH_
#pragma package <opencv>
#endif
#ifndef _EiC
#include <stdio.h>#include <cv.h>#include <cxcore.h>#include <highgui.h>
#include <ctype.h>
#endif
#define FALSE 0
#define TRUE 1
#define EPS 1e-6
#define SQUARE(x) ((x) * (x))
#define ZERO(x) (fabs((x)) < EPS ? TRUE : FALSE)
#define LearnFrame 20
#define NUM 20
#define PARAMETER 2.0
IplConvKernel* element = 0;
const int element_shape = CV_SHAPE_RECT;
//形态学滤波函数操作
void Opening(IplImage* src, IplImage* image, IplImage* dest, int pos);
void Closing(IplImage* src, IplImage* image, IplImage* dest, int pos);
void Erosion(IplImage* src, IplImage* dest, int pos);
void Dilation(IplImage* src, IplImage* dest, int pos);
CvMemStorage* storage = 0; // temporary storage
int i;
CvPoint pt;
CvPoint pre_pt;
int N;
int main( ){ //声明当前帧IplImage指针 IplImage* pFrame = NULL; IplImage* pFrImg = NULL; IplImage* pBkImg = NULL;
IplImage* pCurImg = NULL;
IplImage* pFirstImg = NULL;
IplImage* pTempImg = NULL; CvMat* MeanValue = NULL;
CvMat* SigmaValue = NULL;
CvMat* NumBack = NULL;
IplImage** buf = NULL;
CvCapture* Capture = NULL; int nFrmNum = 0;
int i,j,w,x;
double temp[NUM];
int countframe=0;
double mean = 0.0; //均值
#define MeanValueMat(ROW,COL) ((float *)(MeanValue->data.fl + MeanValue->step/sizeof(float) *(ROW)))[(COL)]
#define SigmaValueMat(ROW,COL) ((float *)(SigmaValue->data.fl + SigmaValue->step/sizeof(float) *(ROW)))[(COL)]
#define NumBackMAT(ROW,COL) ((uchar *)(NumBack->data.ptr + NumBack->step *(ROW)))[(COL)]
#define BufMAT(NUMBER,ROW,COL) ((uchar*)(buf[(NUMBER)]->imageData + buf[(NUMBER)]->widthStep*(ROW)))[(COL)]
#define BkImg(ROW,COL) ((uchar*)(pBkImg->imageData + pBkImg->widthStep*(ROW)))[(COL)]
#define FrImg(ROW,COL) ((uchar*)(pFrImg->imageData + pFrImg->widthStep*(ROW)))[(COL)]
#define TempImg(ROW,COL) ((uchar*)(pTempImg->imageData + pTempImg->widthStep*(ROW)))[(COL)]
#define CurImg(ROW,COL) ((uchar*)(pCurImg->imageData + pCurImg->widthStep*(ROW)))[(COL)]
#define FirstImg(ROW,COL) ((uchar*)(pFirstImg->imageData + pFirstImg->widthStep*(ROW)))[(COL)]
//创建窗口 cvNamedWindow("videos", 1); cvNamedWindow("back",1); cvNamedWindow("fore",1);
cvNamedWindow("temp",1);
Capture =cvCaptureFromCAM(0);
// Capture = cvCaptureFromFile("I:\\经典运动检测\\video8_vlong.avi"); pFrame = cvQueryFrame( Capture );
//使窗口有序排列
cvMoveWindow("videos", 30, 20);
cvMoveWindow("back", 50+2*pFrame->width, 20);
cvMoveWindow("fore", 30, 110+2*pFrame->height);
cvMoveWindow("temp", 50+2*pFrame->width, 110+2*pFrame->height);
//申请内存,并初始化
//背景、前景、临时图像
pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
pTempImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
pCurImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
pFirstImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
//均值矩阵、方差矩阵
MeanValue = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
SigmaValue = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
NumBack = cvCreateMat(pFrame->height, pFrame->width, CV_8UC1);
cvZero(MeanValue);cvZero(SigmaValue);cvZero(NumBack);
//初始化时使用的NUM帧数据
buf = (IplImage**)malloc(NUM*sizeof(buf[0]));
memset( buf, 0, NUM * sizeof(buf[0]) );
for( i = 0; i < NUM; i++ )
{
buf[i] = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
cvZero( buf[i] );
}
storage = cvCreateMemStorage(0);
//逐帧读取视频 while(pFrame = cvQueryFrame( Capture )) { if(countframe<80)
{
countframe++;
continue;
} if(nFrmNum<LearnFrame)//背景模型初始化 {
//转化成单通道图像再处理 cvCvtColor(pFrame, pTempImg, CV_BGR2GRAY);
//中值滤波
cvSmooth( pTempImg, pCurImg, CV_MEDIAN , 3, 0, 0 );//CV_GAUSSIAN or CV_MEDIAN
cvFlip( pCurImg, pCurImg, 0 );
cvCopy( pCurImg, buf[nFrmNum], 0 );
nFrmNum++;
printf("frame= %d \n",nFrmNum);
continue; }
else if (nFrmNum==LearnFrame) //建立 单Gaussian 背景模型
{
nFrmNum++;
cvCvtColor(pFrame, pTempImg, CV_BGR2GRAY);
cvFlip( pTempImg, pTempImg, 0 );
//中值滤波
int width = pFrame->width;
int height = pFrame->height;
cvSmooth( pTempImg, pCurImg, CV_MEDIAN , 3, 0, 0 );//CV_GAUSSIAN or CV_MEDIAN
for (w = 1; w < NUM; w++)
cvCopy( buf[w], buf[w-1], 0 );
cvCopy( pCurImg, buf[NUM-1], 0 );
for ( i = 0; i < height; i++)
{
for ( j = 0; j < width; j++)
{
double temp_deviation[NUM];
int tmp;
temp[0] = BufMAT(0,i,j);
//临时存储
for ( w = 1; w < NUM; w++)
{
temp[w] = BufMAT(w,i,j);
temp_deviation[w-1] = abs(temp[w]-temp[w-1]); //临时离差
}
//排序取其数据的中值
for (w = 0; w < NUM; w++)
{
for ( x = 0; x < NUM - w - 1; x++)
{
if (temp[x] > temp[x + 1])
{
tmp = temp[x];
temp[x] = temp[x + 1];
temp[x + 1] = tmp;
}
}
}
//对离差进行排序
for (w = 0; w < NUM-1; w++)
{
for ( x = 0; x < NUM - w - 2; x++)
{
if (temp_deviation[x] > temp_deviation[x + 1])
{
tmp = temp_deviation[x];
temp_deviation[x] = temp_deviation[x + 1];
temp_deviation[x + 1] = tmp;
}
}
}
//得到中值数,以及中值离差,利用中值滤波,剔除非背景点
tmp = temp[NUM / 2];
int countback=0;
for (w = 0; w < NUM; w++)
{
if (abs(BufMAT(w,i,j) - tmp) < 3 * temp_deviation[(NUM-1)/2])
{
temp[countback] = BufMAT(w,i,j);
countback++;
}
}
//重新计算背景参数,均值、方差
int mean=temp[0];
for ( w = 1; w < countback-1; w++)
mean += 1.0*( temp[w] - mean) / (w+1);
double variance=0.0; //标准方差
for (w = 0; w < countback-1; w++)
{
tmp = (temp[w] - mean);
variance += (tmp * tmp - variance) / (w + 1);
}
variance=sqrt(1.0 * variance * (countback-1)/ (countback-2) );
if (variance<PARAMETER)
variance=PARAMETER;
//背景参数均值方差
SigmaValueMat(i,j) = variance; //标准方差
MeanValueMat(i,j) = mean; //均值
BkImg(i,j) = mean; //背景值
NumBackMAT(i,j) = countback-1; //是背景的数目
//
}//for
}//for
printf("initialization ofbackground model is completed!\n");
}//if else //背景减并进行背景更新
{
countframe++;
printf(" The current frame is %d ; \n",countframe);
//提取前景目标
cvCvtColor(pFrame, pTempImg, CV_BGR2GRAY);
cvFlip( pTempImg, pTempImg, 0 );
//中值滤波
cvSmooth( pTempImg, pCurImg, CV_MEDIAN , 3, 0, 0 );//CV_GAUSSIAN or CV_MEDIAN
cvZero(pFrImg);
for (int i = 0; i < pFrame->height; i++)
{
for (int j = 0; j < pFrame->width; j++)
{
int tt=CurImg(i,j);
int cc=MeanValueMat(i,j);
int mm=SigmaValueMat(i,j);
if ( abs(CurImg(i,j) - MeanValueMat(i,j)) < 3*SigmaValueMat(i,j) )
{
TempImg(i,j)=0; //背景
}
else
{
TempImg(i,j)=255; //前景
FrImg(i,j)=CurImg(i,j);
}
}
}
//进行形态学滤波,去掉噪音
Opening(pBkImg, pBkImg, pBkImg, 1);
Closing(pBkImg, pBkImg, pBkImg, 1);
Opening(pFrImg, pFrImg, pFrImg, 1);
Closing(pFrImg, pFrImg, pFrImg, 1);
Opening(pTempImg, pTempImg, pTempImg, 1);
Closing(pTempImg, pTempImg, pTempImg, 1);
cvShowImage("videos", pCurImg); //视频
cvShowImage("back", pBkImg); //背景图像
cvShowImage("fore", pFrImg); //仅有目标的图像
cvShowImage("temp", pTempImg); //二值化目标提取
cvCopy( buf[0], pFirstImg , 0 );
for (w = 1; w < NUM; w++)
cvCopy( buf[w], buf[w-1], 0 );
cvCopy( pCurImg, buf[NUM-1], 0 );
//根据参数更新背景
for ( i = 0; i < pFrame->height; i++)
{
for ( j = 0; j < pFrame->width; j++)
{
int countback=0;
int tmp,tmp1 ;
double mean=0.0;
double variance=0.0; //标准方差
//仅对无运动的像素进行更新
if ( abs(BufMAT( NUM-1, i,j) - MeanValueMat(i,j)) < 3*SigmaValueMat(i,j) )
{
//当第一帧对均值方差有贡献时,重新计算均值方差
if( abs(FirstImg(i,j) - MeanValueMat(i,j)) < 3*SigmaValueMat(i,j) )
{
mean = 1.0*( MeanValueMat(i,j)*NumBackMAT(i,j)-FirstImg(i,j)+BufMAT(NUM-1,i,j) ) / (NumBackMAT(i,j));
tmp = (FirstImg(i,j) - mean);
tmp1= (BufMAT(NUM-1,i,j)- mean);
variance = sqrt( 1.0*( (NumBackMAT(i,j)-1)*variance-tmp * tmp+ tmp1*tmp1) / (NumBackMAT(i,j)-1) );
}
else
{
mean = 1.0*( MeanValueMat(i,j)*NumBackMAT(i,j)-FirstImg(i,j) ) / (NumBackMAT(i,j)-1);
tmp1= (BufMAT(NUM-1,i,j)- mean);
variance = sqrt( 1.0*( (NumBackMAT(i,j)-1)*variance+ tmp1*tmp1) / (NumBackMAT(i,j)) );
NumBackMAT(i,j)+=1; //是背景的数目
}
/*
for ( w = 0; w < NUM; w++)
{
if ( ( abs(BufMAT(w,i,j) - MeanValueMat(i,j)) < 3*SigmaValueMat(i,j) ) )
{
temp[countback] = BufMAT(w,i,j); //背景像素
countback++;
}
}
//利用中值作为背景
for (w = 0; w < countback; w++)
{
for (int x = 0; x < countback - w - 1; x++)
{
if (temp[x] > temp[x+1])
{
tmp = temp[x];
temp[x] = temp[x + 1];
temp[x+1] = tmp;
}
}
}
*/
if (variance<PARAMETER)
variance=PARAMETER;
//更新背景参数
SigmaValueMat(i,j) = variance; //标准方差
MeanValueMat(i,j) = mean; //均值
BkImg(i,j)=mean;//temp[(countback-1)/2]; //背景值
}
}//for
}//for
}//else
//如果有按键事件,则跳出循环 //此等待也为cvShowImage函数提供时间完成显示 //等待时间可以根据CPU速度调整 if( cvWaitKey(2) >= 0 ) break; }//while
for( i = 0; i < NUM; i++ )
{
cvReleaseImage( &buf[i] );
}
cvReleaseCapture( &Capture );
//销毁窗口 cvDestroyWindow("videos"); cvDestroyWindow("back"); cvDestroyWindow("fore"); cvDestroyWindow("temp");
//释放图像和矩阵
cvReleaseImage(&pFrame);
cvReleaseImage(&pFrImg); cvReleaseImage(&pBkImg); cvReleaseImage(&pTempImg);
cvReleaseMat(&MeanValue);
cvReleaseMat(&SigmaValue);
return 0;}
void Opening(IplImage* src, IplImage* image, IplImage* dest, int pos)
{
element = cvCreateStructuringElementEx( pos*2+1, pos*2+1, pos, pos, element_shape, 0 );
cvErode(src,image,element,1);
cvDilate(image,dest,element,1);
cvReleaseStructuringElement(&element);
}
// implements closing
void Closing(IplImage* src, IplImage* image, IplImage* dest, int pos)
{
element = cvCreateStructuringElementEx( pos*2+1, pos*2+1, pos, pos, element_shape, 0 );
cvDilate(src,image,element,1);
cvErode(image,dest,element,1);
cvReleaseStructuringElement(&element);
}
// implements erosion
void Erosion(IplImage* src, IplImage* dest, int pos)
{
element = cvCreateStructuringElementEx( pos*2+1, pos*2+1, pos, pos, element_shape, 0 );
cvErode(src,dest,element,1);
cvReleaseStructuringElement(&element);
}
// implements dilation
void Dilation(IplImage* src, IplImage* dest, int pos)
{
element = cvCreateStructuringElementEx( pos*2+1, pos*2+1, pos, pos, element_shape, 0 );
cvDilate(src,dest,element,1);
cvReleaseStructuringElement(&element);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -