OpenCV實現(xiàn)平均背景法
更新時間:2020年03月21日 07:12:35 作者:thystar
這篇文章主要為大家詳細介紹了OpenCV實現(xiàn)平均背景法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
平均背景法的基本思想是計算每個像素的平均值和標準差作為它的背景模型。
平均背景法使用四個OpenCV函數(shù):
- cvAcc(),累積圖像;
- cvAbsDiff() ,計算一定時間內(nèi)的每幀圖像只差;
- cvInRange(), 將圖像分割成前景區(qū)域和背景區(qū)域;
- cvOr(), 將不同的彩色通道圖像中合成為一個掩膜圖像
代碼:
/*
平均背景法
*/
#include "highgui.h"
#include "cv.h"
#include<stdlib.h>
#include<stdio.h>
//為不同的臨時指針圖像和統(tǒng)計屬性創(chuàng)建指針
//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;
// 創(chuàng)建一個函數(shù)來給需要的所有臨時圖像分配內(nèi)存
//為了方便,我們傳遞一幅圖像(來自視頻)作為大小參考來分配臨時圖像
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);
Iscratch2 = 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(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都是基于每一幀圖像平均絕對差設置閾值的有效函數(shù)
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);
}
//當積累了足夠多的幀圖像之后,就將其轉(zhuǎn)化為一個背景的統(tǒng)計模型
//計算每一個像素的均值和方差觀測
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);
}
//完成背景建模后, 釋放內(nèi)存
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);
}
//主函數(shù)
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;
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
您可能感興趣的文章:
相關文章
C++使用OpenCV實現(xiàn)證件照藍底換成白底功能(或其他顏色如紅色)詳解
這篇文章主要介紹了C++使用OpenCV實現(xiàn)證件照藍底換成白底功能(或其他顏色如紅色),結(jié)合實例形式詳細分析了OpenCV顏色轉(zhuǎn)換相關操作原理與實現(xiàn)技巧,需要的朋友可以參考下2019-12-12

