《學習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. }  

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