轉自 http://blog.csdn.net/zcube/article/details/7348113
56幀時分割出手效果
63幀時分割出手的效果
/***
平均背景法進行圖像分割, 在圖像背景相對穩定的情況下, 檢測闖入圖像的前景目標
*/
- /***
- Averaging Background Method
- We’ve just seen a simple method of learning background scenes and segmenting fore-
- ground objects. It will work well only with scenes that do not contain moving background
- components (like a waving curtain or waving trees). It also assumes that the lighting
- remains fairly constant (as in indoor static scenes).
- */
- #include "stdafx.h"
- #include "cv.h"
- #include "highgui.h"
- /***************************************************/
- //我們爲需要的不同臨時圖像和統計屬性的圖像創建指針
- //Float 3-channel images
- IplImage *IavgF, *IdiffF, *IprevF, *IhiF, *IlowF;
- IplImage *Iscratch, *Iscratch2;
- //Float 1-channel images
- IplImage *Igray1, *Igray2, *Igray3;
- IplImage *Ilow1, *Ilow2, *Ilow3;
- IplImage *Ihi1, *Ihi2, *Ihi3;
- //Byte 1-channel image
- IplImage *Imaskt;
- IplImage *Imask;
- float Icount;
- /**************************************************/
- void AllocateImages(IplImage* I)
- //該函數爲需要的所有臨時圖像分配內存,傳入來自視頻的首幀圖像作爲大小參考
- {
- CvSize sz = cvGetSize(I);
- IavgF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- IdiffF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- IprevF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- IhiF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- IlowF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- Ilow1 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Ilow2 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Ilow3 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Ihi1 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Ihi2 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Ihi3 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- cvZero(IavgF);
- cvZero(IdiffF);
- cvZero(IprevF);
- cvZero(IhiF);
- cvZero(IlowF);
- Icount = 1e-5;
- Iscratch = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- Iscratch2 = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- cvZero(Iscratch);
- cvZero(Iscratch2);
- Igray1 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Igray2 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Igray3 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Imaskt = cvCreateImage(sz, IPL_DEPTH_8U, 1);
- Imask = cvCreateImage(sz, IPL_DEPTH_8U, 1);
- }
- void accumulateBackground(IplImage* I)
- //累積背景圖像和前後幀圖像差值的絕對值
- //當累積夠一定數量後就將其轉換成一個背景統計模型
- {
- static int first = 1;
- //局部靜態變量,只初始化一次,意思就是第一次被賦值爲1
- cvCvtScale(I, Iscratch, 1, 0);
- //將I指向的圖像複製給Iscratch 不能用cvCopy,因爲像素的位深度不同
- if (!first)
- {
- cvAcc(Iscratch, IavgF);
- //累積原始的浮點圖像到IIavgF
- cvAbsDiff(Iscratch, IprevF, Iscratch2);
- //計算前後幀圖像絕對差圖像到Iscratch2
- cvAcc(Iscratch2, IdiffF);
- //將前後幀差值圖像累加到IdiffF 中
- Icount += 1.0;
- //記錄累加的次數用於背景統計時計算均值
- }
- first = 0;
- //first 爲局部靜態變量,以後調用該函數將不再初始化爲1
- //意思就是除了第一次,以後調用該函數均進入if 語句
- cvCopy(Iscratch, IprevF);
- //IprevF用來保存前一幀圖像
- }
- void setHighThreshold(float scale)
- {
- cvConvertScale(IdiffF, Iscratch, scale);
- //將統計的絕對差分圖像值放大scale 倍賦給Iscratch
- cvAdd(Iscratch, IavgF, IhiF);
- //IhiF = Iscratch + IavgF
- cvSplit(IhiF, Ihi1, Ihi2, Ihi3, 0);
- //將閥值上限分割爲多通道
- }
- void setLowThreshold(float scale)
- {
- cvConvertScale(IdiffF, Iscratch, scale);
- cvSub(IavgF, Iscratch, IlowF);
- //IlowF = IavgF - Iscratch
- cvSplit(IlowF, Ilow1, Ilow2, Ilow3, 0);
- //將閥值下限分割爲多通道
- }
- void createModelsfromStats()
- //當累積足夠多的幀圖後,就將其轉化成一個背景統計模型
- //該函數用於計算每個像素的均值和平均絕對差分
- {
- cvConvertScale(IavgF, IavgF, (double)(1.0/Icount));
- //計算平均原始圖像到 IavgF
- cvConvertScale(IdiffF, IdiffF, (double)(1.0/Icount));
- //計算絕對差分圖像到 IdiffF
- cvAddS(IdiffF, cvScalar(1.0, 1.0, 1.0), IdiffF);
- //使得到的絕對差分圖像每個像素值均不爲空
- setHighThreshold(7.0);
- setLowThreshold(6.0);
- //根據統計的背景模型設定一個閥值上限和下限
- //如果 IlowF <= Temp < IhiF 時認爲其爲背景,否則爲視頻中出現的運動目標物體
- }
- void backgroundDiff(IplImage* I)
- {
- cvCvtScale(I, Iscratch, 1, 0);
- //將I指向的圖像複製給Iscratch 不能用cvCopy, 因爲像素的位深度不同
- cvSplit(Iscratch, Igray1, Igray2, Igray3, 0);
- //得到的當前幀分割成3個單通道圖像
- cvInRange(Igray1, Ilow1, Ihi1, Imask);
- // src lower upper dst
- //檢查這些單通道圖像是否在平均背景像素高低閥值之間
- //如果src(I)在範圍內(lower <= src < upper)dst(I)被設置爲0xff(每一位都是 '1')否則置0
- cvInRange(Igray2, Ilow2, Ihi2, Imaskt);
- cvOr(Imask, Imaskt, Imask);
- //計算兩個數組每個元素的按位或值賦值給第三個參數
- cvInRange(Igray3, Ilow3, Ihi3, Imaskt);
- cvOr(Imask, Imaskt, Imask);
- //最後Imask 爲分離出的前景二值圖
- cvSubRS(Imask, cvScalar(255), Imask);
- //計算數量和數組之間的差,將Imask反相處理
- }
- void DeallocateImages()
- //解除分配的內存
- {
- cvReleaseImage(&IavgF);
- cvReleaseImage(&IdiffF);
- cvReleaseImage(&IprevF);
- cvReleaseImage(&IhiF);
- cvReleaseImage(&IlowF);
- cvReleaseImage(&Ilow1);
- cvReleaseImage(&Ilow2);
- cvReleaseImage(&Ilow3);
- cvReleaseImage(&Ihi1);
- cvReleaseImage(&Ihi2);
- cvReleaseImage(&Ihi3);
- cvReleaseImage(&Iscratch);
- cvReleaseImage(&Iscratch2);
- cvReleaseImage(&Igray1);
- cvReleaseImage(&Igray2);
- cvReleaseImage(&Igray3);
- cvReleaseImage(&Imaskt);
- cvReleaseImage(&Imask);
- }
- int main()
- {
- CvCapture* capture = cvCreateFileCapture("tree.avi");
- //初始化從文件中獲取視頻
- if (!capture)
- {
- printf("Couldn't Open the file.");
- return -1;
- }
- cvNamedWindow("raw");
- cvNamedWindow("avg");
- IplImage* rawImage = cvQueryFrame(capture);
- //這個函數僅僅是函數cvGrabFrame和函數cvRetrieveFrame在一起調用的組合
- cvShowImage("raw", rawImage);
- AllocateImages(rawImage);
- for (int i=0;;i++)
- {
- if (i <= 30)
- {
- accumulateBackground(rawImage);
- //前30幀用於累積計算背景圖像
- if (i == 30)
- //將前30真轉換成一個背景統計模型
- createModelsfromStats();
- }
- else
- //建立好背景模型後調用此函數進行圖像分割
- backgroundDiff(rawImage);
- cvShowImage("avg", Imask);
- //播放分割後的目標圖像結果
- if (cvWaitKey(33) == 27)
- //每33ms 播放一幀
- break;
- if (!(rawImage = cvQueryFrame(capture)))
- break;
- cvShowImage("raw", rawImage);
- //顯示原圖像
- if (i == 56 || i == 63)
- //56幀和63幀時暫停
- cvWaitKey();
- }
- DeallocateImages();
- return 0;
- }