基于背景差分的自适应分割算法(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
α ∈ [0.01, 0.1]:更新速率- 静态场景:α = 0.01
- 动态背景:α = 0.05
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 深度学习结合
- 使用轻量级CNN(MobileNet-SSD)
- 在STM32上部署TFLite Micro
九、完整使用示例
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嵌入式平台