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

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

#include <stdio.h>
//#include "stdafx.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <iostream>
#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<imgsize;i++)   
    {   
    ihist[((int)(*ImgData))&255]++;//灰度统计 '&255'防止指针溢出  
    ImgData++;//像素遍历
    }   
    // set up everything   
    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, "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'<<endl;
}
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);//绘制目标外接矩形
    }
}

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值