Vibe算法简介、优缺点、代码
ViBe檢測方法
- 算法簡介
- 1.背景模型的初始化
- 2.前景檢測過程
- 3.背景模型的更新方法
- Vibe算法優(yōu)缺點
- Vibe代碼
算法簡介
??該算法采用鄰域像素來創(chuàng)建背景模型,通過比對背景模型和當前輸入像素值來檢測前景。總的來說就是先背景建模,后前景檢測的背景差方法。
??具體的思想就是為每個像素點存儲了一個樣本集,樣本集中采樣值就是該像素點過去的像素值和其鄰居點的像素值,然后將每一個新的像素值和樣本集進行比較來判斷是否屬于背景點。
??vibe算法可以分為以下三個步驟。
1.背景模型的初始化
??初始化單幀圖像中每個像素點的背景模型。假設(shè)每一個像素和其鄰域像素的像素值在空域上有相似的分布。基于這種假設(shè),每一個像素模型都可以用其鄰域中的像素來表示。為了保證背景模型符合統(tǒng)計學(xué)規(guī)律,鄰域的范圍要足夠大。
??對于一個像素點,隨機的選擇它的鄰居點的像素值作為它的模型樣本值。M0(x)=v0(y|y∈NG(x)),t=0初始時刻,NG(x)即為鄰居點 。
2.前景檢測過程
??對后續(xù)的圖像序列進行前景目標分割操作。
背景模型為每個背景點存儲一個樣本集,然后每個新的像素值和樣本集比較判斷是否屬于背景。像素點(x,y)的背景模型為,像素值為。按照下面判斷該像素值是否為前景。
這里上標r是隨機選的;T是預(yù)先設(shè)置好的閾值。當??
滿足符合背景#N次時,我們認為像素點????為背景,否則為前景。
3.背景模型的更新方法
??ViBe算法的更新在時間和空間上都具有隨機性。時間上的隨機性。在N個背景模型中隨機抽取一個,設(shè)為圖像Pg。當我們得到新的一幀圖像Pt時,如果圖像Pt中的x位置對應(yīng)的像素Pt(x)被判斷為背景,則Pg需要被更新。這個抽取的過程體現(xiàn)了時間上的隨機性。空間上的隨機性。在Pg(x)的八鄰域中隨機抽取一個像素Pg(r),用Pg(r)的來替換掉Pg(x),這體現(xiàn)了模型更新空間上的隨機性。
Vibe算法優(yōu)缺點
優(yōu)點:
- 內(nèi)存占用少,一個像素需要作一次比較,占用一個字節(jié)的內(nèi)存;
- 無參數(shù)法;
- 性能優(yōu)于混合高斯,參數(shù)化方法,SACON等;
- 像素級算法,視頻處理中的預(yù)處理關(guān)鍵步驟;
- 背景模型及時初始化;
- 具有較好的抗噪能力;
- 在背景建模中,不僅減少了背景模型建立的過程,還可以處理背景突然變化的情況,當檢測到背景突然變化明顯時,只需要舍棄原始的模型,重新利用變化后的首幀圖像建立背景模型;
- 在背景模型更新中,采用八鄰域更新的方法,可以去除由于獲取的視頻細微抖動(攝像機抖動、目標微動)而產(chǎn)生的重影和誤差,讓檢測目標更加準確。
缺點:
-
在背景建模中,由于可能采用了運動物體的像素初始化樣本集,容易引入Ghost區(qū)域(拖影、鬼影區(qū)域)(Ghost區(qū)域也就是指當一個原本靜止的物體開始運動,背景差檢測算法可能會將原來該物體所覆蓋的區(qū)域錯誤的檢測為運動的,這塊區(qū)域就成為Ghost,當然原來運動的物體變?yōu)殪o止的也會引入Ghost區(qū)域,Ghost區(qū)域在檢測中必須被盡快的消除。)Ghost區(qū)域如下圖所示;
-
靜止目標問題,長時間駐留未運動,該人物運動目標逐漸被背景吸收。
-
陰影前景問題,陰影的存在導(dǎo)致檢測出來的運動目標形狀不準確,影響后續(xù)目標分類、跟蹤、識別和分析等其他智能視頻處理模塊。產(chǎn)生陰影前景問題的根源是:光線被運動目標前景遮擋,投射陰影區(qū)的顏色比背景的顏色暗,即陰影和背景顏色值的距離相差較大,背景差分后被誤檢為運動目標前景。
-
運動目標不完整問題,運動目標通常可分為非剛性物體和剛性物體,人屬于非剛性物體,車屬于剛性物體,這兩種常見檢測對象的檢測結(jié)果都出現(xiàn)了不完整現(xiàn)象。
Vibe代碼
Vibe.h頭文件
#include<iostream> #include<cstdio> #include<opencv2/opencv.hpp>using namespace cv; using namespace std;//每個像素點的樣本個數(shù)默認值 #define DEFAULT_NUM_SAMPLES 20//#min指數(shù)默認值 #define DEFAULT_MIN_MATCHES 2//Sqthere半徑默認值 #define DEFAULT_RADIUS 20//子采樣概率默認值 #define DEFAULT_RANDOM_SAMPLE 16class ViBe { public:ViBe(int num_sam = DEFAULT_NUM_SAMPLES,int min_match = DEFAULT_MIN_MATCHES,int r = DEFAULT_RADIUS,int rand_sam = DEFAULT_RANDOM_SAMPLE);~ViBe(void);//背景模型初始化void init(Mat img);//處理第一幀圖像void ProcessFirstFrame(Mat img);//運行ViBe算法,提取前景區(qū)域并更新背景模型樣本庫void Run(Mat img);//獲取前景模型二值圖像Mat getFGModel();//刪除樣本庫void deleteSamples();//x的鄰居點int c_xoff[9];//y的鄰居點int c_yoff[9];private://樣本庫unsigned char*** samples;//前景模型二值圖像Mat FGModel;//每個像素點的樣本個數(shù)int num_samples;//#min指數(shù)int num_min_matches;//Sqthere半徑int radius;//子采樣概率int random_sample;}; #pragma onceVibe.cpp
#include"Vibe.h" /* 構(gòu)造函數(shù)ViBe 參數(shù): int num_sam:每個像素點的樣本個數(shù) int min_match:#min 指數(shù) int r: Sqthere 半徑 int rand_sam:子采樣概率 */ViBe::ViBe(int num_sam, int min_match, int r, int rand_sam) {num_samples = num_sam;num_min_matches = min_match;radius = r;random_sample = rand_sam;int c_off[9] = { -1,0,1,-1,1,-1,0,1,0 };for (int i = 0; i < 9; i++) {c_xoff[i] = c_yoff[i] = c_off[i];} }/*析構(gòu)函數(shù):~ViBe說明:釋放樣本庫內(nèi)存 */ViBe::~ViBe(void) {deleteSamples(); }/*函數(shù)名init說明:背景模型初始化為樣本庫分配空間參數(shù):Mat img:源圖像返回值:void */void ViBe::init(Mat img) {//動態(tài)分配三維數(shù)組,samples[][][num_samples]存儲前景被連續(xù)檢測的次數(shù)//samples = new unsigned char**[img.rows];for (int i = 0; i < img.rows; i++){samples[i] = new uchar *[img.cols];for (int j = 0; j < img.cols; j++){//數(shù)組中,在num_samples之外多增加的一個值,用于統(tǒng)計該像素點連續(xù)成為前景的次數(shù)samples[i][j] = new uchar[num_samples + 1];for (int k = 0; k < num_samples + 1; k++){//創(chuàng)建樣本庫是,所有樣本全部初始化為0samples[i][j][k] = 0;}}}FGModel = Mat::zeros(img.size(), CV_8UC1); } /*函數(shù)名 ProcessFirstFrame說明:處理第一幀圖像讀取視頻序列第一幀,并隨機選取像素點鄰域內(nèi)像素填充樣本庫,初始化背景模型參數(shù):Mat img:源圖像返回值:void*/void ViBe::ProcessFirstFrame(Mat img) {RNG rng;int row, col;for (int i = 0; i < img.rows; i++){for (int j = 0; j < img.cols; j++){for (int k = 0; k < num_samples; k++){//隨機選擇num_samples個鄰域像素點,構(gòu)建背景模型int random;random = rng.uniform(0, 9); row = i + c_yoff[random];random = rng.uniform(0, 9); col = j + c_xoff[random];//防止選取的像素點越界if (row < 0)row = 0;if (row >= img.rows)row = img.rows - 1;if (col < 0)col = 0;if (col >= img.cols)col = img.cols - 1;//為樣本庫賦值隨機值samples[i][j][k] = img.at<uchar>(row, col);}}} }/* 函數(shù)名:Run 說明:運行ViBe算法,提取前景區(qū)域并更新背景模型樣本庫 參數(shù): Mat img 源圖像 返回值:void*/void ViBe::Run(Mat img) {RNG rng;int k = 0, dist = 0, matches = 0;for (int i = 0; i < img.rows; i++){for (int j = 0; j < img.cols; j++){//前景提取//說明:計算當前像素值與樣本庫的匹配情況//參數(shù)://int matches:當前像素值與 樣本庫中值之差小于閾值范圍RADIUS的個數(shù)//int count: 遍歷樣本庫的緩存變量for (k = 0, matches = 0; matches < num_min_matches && k < num_samples; k++){dist = abs(samples[i][j][k] - img.at<uchar>(i, j));if (dist < radius)matches++;}//說明:當前像素值與樣本庫中值匹配次數(shù)較高,則認為是背景像素點;//此時更新前景統(tǒng)計次數(shù)、更新前景模型、更新該像素模型樣本值、更新該像素點鄰域像素點if (matches >= num_min_matches){//已經(jīng)認為是背景像素,故該像素前景統(tǒng)計次數(shù)置0samples[i][j][num_samples] = 0;//該像素點的前景模型像素值置0FGModel.at<uchar>(i, j) = 0;}//說明:當前像素值與樣本庫中值匹配次數(shù)較低,則認為是前景像素點//此時需要更新前景統(tǒng)計次數(shù),判斷更新前景模型else {//已經(jīng)認為是前景像素,故該像素的前景統(tǒng)計次數(shù)+1samples[i][j][num_samples]++;//該像素點的前景模型像素值置255FGModel.at<uchar>(i, j) = 255;//如果某個像素點連續(xù)50次被檢測為前景,則認為一塊靜止區(qū)域被誤判為運動,將其更新為背景點if (samples[i][j][num_samples] > 50){int random = rng.uniform(0, num_samples);samples[i][j][random] = img.at<uchar>(i, j);}}//更新模型樣本庫if (matches >= num_min_matches){//已經(jīng)認為該像素是背景像素,那么它有1/φ的概率去更新自己的模型樣本值int random = rng.uniform(0, random_sample);if (random == 0){random = rng.uniform(0, num_samples);samples[i][j][random] = img.at<uchar>(i, j);}//同時也有1/φ的概率去更新它的鄰居點的模型樣本值random = rng.uniform(0, random_sample);if (random == 0){int row, col;random = rng.uniform(0, 9); row = i + c_yoff[random];random = rng.uniform(0, 9); col = j + c_xoff[random];//防止選取的像素點越界if (row < 0)row = 0;if (row >= img.rows)row = img.rows - 1;if (col < 0)col = 0;if (col >= img.cols)col = img.cols - 1;//為樣本庫賦值隨機值random = rng.uniform(0, num_samples);samples[row][col][random] = img.at<uchar>(i, j);}}}} }/* 函數(shù)名 :getFGModel 說明:獲取前景模型二值圖像 返回值:Mat*/Mat ViBe::getFGModel() {return FGModel; }/* 函數(shù)名:deletesamples 說明:刪除樣本庫 返回值:void*/void ViBe::deleteSamples() {delete samples; }main.cpp
#include<opencv2/imgproc.hpp> #include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/types_c.h> #include <opencv2/objdetect/objdetect.hpp> #include "Vibe.h"int main(int argc, char* argv[]) {Mat frame, gray, FGModel;VideoCapture capture;capture = VideoCapture("E:/material/yaoyongde/test.avi");if (!capture.isOpened()){capture = VideoCapture("E:/material/yaoyongde/test.avi");if (!capture.isOpened()){capture = VideoCapture("E:/material/yaoyongde/test.avi");if (!capture.isOpened()){cout << "ERROR:Didn't find thid video!" << endl;return 0;}}}capture.set(CAP_PROP_FRAME_WIDTH, 160);capture.set(CAP_PROP_FRAME_HEIGHT, 120);if (!capture.isOpened()){cout << "No camera or video input!" << endl;return -1;}//程序運行時間統(tǒng)計變量double time;double start;ViBe vibe;bool count = true;while (1){capture >> frame;if (frame.empty())continue;cvtColor(frame, gray, CV_RGB2GRAY);if (count){vibe.init(gray);vibe.ProcessFirstFrame(gray);cout << "Training ViBe Success." << endl;count = false;}else{start = static_cast<double>(getTickCount());vibe.Run(gray);time = ((double)getTickCount() - start) / getTickFrequency() * 1000;cout << "Time of Update ViBe BAckground:" << time << "ms" << endl << endl;FGModel = vibe.getFGModel();imshow("FGModel", FGModel);}imshow("input", frame);if (waitKey(25) == 27)break;}return 0; }總結(jié)
以上是生活随笔為你收集整理的Vibe算法简介、优缺点、代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu 开启 apache mod
- 下一篇: 【RK3399Pro学习笔记】一、Thi