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

来源:互联网 发布:sql select as 编辑:程序博客网 时间:2024/06/05 03:33

程序出处: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);//绘制目标外接矩形    }}

0 0