vibe背景建模

// vibe背景建模

#ifndef vibe_h
#define vibe_h

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

#define VIBE_DEF_MODEL_NUM          (1)
#define VIBE_DEF_STEP               (8)
#define VIBE_DEF_NUM_SAMPLE         (20)
#define VIBE_DEF_MIN_MATCHS         (2)
#define VIBE_DEF_RADIUS             (15)
#define VIBE_DEF_RAND_SAMPLES       (4)
#define VIBE_DEF_STATIC_FG_FRAMES   (200)

typedef struct{
    int w, h;           //输入图像宽高
    int model_num;      //多模型, def=1。 (适用于固定多阶AE)
    int step;           //采样步长, bg/fg图像尺寸=[w/step, h/step] (控制内存/耗时与精度间平衡)
    int num_samples;    //单像素样本数, def=20
    int min_matchs;     //Match Number of make pixel as Background, def=2。 (背景判断,约小前景越灵敏)
    int radius;         //Radius of pixel value, def=15。 (前景与背景差异阈值,越小前景越灵敏)
    int rand_samples;   //probability of random sample, def=4。 (控制背景更新速度,越大越慢)
    int static_fg_frames;//连续判断为fg的帧数,达到阈值后该像素会被设置成bg, def=200。 (由于类型限制,需小于255)
} VIBE_PARAMS;

typedef struct{
    VIBE_PARAMS params;
    int model_idx;              //当前命中模型索引(多模型)
    int *bg_mean_val;           //背景灰度均值
    unsigned char *bg_samples;  //背景模型
    unsigned char *fg;          //前景mask
} VIBE_MODEL;


/*获取默认参数*/
void vibe_get_def_params(int w, int h, VIBE_PARAMS *vibe_params);

/*初始化*/
int vibe_init(VIBE_PARAMS vibe_params, void **vibe_model);

/*主算法*/
void vibe_run(void *vibe_model, unsigned char *image, int image_w, int image_h);

/*获取前景*/
void vibe_get_fg(void *vibe_model, unsigned char **fg);

/*获取背景*/
void vibe_get_bg(void *vibe_model, int bg_w, int bg_h, unsigned char *bg);

/*资源释放*/
void vibe_release(void *vibe_model);

#ifdef __cplusplus
}
#endif

#endif /* vibe_h */

#include "vibe.h"
#include <string.h>
#include <stdlib.h>

#define BG_VAL (0)
#define FG_VAL (255)

// Compute a pseudorandom integer.
// Output value in range [0, 32767]
static unsigned int g_seed = 123;
static inline int fast_rand(void) {
    g_seed = (214013*g_seed+2531011);
    return (g_seed>>16)&0x7FFF;
}

void vibe_get_def_params(int w, int h, VIBE_PARAMS *vibe_params){
    vibe_params->w = w;
    vibe_params->h = h;
    vibe_params->model_num = VIBE_DEF_MODEL_NUM;
    vibe_params->step = VIBE_DEF_STEP;
    vibe_params->num_samples = VIBE_DEF_NUM_SAMPLE;
    vibe_params->min_matchs = VIBE_DEF_MIN_MATCHS;
    vibe_params->radius = VIBE_DEF_RADIUS;
    vibe_params->rand_samples = VIBE_DEF_RAND_SAMPLES;
    vibe_params->static_fg_frames = VIBE_DEF_STATIC_FG_FRAMES;
}

int vibe_init(VIBE_PARAMS vibe_params, void **vibe_model){
    int ret = 0, bg_size, fg_size;
    if(vibe_params.h % vibe_params.step != 0 || vibe_params.w % vibe_params.step != 0)
        return -1;
    
    if(NULL == *vibe_model){
        *vibe_model = malloc(sizeof(VIBE_MODEL));
        if(!(*vibe_model)) {
            ALOGE("%s %d failed!\n", __FUNCTION__, __LINE__);
            ret = -2;
            goto ERR;
        }
        
        VIBE_MODEL *model = (VIBE_MODEL *)(*vibe_model);
        bg_size = vibe_params.model_num * vibe_params.h * vibe_params.w * (vibe_params.num_samples+1) / (vibe_params.step * vibe_params.step);// 数组中,在num_samples之外多增的一个值,用于统计该像素点连续成为前景的次数;
        model->bg_samples = (unsigned char *)malloc(bg_size);
        if(!model->bg_samples) {
            ALOGE("%s %d failed!\n", __FUNCTION__, __LINE__);
            ret = -3;
            goto ERR;
        }
        memset(model->bg_samples, 0, bg_size);
        
        fg_size = vibe_params.h * vibe_params.w / (vibe_params.step * vibe_params.step);
        model->fg = (unsigned char *)malloc(fg_size);
        if(!model->fg) {
            ALOGE("%s %d failed!\n", __FUNCTION__, __LINE__);
            ret = -4;
            goto ERR;
        }
        memset(model->fg, 0, fg_size);
        
        model->bg_mean_val = (int *)malloc(vibe_params.model_num * sizeof(int));
        if(!model->bg_mean_val) {
            ALOGE("%s %d failed!\n", __FUNCTION__, __LINE__);
            ret = -5;
            goto ERR;
        }
        memset(model->bg_mean_val, 0, vibe_params.model_num * sizeof(int));
        
        memcpy(&(model->params), &vibe_params, sizeof(VIBE_PARAMS));
    }
    return 0;
    
ERR:
    if(*vibe_model){
        VIBE_MODEL *model = (VIBE_MODEL *)(*vibe_model);
        if(model->bg_samples)
            free(model->bg_samples);
        if(model->fg)
            free(model->fg);
        free(*vibe_model);
    }
    
    return ret;
}

int vibe_get_image_mean(VIBE_PARAMS params, unsigned char *image){
    int mean = 0;
    unsigned char *p;
    for(int i = 0; i < params.h; i+=params.step){
        p = image + params.w * i;
        for(int j = 0; j < params.w; j+=params.step){
            mean += p[j];
        }
    }
    mean /= (params.h*params.w/(params.step*params.step));
    
    return mean;
}

int vibe_get_model_idx(VIBE_MODEL *model, unsigned char *image){
    int model_idx = 0;
    int min_diff = 255, diff;
    int image_mean = vibe_get_image_mean(model->params, image);
    //选择灰度差最小的模型
    for(int i = 0; i < model->params.model_num; i++){
        diff = abs(image_mean - model->bg_mean_val[i]);
        if(diff < min_diff){
            min_diff = diff;
            model_idx = i;
        }
    }
    //灰度差太大时,切到空模型
    for(int i = 0; i < model->params.model_num; i++){
        if(model->bg_mean_val[i] == 0 && min_diff > 5){
            model_idx = i;
            break;
        }
    }
    return model_idx;
}

void vibe_run_fisrt_frame(VIBE_MODEL *model, unsigned char *image){
    VIBE_PARAMS *params = &(model->params);
    int row, col;
    int c_off[9] = {-1, 0, 1, -1, 1, -1, 0, 1, 0};
    int bg_h = params->h / params->step;
    int bg_w = params->w / params->step;
    int chn = params->num_samples+1;
    int stride = bg_w * chn;
    int model_buff_oft = bg_h * bg_w * chn * model->model_idx;
    
    model->bg_mean_val[model->model_idx] = 0;
    for(int i = 0; i < bg_h; i++){
        for(int j = 0; j < bg_w; j++){
            unsigned char *psamples = model->bg_samples + model_buff_oft + stride * i + chn * j;
            for(int k = 0 ; k < params->num_samples; k++){
                // 随机选择num_samples个邻域像素点,构建背景模型
                int random;
                random = fast_rand() % 9; row = i * params->step + c_off[random];
                random = fast_rand() % 9; col = j * params->step + c_off[random];

                // 防止选取的像素点越界
                if (row < 0)  row = 0;
                if (row >= params->h)  row = params->h - 1;
                if (col < 0)  col = 0;
                if (col >= params->w)  col = params->w - 1;

                // 为样本库赋随机值
                psamples[k] = image[params->w * row + col];
            }
            //update bg mean
            model->bg_mean_val[model->model_idx] += psamples[0];
        }
    }
    model->bg_mean_val[model->model_idx] /= (bg_h*bg_w);
}

void vibe_run_frame(VIBE_MODEL *model, unsigned char *image){
    VIBE_PARAMS *params = &(model->params);
    int c_off[9] = {-1, 0, 1, -1, 1, -1, 0, 1, 0};
    int bg_h = params->h / params->step;
    int bg_w = params->w / params->step;
    int chn = params->num_samples+1;
    int stride = bg_w * chn;
    int model_buff_oft = bg_h * bg_w * chn * model->model_idx;
    int k = 0, dist = 0, matches = 0;
    
    model->bg_mean_val[model->model_idx] = 0;
    for(int i = 0; i < bg_h; i++){
        for(int j = 0; j < bg_w; j++){
            unsigned char *psamples = model->bg_samples + model_buff_oft + stride * i + chn * j;
            unsigned char *pfg = model->fg + bg_w * i + j;
            unsigned char img_val = image[(params->w * i + j) * params->step];
            
            //计算当前像素值与背景样本的匹配情况
            for(k = 0, matches = 0; matches < params->min_matchs && k < params->num_samples; k++){
                dist = abs(psamples[k] - img_val);
                if (dist < params->radius)
                    matches++;
            }
            
            if (matches >= params->min_matchs) {
                // 已经认为是背景像素,故该像素的前景统计次数置0
                psamples[params->num_samples] = 0;

                // 该像素点被的前景模型像素值置0
                *pfg = BG_VAL;
            }
            else {
                // 已经认为是前景像素,故该像素的前景统计次数+1
                psamples[params->num_samples]++;

                // 该像素点被的前景模型像素值
                *pfg = FG_VAL;

                // 如果某个像素点连续static_fg_frames次被检测为前景,则认为一块静止区域被误判为运动,将其更新为背景点
                if(psamples[params->num_samples] > params->static_fg_frames) {
                    int random = fast_rand() % params->num_samples;
                    psamples[random] = img_val;
                }
            }
            
            // 更新模型样本库
            if (matches >= params->min_matchs){
                // 已经认为该像素是背景像素,那么它有 1 / φ 的概率去更新自己的模型样本值
                int random = fast_rand() % params->rand_samples;
                if (random == 0) {
                    random = fast_rand() % params->num_samples;
                    psamples[random] = img_val;
                }

                // 同时也有 1 / φ 的概率去更新它的邻居点的模型样本值
                random = fast_rand() %  params->rand_samples;
                if (random == 0) {
                    int row, col;
                    random = fast_rand() % 9; row = i + c_off[random];
                    random = fast_rand() % 9; col = j + c_off[random];

                    // 防止选取的像素点越界
                    if (row < 0) row = 0;
                    if (row >= bg_h) row = bg_h - 1;
                    if (col < 0) col = 0;
                    if (col >= bg_w) col = bg_w - 1;

                    // 为样本库赋随机值
                    random = fast_rand() % params->num_samples;
                    model->bg_samples[model_buff_oft + stride * row + chn * col + random] = img_val;
                }
            }
            
            //update bg mean
            model->bg_mean_val[model->model_idx] += psamples[0];
        }
    }
    model->bg_mean_val[model->model_idx] /= (bg_h*bg_w);
}

void vibe_run(void *vibe_model, unsigned char *image, int image_w, int image_h){
    VIBE_MODEL *model = (VIBE_MODEL *)vibe_model;
    if(!model || model->params.w != image_w || model->params.h != image_h)
        return;
    
    //根据灰度均值,选择多模型其中一个
    model->model_idx = vibe_get_model_idx(model, image);

    //背景模型第一帧
    if(model->bg_mean_val[model->model_idx] == 0){
        vibe_run_fisrt_frame(model, image);
    }
    else{
        vibe_run_frame(model, image);
    }
}

void vibe_get_fg(void *vibe_model, unsigned char **fg){
    VIBE_MODEL *model = (VIBE_MODEL *)vibe_model;
    if(!model || !fg)
        return;
    
    *fg = model->fg;
}

void vibe_get_bg(void *vibe_model, int bg_w, int bg_h, unsigned char *bg){
    VIBE_MODEL *model = (VIBE_MODEL *)vibe_model;
    if(!model || !bg)
        return;
    if(model->params.w / model->params.step != bg_w ||
       model->params.h / model->params.step != bg_h)
        return;

    int chn = model->params.num_samples+1;
    int stride = bg_w * chn;
    int model_buff_oft = bg_h * bg_w * chn * model->model_idx;
    for(int i = 0; i < bg_h; i++){
        for(int j = 0; j < bg_w; j++){
            bg[bg_w*i + j] = model->bg_samples[model_buff_oft + stride*i + chn*j];
        }
    }
}

void vibe_release(void *vibe_model){
    if(vibe_model){
        VIBE_MODEL *model = (VIBE_MODEL *)vibe_model;
        if(model->bg_samples)
            free(model->bg_samples);
        if(model->fg)
            free(model->fg);
        free(vibe_model);
        if(model->bg_mean_val)
            free(model->bg_mean_val);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值