opencv 实践程序2——背景差分法实现前景识别

程序出处:http://blog.csdn.net/cwjcwj520/article/details/7433103,感谢博主!

#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, int nFrmNum, 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")是从文件件中读取视频。
  int nFrmNum = 0;

  //创建窗口
  cvNamedWindow("video", 1);
  cvNamedWindow("background",1);
  cvNamedWindow("OTSU foreground",1);
  cvNamedWindow("改进的OTSU foreground",1);

  //使窗口有序排列
  cvMoveWindow("video", 30, 0);
  cvMoveWindow("background", 360, 0);
  cvMoveWindow("OTSU foreground", 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("OTSU foreground", 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.2f FPS %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, int nFrmNum, 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);  //浮点转化为整点
 //二值化前景图
 int threshold_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);  //src和dst必须同时是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;
    int ihist[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>1; //与之矫正,delatT = v*n; v=0.5
   
    if (!n)   
    {//图像全黑,输出警告
    fprintf (stderr, "NOT NORMAL 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 << "OTSU thresholdValue = " << thresholdValue_temp<<
", Returned thresholdValue = " << *thresholdValue<<'\n'<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)