if(abs(gray_diff1.at(i,j))>threshold_diff1)
gray_diff1.at(i,j)=255;
elsegray_diff1.at(i,j)=0;
if(abs(gray_diff2.at(i,j))>threshold_diff2)
gray_diff2.at(i,j)=255;
elsegray_diff2.at(i,j)=0;
}
}
bitwise_and(gray_diff1,gray_diff2,gray);//求两个的交集
imshow("前景",gray);
}
charc=(char)waitKey(500);
if(c==27)break;
if(c=='')pause=!
pause;
}
return0;
}
结果截图:
平均背景建模:
通过多幅图像求图像的平均值和差值的平均值,并以此为依据建立背景模型,差值用于比较的阀值的参考数据,通过比较当前帧与背景模型,确定前景。
#include
#include
#include
IplImage*IavgF,*IdiffF,*IprevF,*IhiF,*IlowF;
IplImage*Iscratch,*Iscratch2;
IplImage*Igray1,*Igray2,*Igray3;
IplImage*Ilow1,*Ilow2,*Ilow3;
IplImage*Ihi1,*Ihi2,*Ihi3;
IplImage*Imaskt;
IplImage*Imask;
floatIcount;
voidAllocateImages(IplImage*I);
voidaccumulateBackground(IplImage*I);
voidcreateModelsfromStats();
voidsetHighThreshold(floatscale);
voidsetLowThreshold(floatscale);
voidbackgroundDiff(IplImage*I,IplImage*Imask);
voidDeallocateImages();
intmain(intargc,char**argv)
{
CvCapture*capture=cvCreateCameraCapture(-1);
if(NULL==capture)
{
printf("没有找到摄像头装置!
\n");
return-1;
}
IplImage*Img=cvQueryFrame(capture);
cvNamedWindow("原图",0);
cvNamedWindow("检测图",0);
cvShowImage("原图",Img);
AllocateImages(Img);//初始化
printf("开始统计背景模型\n");
while(Icount<30)//统计背景模型
{
accumulateBackground(Img);
Img=cvQueryFrame(capture);
cvWaitKey(10);
cvShowImage("原图",Img);
printf(".");
}
createModelsfromStats();//就算每一个像素的均值和方差观测
printf("\n统计背景模型结束.....\n");
printf("按任意键开始分割图像.....\n");
cvWaitKey(NULL);
printf("开始分割图像.....\n");
while
(1)
{
Img=cvQueryFrame(capture);
backgroundDiff(Img,Imask);
cvShowImage("原图",Img);
cvShowImage("检测图",Imask);
if(27==cvWaitKey(100))
break;
}
cvDestroyAllWindows();
//释放内存
DeallocateImages();
cvReleaseCapture(&capture);
return0;
}
//初始化函数:
voidAllocateImages(IplImage*I)//传入原图的大小,根据这个大小初始化。
{
CvSizesz=cvGetSize(I);
IavgF=cvCreateImage(sz,IPL_DEPTH_32F,3);
IdiffF=cvCreateImage(sz,IPL_DEPTH_32F,3);
IprevF=cvCreateImage(sz,IPL_DEPTH_32F,3);
IhiF=cvCreateImage(sz,IPL_DEPTH_32F,3);
IlowF=cvCreateImage(sz,IPL_DEPTH_32F,3);
Ilow1=cvCreateImage(sz,IPL_DEPTH_32F,1);
Ilow2=cvCreateImage(sz,IPL_DEPTH_32F,1);
Ilow3=cvCreateImage(sz,IPL_DEPTH_32F,1);
Ihi1=cvCreateImage(sz,IPL_DEPTH_32F,1);
Ihi2=cvCreateImage(sz,IPL_DEPTH_32F,1);
Ihi3=cvCreateImage(sz,IPL_DEPTH_32F,1);
cvZero(IavgF);//cvZero的作用是把矩阵里的值都置为零,初始化的作用。
cvZero(IdiffF);
cvZero(IprevF);
cvZero(IhiF);
cvZero(IlowF);
Icount=0.00001;
Iscratch=cvCreateImage(sz,IPL_DEPTH_32F,3);
Iscratch2=cvCreateImage(sz,IPL_DEPTH_32F,3);
Igray1=cvCreateImage(sz,IPL_DEPTH_32F,1);
Igray2=cvCreateImage(sz,IPL_DEPTH_32F,1);
Igray3=cvCreateImage(sz,IPL_DEPTH_32F,1);
Imaskt=cvCreateImage(sz,IPL_DEPTH_8U,1);
Imask=cvCreateImage(sz,IPL_DEPTH_8U,1);
cvZero(Iscratch);
cvZero(Iscratch2);
cvZero(Imask);
cvZero(Imaskt);
}
//循环统计背景模型
voidaccumulateBackground(IplImage*I)
{
staticintfirst=1;
cvCvtScale(I,Iscratch,1,0);//数组线性转化函数,四个参数分别为:
转换前数组、转换后数组、转换比例因子、比例缩放后加到结果数组上的数。
if(!
first)
{
cvAcc(Iscratch,IavgF);//将帧叠加到累加器中三个参数:
第一个是输入图像,第二个是图像的累积,第三个是可选择的运算。
cvAbsDiff(Iscratch,IprevF,Iscratch2);//计算两个数组差的绝对值的函数,差的绝对值的结果为第三个参数。
这里表示计算当前图像和上一个图像的差值。
cvAcc(Iscratch2,IdiffF);//IdiffF是相邻两幅图像差值的绝对值的累积
Icount+=1.0;
}
first=0;
cvCopy(Iscratch,IprevF);//把第一个数组copy给第二个数组
}
voidcreateModelsfromStats()
{
//通过除以输入图像积累的数目计算平均原始图像和绝对差分图像
cvConvertScale(IavgF,IavgF,(double)(1.0/Icount));//通过多幅图像的积累除以图像的个数得到平均原始图像。
cvConvertScale(IdiffF,IdiffF,(double)(1.0/Icount));//相邻图像差值绝对值的平均值
//makesurediffisslwayssomething
cvAddS(IdiffF,cvScalar(1.0,1.0,1.0),IdiffF);//确保平均差分图像的值最小是1,第一个数组和第二个标量元素级相加得到第三个元素。
setHighThreshold(7.0);//当计算前景和背景阈值以及避免前景阈值和背景阈值相等而出现的退化情况时,我们要缩放这个因素
setLowThreshold(6.0);
}
voidsetHighThreshold(floatscale)
{
cvConvertScale(IdiffF,Iscratch,scale);
cvAdd(Iscratch,IavgF,IhiF);
cvSplit(IhiF,Ihi1,Ihi2,Ihi3,0);//把第一个多通道图像分为多个单通道图像
}
voidsetLowThreshold(floatscale)
{
cvConvertScale(IdiffF,Iscratch,scale);
cvSub(IavgF,Iscratch,IlowF);//矩阵减法运算
cvSplit(IlowF,Ilow1,Ilow2,Ilow3,0);
}
voidbackgroundDiff(IplImage*I,IplImage*Imask)
{
cvConvertScale(I,Iscratch,1,0);
cvSplit(Iscratch,Igray1,Igray2,Igray3,0);
cvInRange(Igray1,Ilow1,Ihi1,Imask);//cvInRange的作用是判断第一个数组每个参数是不是在第二三个数组对应参数之间,把结果放入第四个参数的相对位置。
cvInRange(Igray2,Ilow2,Ihi2,Imaskt);
cvOr(Imask,Imaskt,Imask);//求第一二个数组的并集,结果放入第三个数组中
cvInRange(Igray3,Ilow3,Ihi3,Imask);
cvOr(Imask,Imaskt,Imask);
cvSubRS(Imask,cvScalar(255),Imask);
}
voidDeallocateImages()
{
cvReleaseImage(&IavgF);
cvReleaseImage(&IdiffF);
cvReleaseImage(&IprevF);
cvReleaseImage(&IhiF);
cvReleaseImage(&IlowF);
cvReleaseImage(&Ilow1);
cvReleaseImage(&Ilow2);
cvReleaseImage(&Ilow3);
cvReleaseImage(&Ihi1);
cvReleaseImage(&Ihi2);
cvReleaseImage(&Ihi3);
cvReleaseImage(&Iscratch);
cvReleaseImage(&Iscratch2);
cvReleaseImage(&Igray1);
cvReleaseImage(&Igray2);
cvReleaseImage(&Igray3);
cvReleaseImage(&Imaskt);
cvReleaseImage(&Imask);
}
均值漂移算法:
寻找区域中数据点的重心,或者加权平均值,将寻找中心移动到,数据点的重心处,并重复这个过程直到寻找区域重心收敛到一个稳定点。
求图像像素点的分布直方图:
#include"cv.h"
#include
#include
#include
usingnamespacecv;
usingnamespacestd;
classHistogram1D{
private:
inthistSize[1];//项的数量
floathranges[2];//像素的最大和最小值
constfloat*ranges[1];//像素
intchannels[1];//通道数,这里表示只有一个通道。
public:
Histogram1D(){
histSize[0]=256;
hranges[0]=0.0;
hranges[1]=255.0;
ranges[0]=hranges;
channels[0]=0;//考察零号通道
}
MatNDgetHistogram(Mat&image){
MatNDhist;
calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges);
returnhist;
}
MatgetHistogramImage(Mat&image){
MatNDhist=getHistogram(image);
doublemaxVal=0;
doubleminVal=0;
minMaxLoc(hist,&minVal,&maxVal,0,0);//查找数组中最大值和最小值的函数,第一个参数表示输入数组,第二三个表示最小大值的指针,第四五个表示最小大值的位置指针。
//得到显示直方图的图像:
MathistImg(histSize[0],histSize[0],CV_8U,Scalar(255));
//设置最高点为nbins的90%
inthpt=static_cast(0.9*histSize[0]);
//依次划线
for(inth=0;hfloatbinVal=hist.at(h);
intintensity=static_cast(binVal*hpt/maxVal);
line(histImg,Point(h,histSize[0]),Point(h,histSize[0]-intensity),cvScalar(0,0,0));
}
returnhistImg;
}
};
voidmain(){
MatImage=imread("beauty.jpg");
Histogram1Dh;
MatNDhisto=h.getHistogram(Image);
intsum=0;
for(inti=0;i<256;i++){
cout<<"像素值为"<(i)<sum=sum+histo.at(i);
}
cout<<"汇总:
"<imshow("describe",h.getHistogramImage(Image));
waitKey(0);
}
运动物体检测:
背景实时变化,把当前图像乘以一个均值加入背景中,主要是下面的cvRunningAvg函数
/**************************************************
*背景建模,运动物体检测
**************************************************/
#include
#include
#include
#include
intmain(intargc,char**argv)
{
//声明IplImage指针
IplImage*pFrame=NULL;
IplImage*pFrImg=NULL;
IplImage*pBkImg=NULL;
CvMat*pFrameMat=NULL;
CvMat*pFrMat=NULL;
CvMat*pBkMat=NULL;
CvCapture*pCapture=NUL