CodeBook算法的基本思想是为每一个像素点建立一个codebook,每个codebook包含一个或者多个boxes,并且随着背景像素值波动情况的不同,不同像素点所包含的boxes数目不一定相同。
CodeBook算法为当前图像的每一个像素建立一个码本CodeBook(CB)结构,每个CodeBook由多个码元CodeWord(CW)组成。CB和CW的形式如下:
CB={CW1,CW2,…CWn,t}
CW={lHigh,lLow,max,min,t_last_update,stale}
其中n为一个CB中所包含的CW的数目,当n太小时,退化为简单背景,当n较大时可以对复杂背景进行建模;t为CB更新的次数。CW是一个6元组,其中IHigh和ILow作为更新时的学习上下界,max和min记录当前像素的最大值和最小值。t_last_update表示此码元最后一次更新的时间,stale表示此码元最长不更新时间(即该CW多久未被访问),用来删除很少使用的CodeWord,精简码本。
1 模型训练
假设当前训练图像I中某一像素为I(x,y),该像素的CB的更新算法如下,另外记背景阈值的增长判定阈值为Bounds:
(1) CB的访问次数加1;
(2) 遍历CB中的每个CW,如果存在一个CW中的IHigh,ILow满足ILow≤I(x,y)≤IHigh,则转(4);
(3) 创建一个新的码字CWnew加入到CB中, CWnew的max与min都赋值为I(x,y),IHigh <- I(x,y) + Bounds,ILow <- I(x,y) – Bounds,并且转(6);
(4) 更新该码字的t_last_update,若当前像素值I(x,y)大于该码字的max,则max <- I(x,y),若I(x,y)小于该码字的min,则min <- I(x,y);
(5) 更新该码字的学习上下界,以增加背景模型对于复杂背景的适应能力,具体做法是:若IHigh < I(x,y) + Bounds,则IHigh 增长1,若ILow > I(x,y) – Bounds,则ILow减少1;
(6) 更新CB中每个CW的stale。设定刷新时间,遍历每个码元,若码元中的不更新时间大于设定的刷新时间,则删除;在刷新时间内则保持。
2 背景检测
使用已建立好的CB进行运动目标检测,记判断前景的范围上下界为minMod和maxMod,对于当前待检测图像上的某一像素I(x,y),遍历它对应像素背景模型CB中的每一个码字CW,若存在一个CW,使得I(x,y) < max + maxMod并且I(x,y) > min – minMod,则I(x,y)被判断为背景,否则被判断为前景。
Opencv库
(1)legacy.hpp
typedef struct CvBGCodeBookElem
{
struct CvBGCodeBookElem* next;
int tLastUpdate; //码元最后一次更新时间
int stale; // 码元最长更新时间
uchar boxMin[3]; // 码元中包含像素的最小值
uchar boxMax[3];// 码元中包含像素的最大值
uchar learnMin[3];// 码元学习下界
uchar learnMax[3];// 码元学习上界
} CvBGCodeBookElem;
typedef struct CvBGCodeBookModel
{
CvSize size;
int t;
uchar cbBounds[3]; //背景阈值判定
uchar modMin[3]; //前景判定下界
uchar modMax[3];//前景判定上界
CvBGCodeBookElem** cbmap;
CvMemStorage* storage;
CvBGCodeBookElem* freeList;
} CvBGCodeBookModel;
(2)bgfg_codebook.cpp
主要包含三个函数 : 模型更新、码元精简、背景检测
1)模型更新
void cvBGCodeBookUpdate( CvBGCodeBookModel* model, const CvArr* _image,
CvRect roi, const CvArr* _mask )
{
CV_FUNCNAME( "cvBGCodeBookUpdate" );
__BEGIN__;
CvMat stub, *image = cvGetMat( _image, &stub );
CvMat mstub, *mask = _mask ? cvGetMat( _mask, &mstub ) : 0;
int i, x, y, T;
int nblocks;
uchar cb0, cb1, cb2;
CvBGCodeBookElem* freeList;
CV_ASSERT( model && CV_MAT_TYPE(image->type) == CV_8UC3 &&
(!mask || (CV_IS_MASK_ARR(mask) && CV_ARE_SIZES_EQ(image, mask))) );
if( roi.x == 0 && roi.y == 0 && roi.width == 0 &a