背景差分法实现前景提取

#include

//#include"stdafx.h"

#include

#include

#include

#include

#include "cvaux.h"

#include "cxmisc.h"

using namespace std;

 

void BackgroundDiff(IplImage* SrcImg, IplImage*FroundImg, IplImage* BackgroundImg, intnFrmNum, int threshold_method);

void cvOtsu(IplImage *src, int*thresholdValue);

void PrintVedioInfo(CvCapture* pCapture, IplImage*img);

void VedioControl(); //未实现

 

 //视频控制全局变量

// 's' 画面stop

// 'q' 退出播放

// 'p' 打印OTSU算法中找到的阈值

char ctrl = NULL;

 

int main( int argc, char** argv )

{

  //声明IplImage指针

  IplImage* pFrame = NULL;

  IplImage* pFroundImg = NULL;

  IplImage* pBackgroundImg = NULL;

  IplImage* pFroundImg_c = NULL;

  IplImage* pBackgroundImg_c = NULL;

    //大门背景建模良好 best

  //CvCapture*pCapture = cvCreateFileCapture("D:\\C++Projects\\OpenCV_project\\img_video\\video.long.mjpg.avi");

  //CvCapture*pCapture=cvCaptureFromCAM(0);//从摄像头读取视频。cvCaptureFromAVI("2.avi")是从文件件中读取视频。

  CvCapture* pCapture = cvCreateFileCapture("E:\\Final3.avi");

  int nFrmNum =0;

 

  //创建窗口

  cvNamedWindow("video",1);

  cvNamedWindow("background",1);

  cvNamedWindow("OTSUforeground",1);

  cvNamedWindow("改进的OTSU foreground",1);

 

  //使窗口有序排列

  cvMoveWindow("video",30, 0);

  cvMoveWindow("background",360, 0);

  cvMoveWindow("OTSUforeground", 690, 0);

  cvMoveWindow("改进的OTSU foreground", 690, 320);

 // pCapture =cvCaptureFromAVI("2.avi");

  //逐帧读取视频

  while(pFrame= cvQueryFrame( pCapture ))

    {

 

 nFrmNum++;

 //视频控制

 if( (ctrl =cvWaitKey(1000/180)) =='s' )  cvWaitKey();

 else if(ctrl == 'p')cout << "Current Frame = "<< nFrmNum << endl;

 else if( ctrl =='q' )

break;

 

 if(nFrmNum==1)

 { 

 pBackgroundImg =cvCreateImage(cvGetSize(pFrame),  8,1);

 pFroundImg =cvCreateImage(cvGetSize(pFrame),  8,1);

 pBackgroundImg_c =cvCreateImage(cvGetSize(pFrame),  8,1); //对比算法的图像

 pFroundImg_c =cvCreateImage(cvGetSize(pFrame),  8,1);

 }

 

 BackgroundDiff(pFrame,pFroundImg,pBackgroundImg,nFrmNum, CV_THRESH_OTSU);  //普通OTSU

 BackgroundDiff(pFrame,pFroundImg_c,pBackgroundImg_c,nFrmNum, CV_THRESH_BINARY); //阈值筛选后的OTSU

 //打印视频信息,画面控制

 PrintVedioInfo(pCapture, pFroundImg);

 //显示图像

 cvShowImage("video",pFrame);

 cvShowImage("background",pBackgroundImg);

 cvShowImage("OTSUforeground", pFroundImg);

 cvShowImage("改进的OTSU foreground", pFroundImg_c);

   }  //while

 

  //销毁窗口

  cvDestroyAllWindows();

  //释放图像和矩阵

  cvReleaseImage(&pFroundImg);

  cvReleaseImage(&pBackgroundImg);

  cvReleaseCapture(&pCapture);

  return 0;

}

 

/**输出文字到图像*/

void PrintVedioInfo(CvCapture* pCapture, IplImage*img)

{

assert( pCapture !=NULL);

double frames = cvGetCaptureProperty(pCapture,CV_CAP_PROP_POS_FRAMES);  //视频当前帧数

 double fps =cvGetCaptureProperty(pCapture,CV_CAP_PROP_FPS); //获得视频每秒帧数

 char str[255];

 sprintf(str,"%4.2fFPS %4.2f frames",fps,frames); // 将浮点数转化为字符串

 CvPoint location = cvPoint(20,20); // 建立字符串打印的位置

 CvScalar color = cvScalar(255,255,255);

 CvFont font; //建立字体变量

 cvInitFont(&font, CV_FONT_HERSHEY_PLAIN,1.0,1.0);  //字体设置

 cvPutText(img, str, location,&font,color);  //打印文本到图像

}

 

/********背景差分函数,求前景目标.重要: 函数退出之后,函数中的动态变量会随着栈的退出全部清空.

*要保存上次操作的结果,则在函数内声明为静态变量.或者在要调用的函数里先声明*********/

void BackgroundDiff(IplImage* SrcImg, IplImage*FroundImg, IplImage* BackgroundImg, intnFrmNum, int threshold_method = CV_THRESH_OTSU)

{

static IplImage* SrcImg_gray = NULL;//源图像的灰度图像

static IplImage* SrcImg_grayf =NULL;  //单通道浮点图像用于背景建模

static IplImage* FroundImgf = NULL;

static IplImage* BackgroundImgf = NULL;

static  IplImage* FroundImg_temp = NULL;

    if(nFrmNum== 1)

{

 SrcImg_gray =cvCreateImage(cvGetSize(SrcImg),  8,1);

 FroundImg_temp =cvCreateImage(cvGetSize(SrcImg),  8,1);

 BackgroundImgf = cvCreateImage(cvGetSize(SrcImg),  32,1); //浮点图像

 FroundImgf =cvCreateImage(cvGetSize(SrcImg),  32,1);

 SrcImg_grayf =cvCreateImage(cvGetSize(SrcImg),  32,1);

 

 //RGB图像先转化成8位单通道图像,再转化为浮点.

 cvCvtColor(SrcImg, BackgroundImg,CV_BGR2GRAY);

 cvCvtColor(SrcImg, FroundImg, CV_BGR2GRAY);

 cvConvert(BackgroundImg,BackgroundImgf);

   cvConvert(FroundImg,FroundImgf);

}

else

{

 cvCvtColor(SrcImg, SrcImg_gray,CV_BGR2GRAY);  //SrcImg_gray在上次函数退出的时候被程序栈回收

   cvConvert(SrcImg_gray,SrcImg_grayf);

 //当前帧跟背景图相减

    cvAbsDiff(SrcImg_grayf, BackgroundImgf,FroundImgf);

cvConvert(FroundImgf,FroundImg_temp);  //浮点转化为整点

 //二值化前景图

 intthreshold_otsu =0;

cvOtsu(FroundImg_temp,&threshold_otsu);

 

 if(threshold_method== CV_THRESH_OTSU)

 {

  cvThreshold(FroundImg_temp, FroundImg, 0,255.0, CV_THRESH_OTSU); //对比自适应阈值化

 //cvAdaptiveThreshold(FroundImg_temp, FroundImg, 255.0, 0, 0, 51);  //srcdst必须同时是8bit或浮点图像

 }

 else

 {

    cvThreshold(FroundImg_temp, FroundImg,threshold_otsu, 255.0, CV_THRESH_BINARY);

 }

     cvSegmentFGMask( FroundImg ); //对前景做连通域分割

 //更新背景

 cvRunningAvg(SrcImg_grayf, BackgroundImgf,0.003, 0);  //必须是浮点图像,因为会有小数出现

 cvConvert(BackgroundImgf,BackgroundImg);

}

}

 

/*********OTSU大津法

*thresholdValue 为使类间方差最大的阈值

* 当找到的阈值小于一个修正阈值,返回此修正阈值.防止没有前景物体时,将背景找出来********/

void cvOtsu(IplImage *src, int*thresholdValue)

    int deltaT= 0; //光照调节参数

uchar grayflag =1;

IplImage* gray =NULL;

if(src->nChannels != 1) //检查源图像是否为灰度图像

{

gray =cvCreateImage(cvGetSize(src), 8, 1);

cvCvtColor(src,gray, CV_BGR2GRAY);

grayflag = 0;

}

else gray = src;

uchar*ImgData=(uchar*)(gray->imageData);  

int thresholdValue_temp = 1;

    intihist[256];   //图像直方图,256个点 

  

    int i,imgsize; //循环变量,图像尺寸

    int n, n1,n2;  //n 非零像素个数, n1 前景像素个数, n2 背景像素个数

    double m1,m2, sum, csum, fmax, sb;//m1前景灰度均值,m2背景灰度均值

    //对直方图置零  

    memset(ihist, 0, sizeof(ihist));  

    //生成直方图 

    imgsize =(gray->widthStep)*(gray->height);//图像数据总数

    for (i=0;i

    {  

    ihist[((int)(*ImgData))&255]++;//灰度统计 '&255'防止指针溢出 

    ImgData++;//像素遍历

    }  

    // set upeverything  

    sum=csum=0.0;  

    n=0;  

    for (i=0;i<255; i++)  

    {  

    sum+=(double)i*(double)ihist[i]; // x*f(x)质量矩  

    n+= ihist[i];   //f(x)质量像素总数

    }

 

deltaT = (int)(sum/imgsize); //像素平均灰度

deltaT =deltaT>>1; //与之矫正,delatT = v*n; v=0.5

  

    if(!n)  

    {//图像全黑,输出警告

    fprintf (stderr, "NOTNORMAL thresholdValue=160\n");  

    }  

    // OTSU算法

    fmax=-1.0;  

    n1=0;  

    for (i=0;i<255; i++)  

    {  

        n1+= ihist[i];  

        if(n1==0) {continue;}

        n2=n-n1;  

        if(n2==0) {break;}  

        csum += (double)i*ihist[i];  

        m1=csum/n1;  

        m2=(sum-csum)/n2;  

        sb=(double)n1*(double)n2*(m1-m2)*(m1-m2); //计算类间方差公式已简化 

        if(sb>fmax)  

        {  

            fmax=sb;  

            thresholdValue_temp=i;  //找到使类间方差最大的灰度值i  

        } 

    }  

  

if(thresholdValue_temp < 20)

*thresholdValue =20;  //阈值筛选

else *thresholdValue = thresholdValue_temp;

if( ctrl == 'p'//ctrl  = cvWaitKey(100),且是全局变量

{

   cout << "OTSUthresholdValue = " << thresholdValue_temp<<

",Returned thresholdValue = "<< *thresholdValue<<'\n'<

}

if(!grayflag) cvReleaseImage(&gray);

 

/***********

*轮廓提取

************/

void Labeling(IplImage *src, IplImage *dst)

{

    CvMemStorage* storage = 0;

    storage = cvCreateMemStorage(0); //开辟默认大小的空间

    CvSeq* contour=0;

    cvCopy(src,dst,0);

    cvFindContours( dst, storage, &contour,sizeof(CvContour),

              CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE ); //外边缘

    int num=0;

    for(;contour!=0; contour=contour->h_next)

    {

          CvRect rect;

      rect = cvBoundingRect(contour,0);//得到目标外接矩形

          num++;

        if((rect.height+ rect.width) >= 16)

       cvRectangle(src,cvPoint(rect.x,rect.y),cvPoint(rect.x+rect.width,rect.y+rect.height),

                  CV_RGB(255, 255,255),1,8);//绘制目标外接矩形

//cvRectangle(dst,cvPoint(rect.x,rect.y),cvPoint(rect.x+rect.width,rect.y+rect.height),

 //                 CV_RGB(255, 255,255),1,8);//绘制目标外接矩形

    }

}

 

你可能感兴趣的:(OpenCV学习笔记,OpenCV学习及实用demo)