分享

opencv 背景差分法实现前景识别

 Y忍冬草 2016-08-26

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

  1. #include <stdio.h>  
  2. //#include "stdafx.h"  
  3. #include <cv.h>  
  4. #include <cxcore.h>  
  5. #include <highgui.h>  
  6. #include <iostream>  
  7. #include "cvaux.h"   
  8. #include "cxmisc.h"  
  9.   
  10. using namespace std;  
  11.   
  12. void BackgroundDiff(IplImage* SrcImg, IplImage* FroundImg, IplImage* BackgroundImg, int nFrmNum, int threshold_method);  
  13. void cvOtsu(IplImage *src, int *thresholdValue);  
  14. void PrintVedioInfo(CvCapture* pCapture, IplImage* img);  
  15. void VedioControl();  //未实现  
  16.   
  17.  //视频控制全局变量,  
  18. // 's' 画面stop  
  19. // 'q' 退出播放  
  20. // 'p' 打印OTSU算法中找到的阈值  
  21. char ctrl = NULL;   
  22.   
  23.   
  24. int main( int argc, char** argv )  
  25. {  
  26.   //声明IplImage指针  
  27.   IplImage* pFrame = NULL;   
  28.   IplImage* pFroundImg = NULL;  
  29.   IplImage* pBackgroundImg = NULL;  
  30.   IplImage* pFroundImg_c = NULL;  
  31.   IplImage* pBackgroundImg_c = NULL;  
  32.   
  33.     //大门背景建模良好  best  
  34.   
  35.   //CvCapture* pCapture = cvCreateFileCapture("D:\\C++ Projects\\OpenCV_project\\img_video\\video.long.mjpg.avi");  
  36.   CvCapture* pCapture=cvCaptureFromCAM(0);//从摄像头读取视频。cvCaptureFromAVI("2.avi")是从文件件中读取视频。  
  37.   int nFrmNum = 0;  
  38.   
  39.   //创建窗口  
  40.   cvNamedWindow("video", 1);  
  41.   cvNamedWindow("background",1);  
  42.   cvNamedWindow("OTSU foreground",1);  
  43.   cvNamedWindow("改进的OTSU foreground",1);  
  44.   
  45.   //使窗口有序排列  
  46.   cvMoveWindow("video", 30, 0);  
  47.   cvMoveWindow("background", 360, 0);  
  48.   cvMoveWindow("OTSU foreground", 690, 0);  
  49.   cvMoveWindow("改进的OTSU foreground", 690, 320);  
  50.  // pCapture = cvCaptureFromAVI("2.avi");   
  51.   //逐帧读取视频  
  52.   while(pFrame = cvQueryFrame( pCapture ))  
  53.     {  
  54.   
  55.  nFrmNum++;  
  56.  //视频控制  
  57.  if( (ctrl = cvWaitKey(1000/180)) =='s' )  cvWaitKey();  
  58.  else if(ctrl == 'p') cout << "Current Frame = " << nFrmNum << endl;  
  59.  else if( ctrl =='q' )  
  60. break;  
  61.   
  62.  if(nFrmNum ==1)  
  63.  {    
  64.    pBackgroundImg = cvCreateImage(cvGetSize(pFrame),  8,1);  
  65.  pFroundImg = cvCreateImage(cvGetSize(pFrame),  8,1);  
  66.  pBackgroundImg_c = cvCreateImage(cvGetSize(pFrame),  8,1); //对比算法的图像  
  67.  pFroundImg_c = cvCreateImage(cvGetSize(pFrame),  8,1);  
  68.  }  
  69.   
  70.   
  71.  BackgroundDiff(pFrame,pFroundImg,pBackgroundImg, nFrmNum, CV_THRESH_OTSU);  //普通OTSU  
  72.  BackgroundDiff(pFrame,pFroundImg_c,pBackgroundImg_c, nFrmNum, CV_THRESH_BINARY); //阈值筛选后的OTSU  
  73.  //打印视频信息,画面控制  
  74.  PrintVedioInfo(pCapture, pFroundImg);  
  75.  //显示图像  
  76.  cvShowImage("video", pFrame);  
  77.  cvShowImage("background", pBackgroundImg);  
  78.  cvShowImage("OTSU foreground", pFroundImg);  
  79.  cvShowImage("改进的OTSU foreground", pFroundImg_c);  
  80.    }  //while  
  81.     
  82.   //销毁窗口  
  83.   cvDestroyAllWindows();  
  84.   //释放图像和矩阵  
  85.   cvReleaseImage(&pFroundImg);  
  86.   cvReleaseImage(&pBackgroundImg);  
  87.   cvReleaseCapture(&pCapture);  
  88.   return 0;  
  89. }  
  90.   
  91. /* 
  92.  *输出文字到图像 
  93.  */  
  94. void PrintVedioInfo(CvCapture* pCapture, IplImage* img)  
  95. {  
  96. assert( pCapture != NULL);  
  97. double frames = cvGetCaptureProperty(pCapture, CV_CAP_PROP_POS_FRAMES);  //视频当前帧数   
  98.  double fps = cvGetCaptureProperty(pCapture,CV_CAP_PROP_FPS); //获得视频每秒帧数  
  99.  char str[255];  
  100.  sprintf(str,"%4.2f FPS %4.2f frames",fps,frames);  // 将浮点数转化为字符串  
  101.  CvPoint location = cvPoint(20,20); // 建立字符串打印的位置  
  102.  CvScalar color = cvScalar(255,255,255);  
  103.  CvFont font;  //建立字体变量  
  104.  cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, 1.0,1.0);  //字体设置  
  105.  cvPutText(img, str, location, &font,color);  //打印文本到图像  
  106. }  
  107.   
  108.   
  109. /******** 
  110. *背景差分函数,求前景目标 
  111. *重要: 函数退出之后,函数中的动态变量会随着栈的退出全部清空. 
  112. *要保存上次操作的结果,则在函数内声明为静态变量.或者在要调用的函数里先声明 
  113. ********/  
  114. void BackgroundDiff(IplImage* SrcImg, IplImage* FroundImg, IplImage* BackgroundImg, int nFrmNum, int threshold_method = CV_THRESH_OTSU)  
  115. {  
  116.   
  117. static IplImage* SrcImg_gray = NULL;//源图像的灰度图像  
  118. static IplImage* SrcImg_grayf =NULL;  //单通道浮点图像用于背景建模  
  119. static IplImage* FroundImgf = NULL;  
  120. static IplImage* BackgroundImgf = NULL;  
  121. static   IplImage* FroundImg_temp = NULL;  
  122.     if(nFrmNum == 1)  
  123. {  
  124.    
  125.  SrcImg_gray = cvCreateImage(cvGetSize(SrcImg),  8,1);  
  126.  FroundImg_temp = cvCreateImage(cvGetSize(SrcImg),  8,1);  
  127.  BackgroundImgf = cvCreateImage(cvGetSize(SrcImg),  32,1);  //浮点图像  
  128.  FroundImgf = cvCreateImage(cvGetSize(SrcImg),  32,1);  
  129.  SrcImg_grayf = cvCreateImage(cvGetSize(SrcImg),  32,1);  
  130.   
  131.  //RGB图像先转化成8位单通道图像,再转化为浮点.  
  132.  cvCvtColor(SrcImg, BackgroundImg, CV_BGR2GRAY);   
  133.  cvCvtColor(SrcImg, FroundImg, CV_BGR2GRAY);   
  134.  cvConvert(BackgroundImg,BackgroundImgf);  
  135.    cvConvert(FroundImg,FroundImgf);  
  136. }  
  137. else  
  138. {  
  139.  cvCvtColor(SrcImg, SrcImg_gray, CV_BGR2GRAY);  //SrcImg_gray在上次函数退出的时候被程序栈回收  
  140.    cvConvert(SrcImg_gray,SrcImg_grayf);  
  141.  //当前帧跟背景图相减  
  142.     cvAbsDiff(SrcImg_grayf, BackgroundImgf, FroundImgf);  
  143. cvConvert(FroundImgf,FroundImg_temp);  //浮点转化为整点  
  144.  //二值化前景图  
  145.  int threshold_otsu =0;  
  146. cvOtsu(FroundImg_temp, &threshold_otsu);  
  147.   
  148.  if(threshold_method == CV_THRESH_OTSU)  
  149.  {  
  150.   cvThreshold(FroundImg_temp, FroundImg, 0, 255.0, CV_THRESH_OTSU); //对比自适应阈值化  
  151.  // cvAdaptiveThreshold(FroundImg_temp, FroundImg, 255.0, 0, 0, 51);  //src和dst必须同时是8bit或浮点图像  
  152.  }  
  153.  else  
  154.  {  
  155.     cvThreshold(FroundImg_temp, FroundImg, threshold_otsu, 255.0, CV_THRESH_BINARY);   
  156.  }  
  157.      cvSegmentFGMask( FroundImg ); //对前景做连通域分割  
  158.  //更新背景  
  159.  cvRunningAvg(SrcImg_grayf, BackgroundImgf, 0.003, 0);  //必须是浮点图像,因为会有小数出现  
  160.  cvConvert(BackgroundImgf,BackgroundImg);  
  161. }  
  162. }  
  163.   
  164. /******** 
  165.  *OTSU大津法 
  166.  * thresholdValue 为使类间方差最大的阈值 
  167.  * 当找到的阈值小于一个修正阈值,返回此修正阈值.防止没有前景物体时,将背景找出来 
  168.  ********/  
  169. void cvOtsu(IplImage *src, int *thresholdValue)  
  170. {    
  171.     int deltaT = 0; //光照调节参数  
  172. uchar grayflag =1;  
  173. IplImage* gray = NULL;  
  174. if(src->nChannels != 1) //检查源图像是否为灰度图像  
  175. {  
  176. gray = cvCreateImage(cvGetSize(src), 8, 1);  
  177. cvCvtColor(src, gray, CV_BGR2GRAY);  
  178. grayflag = 0;  
  179. }  
  180. else gray = src;  
  181. uchar* ImgData=(uchar*)(gray->imageData);     
  182. int thresholdValue_temp = 1;  
  183.     int ihist[256];   //图像直方图,256个点    
  184.      
  185.     int i, imgsize; //循环变量,图像尺寸  
  186.     int n, n1, n2;  //n 非零像素个数, n1 前景像素个数, n2 背景像素个数  
  187.     double m1, m2, sum, csum, fmax, sb;//m1前景灰度均值,m2背景灰度均值  
  188.     //对直方图置零     
  189.     memset(ihist, 0, sizeof(ihist));     
  190.     //生成直方图    
  191.     imgsize = (gray->widthStep)*(gray->height);//图像数据总数   
  192.     for (i=0; i<imgsize;i++)     
  193.     {     
  194.     ihist[((int)(*ImgData))&255]++;//灰度统计 '&255'防止指针溢出    
  195.     ImgData++;//像素遍历  
  196.     }     
  197.     // set up everything     
  198.     sum=csum=0.0;     
  199.     n=0;     
  200.     for (i=0; i<255; i++)     
  201.     {     
  202.     sum+=(double)i*(double)ihist[i];  // x*f(x)质量矩     
  203.     n+= ihist[i];   //f(x)质量 像素总数  
  204.     }  
  205.   
  206. deltaT = (int)(sum/imgsize); //像素平均灰度  
  207. deltaT = deltaT>>1; //与之矫正,delatT = v*n; v=0.5  
  208.      
  209.     if (!n)     
  210.     {//图像全黑,输出警告  
  211.     fprintf (stderr, "NOT NORMAL thresholdValue=160\n");     
  212.     }     
  213.     // OTSU算法  
  214.     fmax=-1.0;     
  215.     n1=0;     
  216.     for (i=0; i<255; i++)     
  217.     {     
  218.         n1+= ihist[i];     
  219.         if (n1==0) {continue;}  
  220.         n2=n-n1;     
  221.         if (n2==0) {break;}     
  222.         csum += (double)i *ihist[i];     
  223.         m1=csum/n1;     
  224.         m2=(sum-csum)/n2;     
  225.         sb=(double)n1*(double)n2*(m1-m2)*(m1-m2); //计算类间方差,  公式已简化    
  226.         if (sb>fmax)     
  227.         {     
  228.             fmax=sb;     
  229.             thresholdValue_temp=i;  //找到使类间方差最大的灰度值i     
  230.         }    
  231.     }     
  232.      
  233. if(thresholdValue_temp < 20)  
  234. *thresholdValue = 20;  //阈值筛选  
  235. else *thresholdValue = thresholdValue_temp;  
  236. if( ctrl == 'p')  //ctrl  = cvWaitKey(100),且是全局变量  
  237. {  
  238.    cout << "OTSU thresholdValue = " << thresholdValue_temp<<  
  239. ", Returned thresholdValue = " << *thresholdValue<<'\n'<<endl;  
  240. }  
  241. if(!grayflag) cvReleaseImage(&gray);  
  242. }    
  243.   
  244. /*********** 
  245. *轮廓提取 
  246. ************/  
  247. void Labeling(IplImage *src, IplImage *dst)   
  248. {  
  249.     CvMemStorage* storage = 0;  
  250.     storage = cvCreateMemStorage(0); //开辟默认大小的空间  
  251.     CvSeq* contour=0;  
  252.     cvCopy(src,dst,0);  
  253.     cvFindContours( dst, storage, &contour, sizeof(CvContour),  
  254.               CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE ); //外边缘  
  255.     int num=0;  
  256.     for( ;contour!=0; contour=contour->h_next)  
  257.     {  
  258.           CvRect rect;  
  259.       rect = cvBoundingRect(contour,0);//得到目标外接矩形  
  260.           num++;  
  261.         if((rect.height + rect.width) >= 16)  
  262.         cvRectangle(src,cvPoint(rect.x,rect.y),cvPoint(rect.x+rect.width,rect.y+rect.height),  
  263.                   CV_RGB(255, 255,255),1,8);//绘制目标外接矩形  
  264. // cvRectangle(dst,cvPoint(rect.x,rect.y),cvPoint(rect.x+rect.width,rect.y+rect.height),  
  265.  //                 CV_RGB(255, 255,255),1,8);//绘制目标外接矩形  
  266.     }  
  267. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多