Vibe算法官网:http://www2.ulg.ac.be/telecom/research/vibe/
Vibe算法相关论文:
年份 | 论文题目 | 作者 | 论文内容 |
---|---|---|---|
2009 | ViBe: a powerful random technique to estimate the background in video sequences | Olivier Barnich,M. Van Droogenbroeck | 简要介绍了Vibe算法的思路 |
2011 | ViBe: A Universal Background Subtraction Algorithm for Video Sequences | Olivier Barnich,M. Van Droogenbroeck | 详细介绍了Vibe算法的实现细节 |
2012 | Background Subtraction: Experiments and Improvements for ViBe | M. Van Droogenbroeck,O. Paquot | 对Vibe算法作出一些修改,并对二值化后的各连通域添加了后处理,对阴影没有进一步处理,称为Vibe+算法 |
2014 | ViBe: A Disruptive Method for Background Subtraction | M. Van Droogenbroeck,O. Barnich. | 总结Vibe算法,讨论了对Vibe相关改进的论文,详细比较Vibe算法与其他建模方法的速度 |
2011年Vibe算法论文中的用于灰度图像的伪代码(与原文一致,仅翻译注释):
//Vibe的固定参数
//每个像素的样本数量
int N = 20;
//球体的半径
int R = 20;
//分类为背景的匹配样本数
int #min = 2;
//更新因子
int φ = 16;
//图像的宽,高
int width,height;
//当前图像
byte image[width][height];
//背景模型
byte samples[width][height][N];
//背景/前景分割图
byte segMap[width][height];
//二值化
byte background = 0;
byte foreground = 255;
//处理每个像素
for(int x = 0;x < width;x++){
for(int y = 0;y < height;y++){
//1.比较当前像素和背景模型
int count = 0,index = 0,dist = 0;
while((count < #min)&&(index < N)){
//计算欧式距离
dist = EuclidDist(image[x][y],samples[x][y][index]);
if(dist < R){
count++;
}
index++;
}
//2.分类并更新模型
if(count >= #min){
//image[x][y]分类为背景
segMap[x][y] = background;
//3.更新当前像素模型
//获得0到φ-1之间的随机数
int rand = getRandomNumber(0,φ-1);
if(rand == 0){//随机子采样
//随机选择样本进行替换
rand = getRandomNumber(0,N-1);
samples[x][y][rand] = image[x][y];
}
//4.更新邻域像素模型
rand = getRandomNumber(0,φ-1);
if(rand == 0){//随机子采样
//随机选择邻域像素
int xNG,yNG;
xNG = getRandomNeighbrXCoordinate(x);
yNG = getRandomNeighbrYCoordinate(y);
//随机替换所选像素的样本
rand = getRandomNumber(0,N-1);
samples[xNG][yNG][rand] = image[x][y];
}
}else{//count < #min
//image[x][y]分类为前景
segMap[x][y] = foreground;
}
}
}
Vibe:
- 算法思路: 为每个像素点建立一个代表背景的样本集,对新的一帧(x,y)处的像素值依次与(x,y)的样本集中的各样本进行比较,若其与样本集中某个样本的距离小于R的话,则匹配个数+1,若最终匹配个数 >= #min,则判断为背景,否则判断为前景。
- 模型初始化: 一帧便能完成初始化,每个像素点的样本集通过随机选择8邻域中的值来进行填充,即从8邻域中随机选择N次,这N个样本组成该点的样本集。
- 前景/背景的分类: 后续每帧计算(x,y)处像素点的像素值与该像素点样本集中样本的像素值的欧几里得距离,若距离 < R,则认为有一个样本与之匹配,若匹配个数 >= #min,则判断为背景(黑),否则为前景(白)。
- 模型更新: 若判断为背景,则有1/φ的几率随机替换样本集中的某个样本,还有1/φ的几率随机替换8邻域中某像素点样本集的某个样本。
- 涉及参数: N(每个像素点的背景模型样本数量),R(球体的半径),#min(匹配个数),φ(更新因子),原文中经测试得到的最佳参数为N=20,R=20,#min=2,φ=16。
Vibe↓:
- 改进: Vibe↓指的是Vibe的简化版本,用小的N和#min可以进一步降低Vibe算法的计算成本。Vibe↓相对于Vibe仅仅只是修改了参数,Vibe↓使用参数N=1,#min=1
Vibe+:
- 改进:
- 当检测到相机抖动时,将φ(更新因子)由16修改为5(或者1)。
- 区分分割蒙版和更新蒙版,即Vibe+算法二值化后进行不同的处理。
分割蒙版: 删除面积 <= 10(像素)的连通域,填充前景空洞面积 <= 20(像素)的区域,与图像边界接触的连通域无论面积是多少都保留。(该蒙版就是最终得到的二值化图像)
更新蒙版: 填充前景空洞面积 <= 50(像素)的区域,不会删除任何一个被判断为前景的像素点。(使用该蒙版来更新样本集) - 抑制空间传播机制,计算内边界上的梯度(缩放至[0,255]范围),若梯度 > 50,则禁止该像素点的空间传播,可以避免背景值穿过物体边界。(为了延缓静态对象融入背景中)
- 样本匹配策略的修改,要求颜色失真 < 20(颜色失真的度量公式使用CodeBook方法中的)且像素值距离 < 0.5σ(σ是该像素点样本集的标准差,即Vibe中的R = 20改为R = 0.5σ,0.5σ的范围限制在[20,40]),要同时满足这两个条件才算匹配。(引入了颜色失真度量+自适应阈值)
- 闪烁像素检测,认为经常在背景和前景来回变化的像素点是闪烁像素,对每个像素点保存其上一帧的更新蒙版和闪烁等级,若该像素属于背景的内边界,并且当前更新蒙版和先前更新蒙版不同,则闪烁等级+15,否则-1。(闪烁等级范围[0,150],在∑-Δ方法中使用过)若闪烁等级 >= 30,则认为正在闪烁并将其从更新蒙版中移除。(相机晃动时,禁用闪烁像素检测)
注: 相机抖动的判断使用KLT算法,在首帧选择100个特征,在后续的100帧进行跟踪,若跟踪特征的水平和垂直位移均 < 1个像素,则认为该帧是静态,否则动态。再对这100帧进行多数表决,若100帧中有50帧以上为动态,则认为存在相机抖动。
- 原文使用参数: N=20,R=0.5σ(范围[20,40]),颜色失真阈值=20,#min=2,对于前100帧φ=1,后续帧φ=5,抑制空间传播阈值=50(范围[0,255]),闪烁等级阈值=30(范围[0,150])。
分割蒙版: 最小的前景连通域=10(像素),前景最小的空洞=20(像素)
更新蒙版: 前景最小的空洞=50(像素)
附:
自己根据论文用Python实现的,供参考
Vibe算法代码:https://github.com/ZZZZZZZJJHHH/Vibe