#include "highgui.h"
#include "cv.h"
#include "cxcore.h"
/*为不同临时图像和统计属性图像创建指针*/
//三通道float图像
IplImage *IavgF,*IdiffF,*IprevF,*IhiF,*IlowF;
IplImage *Iscratch,*Iscratch2;
//单通道float图像
IplImage *Igray1,*Igray2,*Igray3;
IplImage *Ilow1, *Ilow2, *Ilow3;
IplImage *Ihi1, *Ihi2, *Ihi3;
//单通道Byte图像
IplImage *Imaskt;
//自己定义的图像
//IplImage *mypic;
//计算背景建模使用图片的张数
float Icount;
/*调用函数的声明*/
void AllocateImages(IplImage *I);
void accumulateBackground(IplImage * I);
void createModelsfromStats();
void setHighThreshold(float scale);
void setLowThreshold(float scale);
void backgroundDiff(IplImage *I,IplImage * Imask);
void DeallocateImages();
int main(int argc,char** argv)
{
cvNamedWindow("intput",CV_WINDOW_AUTOSIZE); //创建输入显示窗口
cvNamedWindow("output",CV_WINDOW_AUTOSIZE); //创建输出显示窗口
CvCapture* capture = cvCreateFileCapture("bike.avi"); //返回一个capture指针,指向视频
IplImage*Img = cvQueryFrame(capture); //从视频中取出的图片
IplImage*Imask = cvCreateImage(cvGetSize(Img),IPL_DEPTH_8U,1);//创建输出图片,这里不能去掉cvCreateImage(cvGetSize(Img),IPL_DEPTH_8U,1),虽然我看例程里省略了
AllocateImages(Img); //调用创建临时图片函数
/*累积图像,只取了前30帧图片*/
while(Icount<30){
accumulateBackground(Img); //调用累积图像的函数,循环30次
Img = cvQueryFrame(capture);
cvShowImage("intput",Img);
cvWaitKey(20);
}
createModelsfromStats(); //背景建模
while(1)
{
Img = cvQueryFrame(capture);
if(!Img) break;
backgroundDiff(Img,Imask); //根据模型分割前景
cvShowImage("output",Imask); //显示图像,视频是一张一张图片连续播放的结果
cvShowImage("intput",Img);
char c = cvWaitKey(33); //当前帧被显示后,等待33ms再读取下一张图片
if(c==27) break; //等待期间按下esc键,ASCII码为27,则循环退出
}
cvReleaseCapture(&capture);
cvDestroyWindow("output");
cvDestroyWindow("intput");
DeallocateImages();
}
/*给需要的所有临时图像分配内存。为了方便,传递一副图像作为大小参考来分配临时图像*/
void AllocateImages( IplImage* I ){
CvSize sz = 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( IdiffF );
cvZero( IprevF );
cvZero( IhiF );
cvZero( IlowF );
Icount = 0.0001;
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);
cvZero( Iscratch );
cvZero( Iscratch2 );
//mypic = cvCreateImage(sz,IPL_DEPTH_8U,1);
}
/*累积背景图像和每一帧图像差值的绝对值*/
void accumulateBackground( IplImage *I ){
static int first = 1;
cvCvtScale( I,Iscratch,1,0);
if( !first ){
cvAcc( Iscratch,IavgF );
cvAbsDiff( Iscratch,IprevF,Iscratch2 );
cvAcc( Iscratch2,IdiffF );
Icount += 1.0;
}
first = 0;
cvCopy( Iscratch,IprevF );
}
/*累积背景图像与每一帧图像差值的绝对值后,建立一个背景的统计模型*/
/*先定义setHighThreshold与setLowThreshold*/
void setHighThreshold( float scale ){
cvConvertScale(IdiffF,Iscratch,scale);
cvAdd( Iscratch,IavgF,IhiF);
cvSplit( IhiF,Ihi1,Ihi2,Ihi3,0);
}
void setLowThreshold( float scale ){
cvConvertScale(IdiffF,Iscratch,scale);
cvSub( IavgF,Iscratch,IlowF);
cvSplit( IlowF,Ilow1,Ilow2,Ilow3,0);
}
/*建立模型*/
void createModelsfromStats(){
cvConvertScale( IavgF, IavgF, (double)(1.0/Icount)); //IgvgF = IgvgF *(1.0/Icount) + 0
cvConvertScale( IdiffF,IdiffF,(double)(1.0/Icount));
cvAddS( IdiffF,cvScalar(1.0,1.0,1.0),IdiffF);
setHighThreshold(7.0); //函数设置一个阈值,使得对于每一帧图像的绝对差大于平局值7倍的像素都认为是前景
setLowThreshold(6.0);
}
/*建立模型同时有了高低阈值,我们就能把图像分割成前景(不能被背景模型“解释”的图像部分)*/
void backgroundDiff(
IplImage *I,
IplImage *Imask
){
cvCvtScale(I,Iscratch,1,0);
cvSplit( Iscratch,Igray1,Igray2,Igray3,0);
//Channel 1
cvInRange(Igray1,Ilow1,Ihi1,Imask);
//Channel 2
cvInRange(Igray2,Ilow2,Ihi2,Imaskt);
cvOr(Imask,Imaskt,Imask);
//Channel 3
cvInRange(Igray3,Ilow3,Ihi3,Imaskt);
cvOr(Imask,Imaskt,Imask);
//cvCvtScale(Imask,mypic,1,0);
cvSubRS( Imask,cvScalar(255),Imask); //这里书上例程写cvSubRS(Imask,255,Imask);但是这样编译的时候会报错,必须先转换成cvScalar型
}
/*释放内存*/
void DeallocateImages()
{
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);
}
许久没有更新博客了,一直觉得自己很菜,没什么可以分享的,也一直在学习中,我用的是学习Opencv这本书,书学到一半多了,最近做了前景提取,用的平均背景法,发现书上例程并不完美的,或许是作者的用心良苦把。学习中遇到的问题我都注释在程序上了。接下来开始做有移动目标前景的背景提取了,然后就是对数据的分析,希望能够早点完成自己想做的功能吧。