平均背景法的基本思想是計算每個像素的平均值和標準差作為它的背景模型。
平均背景法使用四個OpenCV函數:
代碼:
/*
平均背景法
*/
#include "highgui.h"
#include "cv.h"
#include<stdlib.h>
#include<stdio.h>
//為不同的臨時指針圖像和統計屬性創建指針
//Float, 3-channel images
IplImage* IavgF, * IdiffF, * IprevF, * IhiF, *IlowF;
IplImage* Iscratch, *Iscratch3;
//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, 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 = 0.00001;
Iscratch = cvCreateImage(sz, IPL_DEPTH_32F,3);
Iscratch3 = cvCreateImage(sz, IPL_DEPTH_32F,3);
Igray1 = cvCreateImage(sz, IPL_DEPTH_32F,1);
Igray2 = cvCreateImage(sz, IPL_DEPTH_32F,1);
Igray3 = cvCreateImage(sz, IPL_DEPTH_32F,1);
Imask = cvCreateImage(sz, IPL_DEPTH_8U, 1);
Imaskt = cvCreateImage(sz, IPL_DEPTH_8U,1);
cvZero(Iscratch);
cvZero(Iscratch3);
}
//學習累積背景圖像和每一幀圖像差值的絕對值
// 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, Iscratch3);
cvAcc(Iscratch3,IdiffF);
Icount += 1.0;
}
first = 0;
cvCopy(Iscratch, IprevF);
}
//setHighThreshold和setLowThreshold都是基于每一幀圖像平均絕對差設置閾值的有效函數
void setHighThreshold(float scale)
{
cvConvertScale(IdiffF, Iscratch, scale);
cvAdd(Iscratch, IavgF, IhiF);
cvSplit(IhiF, Ihi1, Ihi2, Ihi3, 0);
}
void setLowThreshold(float scale)
{
cvConvertScale(IdiffF, Iscratch, scale);
cvSub(IavgF, Iscratch, IlowF);
cvSplit(IlowF, Ilow1, Ilow2, Ilow3, 0);
}
//當積累了足夠多的幀圖像之后,就將其轉化為一個背景的統計模型
//計算每一個像素的均值和方差觀測
void createModelsfromStats()
{
cvConvertScale(IavgF, 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, 3-channel, 8u
//Imask
void backgroundDiff(IplImage* I)
{
cvCvtScale(I, Iscratch, 1, 0);
cvSplit(Iscratch, Igray1, Igray2, Igray3, 0);
//Channel 1
cvInRange(Igray1, Ilow1, Ihi1, Imask);
//Channel 2
cvInRange(Igray2, Ilow2, Ihi2, Imaskt);
cvOr(Imask, Imaskt, Imask);
//Channel 3
cvInRange(Igray3, Ilow3, Ihi3, Imaskt);
cvOr(Imask, Imaskt, 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(&Iscratch3);
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;
}
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。