MATLAB实现,使用高斯混合模型(GMM)进行背景建模,并从视频中提取运动目标(特别是人体)。
matlab
function gaussian_background_modeling()
% 高斯背景建模与目标提取主函数
clear; clc; close all;
% 参数设置
video_source = 'pedestrians.avi'; % 视频文件路径
learning_rate = 0.005; % 背景学习率
num_gaussians = 3; % 每个像素的高斯分布数量
bg_ratio = 0.7; % 背景权重比例阈值
variance_threshold = 25; % 方差阈值
min_area = 500; % 最小目标面积(像素)
% 创建视频读取器
if exist(video_source, 'file') == 2
vid_reader = VideoReader(video_source);
else
error('视频文件不存在: %s', video_source);
end
% 获取第一帧并初始化
first_frame = readFrame(vid_reader);
if size(first_frame, 3) == 1
first_frame = cat(3, first_frame, first_frame, first_frame);
end
[height, width, ~] = size(first_frame);
% 初始化高斯模型参数
weights = ones(height, width, num_gaussians) / num_gaussians; % 权重
means = repmat(reshape(first_frame, height, width, 1, 3), [1, 1, num_gaussians, 1]); % 均值
variances = ones(height, width, num_gaussians) * 15; % 方差
background_mask = false(height, width); % 背景掩码
% 创建结果展示窗口
fig = figure('Name', '高斯背景建模与目标提取', 'NumberTitle', 'off', ...
'Position', [100, 100, 1200, 600], 'MenuBar', 'none');
% 主处理循环
frame_count = 0;
while hasFrame(vid_reader)
frame = readFrame(vid_reader);
frame_count = frame_count + 1;
if isempty(frame), break; end
if size(frame, 3) == 1
frame = cat(3, frame, frame, frame);
end
% 转换为双精度浮点型
frame_double = im2double(frame);
% 更新高斯模型
[background_mask, foreground_mask] = update_gmm_model(...
frame_double, weights, means, variances, learning_rate, ...
bg_ratio, variance_threshold, num_gaussians);
% 提取运动目标(人体)
detected_objects = extract_moving_objects(foreground_mask, min_area);
% 可视化结果
visualize_results(fig, frame, background_mask, foreground_mask, detected_objects, frame_count);
% 控制处理速度
pause(0.02);
end
% 释放视频资源
release(vid_reader);
end
function [bg_mask, fg_mask] = update_gmm_model(frame, weights, means, variances, lr, ratio_thresh, var_thresh, K)
% 更新高斯混合模型并返回背景/前景掩码
[h, w, ~] = size(frame);
fg_mask = false(h, w);
bg_mask = false(h, w);
% 遍历每个像素
for i = 1:h
for j = 1:w
pixel = squeeze(frame(i, j, :)); % 当前像素值 (1x3)
pixel_vec = reshape(pixel, 1, 1, 3); % 转换为1x1x3
% 获取当前像素的模型参数
w_ij = squeeze(weights(i, j, :)); % 权重 (1xK)
mu_ij = squeeze(means(i, j, :, :)); % 均值 (Kx3)
var_ij = squeeze(variances(i, j, :)); % 方差 (1xK)
% 计算马氏距离(简化版欧氏距离)
distances = sum((mu_ij - pixel_vec).^2, 3); % Kx1向量
% 找到最佳匹配的高斯分布
[min_dist, match_idx] = min(distances);
% 更新匹配的高斯分布
if min_dist < var_thresh(multiindex(match_idx)) % 阈值设为方差
% 更新权重、均值和方差
w_ij(match_idx) = (1 - lr) * w_ij(match_idx) + lr;
mu_ij(match_idx, :) = (1 - lr) * mu_ij(match_idx, :) + lr * pixel;
var_ij(match_idx) = (1 - lr) * var_ij(match_idx) + lr * min_dist;
% 更新其他高斯分布权重
w_ij = (1 - lr) * w_ij;
w_ij(match_idx) = w_ij(match_idx) + lr;
else
% 未匹配任何分布,替换最不匹配的分布
[~, worst_idx] = min(w_ij);
w_ij(worst_idx) = lr;
mu_ij(worst_idx, :) = pixel;
var_ij(worst_idx) = var_thresh;
% 更新其他高斯分布权重
w_ij = (1 - lr) * w_ij;
w_ij(worst_idx) = w_ij(worst_idx) + lr;
end
% 归一化权重
w_ij = w_ij / sum(w_ij);
% 确定背景模型
[sorted_w, sort_idx] = sort(w_ij, 'descend');
cum_sum = cumsum(sorted_w);
bg_components = cum_sum < ratio_thresh;
num_bg = sum(bg_components);
% 创建背景掩码
if any(distances(sort_idx(1:num_bg)) < 2.5 * sqrt(var_ij(sort_idx(1:num_bg))))
bg_mask(i, j) = true;
else
fg_mask(i, j) = true;
end
% 保存更新后的参数
weights(i, j, :) = w_ij;
means(i, j, :, :) = mu_ij;
variances(i, j, :) = var_ij;
end
end
end
function objects = extract_moving_objects(fg_mask, min_area)
% 从前景掩码中提取运动目标
% 形态学操作去除噪声
se = strel('disk', 3);
cleaned_mask = imopen(fg_mask, se);
cleaned_mask = imclose(cleaned_mask, se);
% 填充小孔
filled_mask = imfill(cleaned_mask, 'holes');
% 标记连通区域
[labeled, num_objects] = bwlabel(filled_mask, 8);
stats = regionprops(labeled, 'Area', 'BoundingBox', 'Centroid');
% 过滤小区域
valid_objects = [];
for k = 1:num_objects
if stats(k).Area >= min_area
valid_objects = [valid_objects; k];
end
end
% 创建目标结构
objects = struct('BoundingBox', {}, 'Centroid', {}, 'Area', {});
for idx = 1:length(valid_objects)
k = valid_objects(idx);
objects(idx).BoundingBox = stats(k).BoundingBox;
objects(idx).Centroid = stats(k).Centroid;
objects(idx).Area = stats(k).Area;
end
end
function visualize_results(fig, frame, bg_mask, fg_mask, objects, frame_num)
% 可视化结果
figure(fig);
clf;
% 显示原始帧
subplot(2, 2, 1);
imshow(frame);
title(sprintf('原始视频 (帧: %d)', frame_num));
% 显示背景模型
subplot(2, 2, 2);
background_img = uint8(repmat(bg_mask, [1, 1, 3]) * 255);
imshow(background_img);
title('背景模型');
% 显示前景掩码
subplot(2, 2, 3);
foreground_img = uint8(repmat(fg_mask, [1, 1, 3]) * 255);
imshow(foreground_img);
title('前景掩码');
% 显示检测结果
subplot(2, 2, 4);
result_img = frame;
for k = 1:length(objects)
bbox = objects(k).BoundingBox;
centroid = objects(k).Centroid;
% 绘制边界框
result_img = insertShape(result_img, 'Rectangle', bbox, ...
'Color', 'red', 'LineWidth', 2);
% 绘制质心
result_img = insertMarker(result_img, centroid, 'o', ...
'Color', 'green', 'Size', 10);
% 显示目标信息
label = sprintf('目标 %d: %.0f px', k, objects(k).Area);
result_img = insertText(result_img, [bbox(1), bbox(2)-20], label, ...
'FontSize', 12, 'BoxColor', 'yellow', 'TextColor', 'black');
end
imshow(result_img);
title(sprintf('检测到 %d 个目标', length(objects)));
drawnow;
end
% 辅助函数:多索引访问
function val = multiindex(idx)
persistent values;
if isempty(values)
values = [15, 25, 35]; % 不同高斯分布的方差阈值
end
val = values(min(idx, length(values)));
end
算法原理详解
高斯混合模型(GMM)背景建模
高斯混合模型假设每个像素的颜色分布可以由多个高斯分布的加权和表示:

其中:
-
KKK:高斯分布的数量(通常3-5个)
-
wi,tw_{i,t}wi,t:第iii个高斯分布在时间t的权重
-
μi,tμ_{i,t}μi,t:第i个高斯分布的均值
-
Σi,tΣ_{i,t}Σi,t:第iii个高斯分布的协方差矩阵
背景更新过程
-
匹配阶段:对于新像素值xt,找到与其最匹配的高斯分布(最小Mahalanobis距离)
-
更新阶段:
-
匹配成功:wi←(1−α)wi+α,(μi,Σi)w_i←(1−α)w_i+α,(μ_i,Σ_i)wi←(1−α)wi+α,(μi,Σi)按学习率更新
-
匹配失败:创建新分布或替换最不匹配的分布
-
-
背景判定:按权重排序高斯分布,累积权重超过阈值T的分布被视为背景
目标提取流程
-
前景分割:像素不属于背景模型则标记为前景
-
形态学处理:
-
开运算:去除小的亮点(噪声)
-
闭运算:填充小的孔洞
-
-
连通区域分析:
-
标记连通区域
-
过滤小面积区域(去除噪声)
-
提取边界框和质心
-
参数调优
| 参数 | 推荐值 | 作用 |
|---|---|---|
learning_rate |
0.001-0.01 | 背景模型更新速度 |
num_gaussians |
3-5 | 每个像素的高斯分布数量 |
bg_ratio |
0.7-0.9 | 背景权重累积阈值 |
variance_threshold |
15-50 | 高斯分布方差阈值 |
min_area |
200-1000 | 最小目标面积 |
参考代码 matlab实现高斯背景建模,并且提取运动目标(人体) www.youwenfan.com/contentcss/122377.html
实际应用技巧
-
阴影处理:
matlab% 在前景掩码后添加阴影抑制 shadow_mask = detect_shadows(fg_mask, frame); fg_mask(shadow_mask) = false; -
自适应参数:
matlab% 根据场景复杂度动态调整参数 if scene_complexity > threshold learning_rate = 0.01; min_area = 800; else learning_rate = 0.005; min_area = 400; end -
夜间场景优化:
matlab% 夜间使用红外通道或增强对比度 if is_night_scene(frame) frame = enhance_contrast(rgb2gray(frame)); end -
运动历史增强:
matlab% 使用运动历史图像增强目标连续性 mhi = update_mhi(fg_mask, prev_fg_mask, tau);
扩展功能
-
多目标跟踪:
matlab% 使用Kalman滤波跟踪目标 tracks = kalman_filter_update(tracks, detections); -
行为识别:
matlab% 分析目标运动模式 behavior = analyze_behavior(track_history); -
人群密度估计:
matlab% 基于目标计数估计人群密度 density = num_objects / area; -
异常事件检测:
matlab% 检测异常运动模式 anomaly_score = detect_anomaly(motion_features);
实际应用场景
-
智能监控系统:检测入侵者、遗留物品
-
交通监控:车辆计数、违章检测
-
零售分析:顾客行为分析、热力图生成
-
人机交互:手势识别、动作捕捉
-
视频摘要:提取关键运动片段
注意:对于实际应用,建议使用MATLAB的Computer Vision Toolbox中的
vision.ForegroundDetector对象,它提供了高度优化的高斯混合模型实现。本代码展示了算法的基本原理,可根据具体需求进行优化。