基于背景差分的自适应分割算法(OSTU优化版)

基于背景差分的自适应分割算法(OSTU优化版)

一、算法核心思想

背景差分 + OSTU自适应阈值 + 动态背景更新

视频序列 → 背景建模 → 差分计算 → OSTU分割 → 形态学优化 → 目标分割

二、算法流程设计

1 整体流程图

┌─────────────────────────────────────────────┐
│           自适应背景差分分割算法            │
├─────────────────────────────────────────────┤
│ 1. 初始化背景模型 B₀                     │
│ 2. For each frame Iₜ:                 │
│    ├── 3. 背景差分 Dₜ = |Iₜ - Bₜ₋₁|      │
│    ├── 4. OSTU自适应阈值 Tₜ = ostu(Dₜ) │
│    ├── 5. 前景分割 Mₜ = (Dₜ > Tₜ)       │
│    ├── 6. 形态学优化(开/闭运算)         │
│    └── 7. 自适应背景更新 Bₜ            │
└─────────────────────────────────────────────┘

三、OSTU算法原理(核心)

1 类间方差最大化

对于灰度图像,OSTU算法自动寻找最佳阈值 T,使得:

σ²_between(T) = ω₀ω₁(μ₀ - μ₁)²  → 最大

其中:

2 离散形式计算

# 灰度级 [0, L-1]
for T in range(L):
    计算类间方差
    选择最大方差对应的T

四、自适应背景建模

1 滑动平均背景模型

// 背景更新公式(指数衰减)
B_current = α × I_current + (1-α) × B_previous

2 多模态背景(改进版)

class AdaptiveBackground:
    def __init__(self, height, width):
        self.bg_mean = np.zeros((height, width), dtype=np.float32)
        self.bg_variance = np.ones((height, width), dtype=np.float32) * 100
        self.alpha = 0.05  # 学习率
    
    def update(self, frame):
        # 差分
        diff = cv2.absdiff(frame, self.bg_mean.astype(np.uint8))
        
        # 动态更新
        mask = diff < 50  # 背景区域才更新
        self.bg_mean[mask] = (
            self.alpha * frame[mask] + 
            (1 - self.alpha) * self.bg_mean[mask]
        )

五、完整C语言实现(嵌入式友好)

1 数据结构定义

typedef struct {
    uint8_t* bg_model;      // 背景模型
    uint8_t* fg_mask;        // 前景掩码
    float alpha;             // 学习率
    int width;
    int height;
} BGSubtractor_t;

2 OSTU阈值计算(核心函数)

/**
 * @brief OSTU自适应阈值计算
 * @param hist 灰度直方图
 * @param pixel_count 总像素数
 * @return 最佳阈值
 */
uint8_t ostu_threshold(uint32_t* hist, uint32_t pixel_count)
{
    float sum = 0;
    for (int i = 0; i < 256; i++) {
        sum += i * hist[i];
    }
    
    float sumB = 0;
    uint32_t wB = 0;
    uint32_t wF = 0;
    float max_variance = 0;
    uint8_t threshold = 0;
    
    for (int t = 0; t < 256; t++) {
        wB += hist[t];
        if (wB == 0) continue;
        
        wF = pixel_count - wB;
        if (wF == 0) break;
        
        sumB += (float)(t * hist[t]);
        float mB = sumB / wB;
        float mF = (sum - sumB) / wF;
        
        float variance = (float)wB * (float)wF * (mB - mF) * (mB - mF);
        
        if (variance > max_variance) {
            max_variance = variance;
            threshold = t;
        }
    }
    return threshold;
}

3 背景差分与分割

void adaptive_bg_segmentation(BGSubtractor_t* bg, uint8_t* frame)
{
    uint32_t hist[256] = {0};
    uint8_t diff[bg->width * bg->height];
    
    // 1. 背景差分
    for (int i = 0; i < bg->width * bg->height; i++) {
        diff[i] = abs(frame[i] - bg->bg_model[i]);
        hist[diff[i]]++;  // 统计直方图
    }
    
    // 2. OSTU自适应阈值
    uint8_t thresh = ostu_threshold(hist, bg->width * bg->height);
    
    // 3. 二值化分割
    for (int i = 0; i < bg->width * bg->height; i++) {
        bg->fg_mask[i] = (diff[i] > thresh) ? 255 : 0;
    }
    
    // 4. 自适应背景更新
    for (int i = 0; i < bg->width * bg->height; i++) {
        if (diff[i] < thresh) {  // 仅更新背景区域
            bg->bg_model[i] = (uint8_t)(
                bg->alpha * frame[i] + 
                (1.0f - bg->alpha) * bg->bg_model[i]
            );
        }
    }
}

4 形态学优化(去噪)

void morphology_optimization(uint8_t* mask, int width, int height)
{
    // 开运算:去噪点
    cv2_morphology(mask, width, height, MORPH_OPEN, 3);
    
    // 闭运算:填洞
    cv2_morphology(mask, width, height, MORPH_CLOSE, 5);
}

参考代码 OSTU算法实现背景差分的自适应分割算法 www.youwenfan.com/contentcst/122353.html

六、STM32优化实现

1 内存优化策略

// 使用定点运算替代浮点
#define ALPHA_Q8 13   // 0.05 * 256 ≈ 13

// 背景更新(定点)
bg_model[i] = (ALPHA_Q8 * frame[i] + 
               (256 - ALPHA_Q8) * bg_model[i]) >> 8;

2 查表加速OSTU

// 预计算平方和
static uint32_t sum_table[256];
static uint32_t sq_sum_table[256];

void init_ostu_tables(void)
{
    sum_table[0] = 0;
    sq_sum_table[0] = 0;
    for (int i = 1; i < 256; i++) {
        sum_table[i] = sum_table[i-1] + i;
        sq_sum_table[i] = sq_sum_table[i-1] + i*i;
    }
}

3 DMA + DCMI 优化

// STM32 + OV2640 摄像头
void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
    // 获取图像数据
    uint8_t* frame = camera_buffer;
    
    // 执行分割
    adaptive_bg_segmentation(&bg_subtractor, frame);
    
    // 处理结果
    process_segmentation_result(bg_subtractor.fg_mask);
}

七、性能评估指标

指标 计算公式 目标值
误检率 (FPR) FP/(FP+TN) < 5%
漏检率 (FNR) FN/(FN+TP) < 10%
处理速度 FPS > 30 (640×480)
内存占用 RAM < 100KB

八、算法改进方向

1多模态背景(ViBe改进)

# 为每个像素维护多个背景样本
samples = [bg1, bg2, bg3, bg4, bg5]

# 决策:当前像素与样本差异是否足够小
if sum(|frame - samples| < radius) >= min_samples:
    background
else:
    foreground

2阴影抑制

// HSV颜色空间阴影检测
if (V_diff < T_v && S_diff < T_s) {
    shadow_pixel = true;
}

3 深度学习结合


九、完整使用示例

int main(void)
{
    // 初始化
    BGSubtractor_t bg;
    bg.width = 320;
    bg.height = 240;
    bg.alpha = 0.05f;
    bg.bg_model = malloc(320 * 240);
    bg.fg_mask = malloc(320 * 240);
    
    // 初始化背景
    memset(bg.bg_model, 0, 320 * 240);
    
    while(1) {
        uint8_t* frame = capture_frame();
        adaptive_bg_segmentation(&bg, frame);
        display_result(bg.fg_mask);
    }
}

十、总结

OSTU自适应阈值解决光照变化问题
指数衰减背景更新适应动态场景
形态学优化提升分割质量
定点运算优化适合STM32嵌入式平台

专注于matlab/simulink,电子电路,编程