《学习openCV》例程解析 ex_9_2(背景减除)

转自 http://blog.csdn.net/zcube/article/details/7348113


56帧时分割出手效果

63帧时分割出手的效果

/***
平均背景法进行图像分割, 在图像背景相对稳定的情况下, 检测闯入图像的前景目标

*/

  1. /*** 
  2.     Averaging Background Method 
  3.  
  4.     We’ve just seen a simple method of learning background scenes and segmenting fore- 
  5.     ground objects. It will work well only with scenes that do not contain moving background  
  6.     components (like a waving curtain or waving trees). It also assumes that the lighting  
  7.     remains fairly constant (as in indoor static scenes).  
  8. */  
  9. #include "stdafx.h"  
  10. #include "cv.h"  
  11. #include "highgui.h"  
  12.   
  13. /***************************************************/  
  14. //我们为需要的不同临时图像和统计属性的图像创建指针  
  15.   
  16. //Float 3-channel images  
  17. IplImage *IavgF, *IdiffF, *IprevF, *IhiF, *IlowF;  
  18. IplImage *Iscratch, *Iscratch2;  
  19.   
  20. //Float 1-channel images  
  21. IplImage *Igray1, *Igray2, *Igray3;  
  22. IplImage *Ilow1, *Ilow2, *Ilow3;  
  23. IplImage *Ihi1, *Ihi2, *Ihi3;  
  24.   
  25. //Byte 1-channel image  
  26. IplImage *Imaskt;  
  27. IplImage *Imask;  
  28.   
  29. float Icount;  
  30. /**************************************************/  
  31.   
  32.   
  33. void AllocateImages(IplImage* I)  
  34. //该函数为需要的所有临时图像分配内存,传入来自视频的首帧图像作为大小参考  
  35. {  
  36.     CvSize sz = cvGetSize(I);  
  37.   
  38.     IavgF   = cvCreateImage(sz, IPL_DEPTH_32F, 3);  
  39.     IdiffF  = cvCreateImage(sz, IPL_DEPTH_32F, 3);  
  40.     IprevF  = cvCreateImage(sz, IPL_DEPTH_32F, 3);  
  41.     IhiF    = cvCreateImage(sz, IPL_DEPTH_32F, 3);  
  42.     IlowF   = cvCreateImage(sz, IPL_DEPTH_32F, 3);  
  43.   
  44.     Ilow1   = cvCreateImage(sz, IPL_DEPTH_32F, 1);  
  45.     Ilow2   = cvCreateImage(sz, IPL_DEPTH_32F, 1);  
  46.     Ilow3   = cvCreateImage(sz, IPL_DEPTH_32F, 1);  
  47.     Ihi1    = cvCreateImage(sz, IPL_DEPTH_32F, 1);  
  48.     Ihi2    = cvCreateImage(sz, IPL_DEPTH_32F, 1);  
  49.     Ihi3    = cvCreateImage(sz, IPL_DEPTH_32F, 1);  
  50.   
  51.     cvZero(IavgF);  
  52.     cvZero(IdiffF);  
  53.     cvZero(IprevF);  
  54.     cvZero(IhiF);  
  55.     cvZero(IlowF);  
  56.       
  57.     Icount = 1e-5;  
  58.   
  59.     Iscratch    = cvCreateImage(sz, IPL_DEPTH_32F, 3);  
  60.     Iscratch2   = cvCreateImage(sz, IPL_DEPTH_32F, 3);  
  61.   
  62.     cvZero(Iscratch);  
  63.     cvZero(Iscratch2);  
  64.   
  65.     Igray1  = cvCreateImage(sz, IPL_DEPTH_32F, 1);  
  66.     Igray2  = cvCreateImage(sz, IPL_DEPTH_32F, 1);  
  67.     Igray3  = cvCreateImage(sz, IPL_DEPTH_32F, 1);  
  68.     Imaskt  = cvCreateImage(sz, IPL_DEPTH_8U, 1);  
  69.     Imask   = cvCreateImage(sz, IPL_DEPTH_8U, 1);  
  70.   
  71. }  
  72.   
  73. void accumulateBackground(IplImage* I)  
  74. //累积背景图像和前后帧图像差值的绝对值  
  75. //当累积够一定数量后就将其转换成一个背景统计模型  
  76. {  
  77.     static int first = 1;  
  78.     //局部静态变量,只初始化一次,意思就是第一次被赋值为1  
  79.   
  80.     cvCvtScale(I, Iscratch, 1, 0);  
  81.     //将I指向的图像复制给Iscratch 不能用cvCopy,因为像素的位深度不同  
  82.   
  83.     if (!first)  
  84.     {  
  85.         cvAcc(Iscratch, IavgF);  
  86.         //累积原始的浮点图像到IIavgF  
  87.         cvAbsDiff(Iscratch, IprevF, Iscratch2);  
  88.         //计算前后帧图像绝对差图像到Iscratch2  
  89.         cvAcc(Iscratch2, IdiffF);  
  90.         //将前后帧差值图像累加到IdiffF 中  
  91.         Icount += 1.0;  
  92.         //记录累加的次数用于背景统计时计算均值  
  93.     }  
  94.     first = 0;  
  95.     //first 为局部静态变量,以后调用该函数将不再初始化为1  
  96.     //意思就是除了第一次,以后调用该函数均进入if 语句  
  97.   
  98.     cvCopy(Iscratch, IprevF);  
  99.     //IprevF用来保存前一帧图像  
  100. }  
  101.   
  102. void setHighThreshold(float scale)  
  103. {  
  104.     cvConvertScale(IdiffF, Iscratch, scale);  
  105.     //将统计的绝对差分图像值放大scale 倍赋给Iscratch  
  106.     cvAdd(Iscratch, IavgF, IhiF);  
  107.     //IhiF = Iscratch + IavgF   
  108.     cvSplit(IhiF, Ihi1, Ihi2, Ihi3, 0);  
  109.     //将阀值上限分割为多通道  
  110. }  
  111.   
  112. void setLowThreshold(float scale)  
  113. {  
  114.     cvConvertScale(IdiffF, Iscratch, scale);  
  115.     cvSub(IavgF, Iscratch, IlowF);  
  116.     //IlowF = IavgF - Iscratch  
  117.     cvSplit(IlowF, Ilow1, Ilow2, Ilow3, 0);  
  118.     //将阀值下限分割为多通道  
  119. }  
  120.   
  121. void createModelsfromStats()  
  122. //当累积足够多的帧图后,就将其转化成一个背景统计模型  
  123. //该函数用于计算每个像素的均值和平均绝对差分  
  124. {  
  125.     cvConvertScale(IavgF, IavgF, (double)(1.0/Icount));  
  126.     //计算平均原始图像到 IavgF  
  127.     cvConvertScale(IdiffF, IdiffF, (double)(1.0/Icount));  
  128.     //计算绝对差分图像到 IdiffF  
  129.   
  130.     cvAddS(IdiffF, cvScalar(1.0, 1.0, 1.0), IdiffF);  
  131.     //使得到的绝对差分图像每个像素值均不为空  
  132.   
  133.     setHighThreshold(7.0);  
  134.     setLowThreshold(6.0);  
  135.     //根据统计的背景模型设定一个阀值上限和下限  
  136.     //如果 IlowF <= Temp < IhiF 时认为其为背景,否则为视频中出现的运动目标物体  
  137. }  
  138.   
  139.   
  140.   
  141. void backgroundDiff(IplImage* I)  
  142. {  
  143.     cvCvtScale(I, Iscratch, 1, 0);  
  144.     //将I指向的图像复制给Iscratch 不能用cvCopy, 因为像素的位深度不同  
  145.     cvSplit(Iscratch, Igray1, Igray2, Igray3, 0);  
  146.     //得到的当前帧分割成3个单通道图像  
  147.     cvInRange(Igray1, Ilow1, Ihi1, Imask);  
  148.     //        src     lower  upper dst  
  149.     //检查这些单通道图像是否在平均背景像素高低阀值之间  
  150.     //如果src(I)在范围内(lower <= src < upper)dst(I)被设置为0xff(每一位都是 '1')否则置0  
  151.     cvInRange(Igray2, Ilow2, Ihi2, Imaskt);  
  152.     cvOr(Imask, Imaskt, Imask);  
  153.     //计算两个数组每个元素的按位或值赋值给第三个参数  
  154.     cvInRange(Igray3, Ilow3, Ihi3, Imaskt);  
  155.     cvOr(Imask, Imaskt, Imask);  
  156.     //最后Imask 为分离出的前景二值图  
  157.     cvSubRS(Imask, cvScalar(255), Imask);  
  158.     //计算数量和数组之间的差,将Imask反相处理  
  159. }  
  160.   
  161. void DeallocateImages()  
  162. //解除分配的内存  
  163. {  
  164.     cvReleaseImage(&IavgF);  
  165.     cvReleaseImage(&IdiffF);  
  166.     cvReleaseImage(&IprevF);  
  167.     cvReleaseImage(&IhiF);  
  168.     cvReleaseImage(&IlowF);  
  169.     cvReleaseImage(&Ilow1);  
  170.     cvReleaseImage(&Ilow2);  
  171.     cvReleaseImage(&Ilow3);  
  172.     cvReleaseImage(&Ihi1);  
  173.     cvReleaseImage(&Ihi2);  
  174.     cvReleaseImage(&Ihi3);  
  175.     cvReleaseImage(&Iscratch);  
  176.     cvReleaseImage(&Iscratch2);  
  177.     cvReleaseImage(&Igray1);  
  178.     cvReleaseImage(&Igray2);  
  179.     cvReleaseImage(&Igray3);  
  180.     cvReleaseImage(&Imaskt);  
  181.     cvReleaseImage(&Imask);  
  182. }  
  183.   
  184. int main()  
  185. {  
  186.     CvCapture* capture = cvCreateFileCapture("tree.avi");  
  187.     //初始化从文件中获取视频  
  188.     if (!capture)  
  189.     {  
  190.         printf("Couldn't Open the file.");  
  191.         return -1;  
  192.     }  
  193.       
  194.     cvNamedWindow("raw");  
  195.     cvNamedWindow("avg");  
  196.   
  197.     IplImage* rawImage = cvQueryFrame(capture);  
  198.     //这个函数仅仅是函数cvGrabFrame和函数cvRetrieveFrame在一起调用的组合  
  199.     cvShowImage("raw", rawImage);  
  200.       
  201.     AllocateImages(rawImage);  
  202.       
  203.     for (int i=0;;i++)  
  204.     {  
  205.         if (i <= 30)   
  206.         {  
  207.             accumulateBackground(rawImage);  
  208.             //前30帧用于累积计算背景图像  
  209.             if (i == 30)  
  210.                 //将前30真转换成一个背景统计模型  
  211.                 createModelsfromStats();  
  212.         }  
  213.         else   
  214.             //建立好背景模型后调用此函数进行图像分割  
  215.             backgroundDiff(rawImage);  
  216.   
  217.         cvShowImage("avg", Imask);  
  218.         //播放分割后的目标图像结果  
  219.   
  220.         if (cvWaitKey(33) == 27)  
  221.             //每33ms 播放一帧  
  222.             break;  
  223.   
  224.         if (!(rawImage = cvQueryFrame(capture)))  
  225.             break;  
  226.         cvShowImage("raw", rawImage);  
  227.         //显示原图像  
  228.   
  229.         if (i == 56 || i == 63)  
  230.             //56帧和63帧时暂停  
  231.             cvWaitKey();  
  232.     }     
  233.   
  234.     DeallocateImages();  
  235.     return 0;  
  236. }  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章