1. 程式人生 > 程式設計 >OpenCV實現平均背景法

OpenCV實現平均背景法

平均背景法的基本思想是計算每個畫素的平均值和標準差作為它的背景模型。

平均背景法使用四個OpenCV函式:

  • cvAcc(),累積影象;
  • cvAbsDiff() ,計算一定時間內的每幀影象只差;
  • cvInRange(),將影象分割成前景區域和背景區域;
  • cvOr(),將不同的彩色通道影象中合成為一個掩膜影象

程式碼:

/*
平均背景法
*/
 
#include "highgui.h"
#include "cv.h"
#include<stdlib.h>
#include<stdio.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* Imask;
IplImage* Imaskt;
 
//Counts number of images learned for averaging later.
float Icount;
 
// 建立一個函式來給需要的所有臨時影象分配記憶體
//為了方便,我們傳遞一幅影象(來自視訊)作為大小參考來分配臨時影象
 
void AllocateImages(IplImage* I)
{
 CvSize sz = cvGetSize(I);
 IavgF = cvCreateImage(sz,IPL_DEPTH_32F,3);
 IdiffF = cvCreateImage(sz,3);
 IprevF = cvCreateImage(sz,3);
 IhiF = cvCreateImage(sz,3);
 IlowF = cvCreateImage(sz,3);
 
 Ilow1 = cvCreateImage(sz,1);
 Ilow2 = cvCreateImage(sz,1);
 Ilow3 = cvCreateImage(sz,1);
 Ihi1 = cvCreateImage(sz,1);
 Ihi2 = cvCreateImage(sz,1);
 Ihi3 = cvCreateImage(sz,1);
 cvZero(IavgF);
 cvZero(IdiffF);
 cvZero(IprevF);
 cvZero(IhiF);
 cvZero(IlowF);
 Icount = 0.00001;
 
 Iscratch = cvCreateImage(sz,3);
 Iscratch2 = cvCreateImage(sz,3);
 
 Igray1 = cvCreateImage(sz,1);
 Igray2 = cvCreateImage(sz,1);
 Igray3 = cvCreateImage(sz,1);
 
 Imask = cvCreateImage(sz,IPL_DEPTH_8U,1);
 Imaskt = cvCreateImage(sz,1);
 
 cvZero(Iscratch);
 cvZero(Iscratch2);
}
 
//學習累積背景影象和每一幀影象差值的絕對值
// Learn the background statistics for one more frame
// I is a color sample of the background,3-channel,8u
void accumulateBackground(IplImage *I)
{
 static int first = 1;
 cvCvtScale(I,Iscratch,1,0);
 if(!first)
 {
 cvAcc(Iscratch,IavgF);
 cvAbsDiff(Iscratch,IprevF,Iscratch2);
 cvAcc(Iscratch2,IdiffF);
 Icount += 1.0;
 }
 first = 0;
 cvCopy(Iscratch,IprevF);
}
 
//setHighThreshold和setLowThreshold都是基於每一幀影象平均絕對差設定閾值的有效函式
void setHighThreshold(float scale)
{
 cvConvertScale(IdiffF,scale);
 cvAdd(Iscratch,IavgF,IhiF);
 cvSplit(IhiF,Ihi1,Ihi2,Ihi3,0);
}
void setLowThreshold(float scale)
{
 cvConvertScale(IdiffF,scale);
 cvSub(IavgF,IlowF);
 cvSplit(IlowF,Ilow1,Ilow2,Ilow3,0);
}
 
//當積累了足夠多的幀影象之後,就將其轉化為一個背景的統計模型
//計算每一個畫素的均值和方差觀測
void createModelsfromStats()
{
 cvConvertScale(IavgF,(double)(1.0/Icount));
 cvConvertScale(IdiffF,IdiffF,(double)(1.0/Icount));
 
 //Make sure diff is always something
 
 cvAddS(IdiffF,cvScalar(1.0,1.0,1.0),IdiffF);
 setHighThreshold(7.0);
 setLowThreshold(6.0);
}
 
//有了背景模型,同時給出了高,低閾值,就能用它將影象分割為前景和背景
// Create a binary: 0,255 mask where 255 means foregrond pixel
// I Input image,8u
//Imask 
void backgroundDiff(IplImage* I)
{
 cvCvtScale(I,0);
 cvSplit(Iscratch,Igray1,Igray2,Igray3,0);
 
 //Channel 1
 cvInRange(Igray1,Imask);
 
 //Channel 2
 cvInRange(Igray2,Imaskt);
 cvOr(Imask,Imaskt,Imask);
 
 //Channel 3
 cvInRange(Igray3,Imask);
 
 //Finally,invert the result
 cvSubRS(Imask,cvScalar(255),Imask);
}
 
//完成背景建模後, 釋放記憶體
void DeallocateImage()
{
 cvReleaseImage(&IavgF);
 cvReleaseImage(&IdiffF);
 cvReleaseImage(&IprevF);
 cvReleaseImage(&IhiF);
 cvReleaseImage(&IlowF);
 cvReleaseImage(&Ilow1);
 cvReleaseImage(&Ilow2);
 cvReleaseImage(&Ilow3);
 cvReleaseImage(&Iscratch);
 cvReleaseImage(&Iscratch2);
 cvReleaseImage(&Igray1);
 cvReleaseImage(&Igray2);
 cvReleaseImage(&Igray3);
 cvReleaseImage(&Imaskt);
}
 
//主函式
int main()
{
 CvCapture* capture = cvCreateFileCapture("tree.avi");
 if(!capture)
 {
 return -1;
 }
 cvNamedWindow("win1");
 cvNamedWindow("win2");
 
 IplImage* rawImage = cvQueryFrame(capture);
 cvShowImage("win1",rawImage);
 
 AllocateImages(rawImage);
 int i = 0;
 while(1)
 {
 if(i <= 30)
 {
  accumulateBackground(rawImage);
  if(i == 30)
  {
  createModelsfromStats();
  }
 }
 else
 {
  backgroundDiff(rawImage);
 }
 cvShowImage("win2",Imask);
 
 if(cvWaitKey(33) == 27)
 {
  break;
 }
 if(!(rawImage = cvQueryFrame(capture)))
 {
  break;
 }
 cvShowImage("win1",rawImage);
 if(i == 56 || i == 63)
  cvWaitKey();
 i = i+1;
 }
 DeallocateImage();
 return 0;
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。