基于均值漂移(Mean Shift)的物体跟踪算法MATLAB 实现
均值漂移(Mean Shift)是一种非参数密度梯度估计方法,通过计算概率密度梯度的零点(峰值)实现目标定位。在计算机视觉中,常用于基于颜色直方图的物体跟踪,具有计算高效、对形变部分鲁棒的特点。
一、算法原理
- 目标表示:用颜色直方图(通常为 HSV 空间的 H 通道)描述目标外观。
- 相似性度量:用巴氏系数(Bhattacharyya Coefficient)衡量候选区域与目标直方图的相似度。
- 均值漂移迭代:在当前帧中,以目标位置为中心,计算候选区域的直方图,通过梯度上升找到相似度最大的新位置,重复直到收敛。
二、MATLAB 代码
2.1 主脚本 mean_shift_tracking.m
%% 基于均值漂移的物体跟踪
clear; clc; close all;
%% ===== 1. 生成模拟视频(带移动目标)=====
video_path = 'test_video.avi';
generate_test_video(video_path); % 手写模拟视频生成函数
fprintf('模拟视频已生成: %s\n', video_path);
%% ===== 2. 初始化跟踪参数 =====
params.window_radius = 25; % 跟踪窗口半径(像素)
params.bin_num = 16; % 直方图 bin 数量(H 通道分16级)
params.max_iter = 10; % 最大迭代次数
params.eps = 1.0; % 收敛阈值(像素)
% 打开视频
vid = VideoReader(video_path);
N_frames = vid.NumFrames;
% 读取第一帧,手动选择目标区域
frame = read(vid, 1);
figure('Color','w'); imshow(frame); title('请在目标上点击拖拽选择区域');
rect = getrect(); % 用户手动选择目标 [x, y, width, height]
target_pos = [rect(1)+rect(3)/2, rect(2)+rect(4)/2]; % 目标中心
target_size = [rect(3), rect(4)];
% 计算目标直方图
target_hist = calc_histogram(frame, target_pos, target_size, params.bin_num);
%% ===== 3. 开始跟踪 =====
track_pos = zeros(N_frames, 2); % 存储每帧跟踪位置
track_pos(1,:) = target_pos;
figure('Color','w','Position',[100 100 800 600]);
for f = 2:N_frames
frame = read(vid, f);
% 均值漂移迭代
[new_pos, iter] = mean_shift(frame, target_hist, track_pos(f-1,:), params);
track_pos(f,:) = new_pos;
% 可视化
subplot(1,2,1); imshow(frame); hold on;
rectangle('Position',[new_pos(1)-target_size(1)/2, new_pos(2)-target_size(2)/2, target_size(1), target_size(2)],...
'EdgeColor','r','LineWidth',2);
plot(new_pos(1), new_pos(2), 'ro', 'MarkerSize',8, 'MarkerFaceColor','r');
title(sprintf('帧 %d/%d | 迭代 %d 次', f, N_frames, iter));
hold off;
% 显示目标直方图
subplot(1,2,2); bar(target_hist); xlim([0 params.bin_num]);
title('目标颜色直方图 (H通道)');
drawnow;
end
%% ===== 4. 跟踪结果分析 =====
figure('Color','w');
subplot(1,2,1); plot(track_pos(:,1), track_pos(:,2), 'b.-'); grid on;
xlabel('X 像素'); ylabel('Y 像素'); title('跟踪轨迹');
subplot(1,2,2);
% 计算跟踪误差(假设第一帧位置为真值)
error = sqrt(sum((track_pos - track_pos(1,:)).^2, 2));
plot(1:N_frames, error, 'r-'); grid on;
xlabel('帧号'); ylabel('跟踪误差 (像素)'); title('跟踪稳定性');
sgtitle('均值漂移物体跟踪结果', 'FontSize',14, 'FontWeight','bold');
2.2 核心函数
2.2.1 生成模拟测试视频
function generate_test_video(video_path)
% 生成带移动目标的模拟视频
writer = VideoWriter(video_path);
writer.FrameRate = 30;
open(writer);
% 视频参数
frame_size = [480, 640, 3]; % 高×宽×通道
target_size = [60, 60]; % 目标大小
target_color = [255, 0, 0]; % 蓝色目标
% 目标运动轨迹(正弦曲线)
t = linspace(0, 2*pi, 100);
x_traj = 320 + 150*sin(t);
y_traj = 240 + 100*cos(t);
for f = 1:100
% 创建背景(灰色)
frame = uint8(ones(frame_size) * 128);
% 绘制目标
x = round(x_traj(f));
y = round(y_traj(f));
frame(y:y+target_size(1), x:x+target_size(2), 1) = target_color(1); % R
frame(y:y+target_size(1), x:x+target_size(2), 2) = target_color(2); % G
frame(y:y+target_size(1), x:x+target_size(2), 3) = target_color(3); % B
% 添加噪声
frame = uint8(double(frame) + 10*randn(size(frame)));
frame = max(0, min(255, frame));
writeVideo(writer, frame);
end
close(writer);
end
2.2.2 颜色直方图计算(HSV 空间 H 通道)
function hist = calc_histogram(frame, center, size, bin_num)
% 计算目标区域的颜色直方图(HSV 空间 H 通道)
x = round(center(1) - size(1)/2);
y = round(center(2) - size(2)/2);
w = round(size(1));
h = round(size(2));
% 边界检查
x = max(1, x); y = max(1, y);
x_end = min(size(frame,2), x+w-1);
y_end = min(size(frame,1), y+h-1);
% 提取区域
region = frame(y:y_end, x:x_end, :);
% RGB 转 HSV(手写实现)
hsv_region = rgb2hsv_manual(region);
% 取 H 通道(0-1 范围)
H = hsv_region(:,:,1);
% 计算直方图
hist = zeros(bin_num, 1);
for i = 1:bin_num
bin_low = (i-1)/bin_num;
bin_high = i/bin_num;
mask = (H >= bin_low) & (H < bin_high);
hist(i) = sum(mask(:));
end
% 归一化(避免光照影响)
hist = hist / (sum(hist) + eps);
end
function hsv = rgb2hsv_manual(rgb)
% 手写 RGB 转 HSV(简化版)
rgb = double(rgb) / 255;
r = rgb(:,:,1); g = rgb(:,:,2); b = rgb(:,:,3);
max_val = max(max(r,g),b);
min_val = min(min(r,g),b);
delta = max_val - min_val;
% 计算 H
h = zeros(size(r));
mask = delta > 0;
h(mask & max_val==r) = 60 * mod((g(mask)-b(mask))./delta(mask), 6);
h(mask & max_val==g) = 60 * ((b(mask)-r(mask))./delta(mask) + 2);
h(mask & max_val==b) = 60 * ((r(mask)-g(mask))./delta(mask) + 4);
h = h / 360; % 归一化到 0-1
% 计算 S
s = zeros(size(r));
s(mask) = delta(mask) ./ max_val(mask);
% 计算 V
v = max_val;
hsv = cat(3, h, s, v);
end
2.2.3 均值漂移迭代
function [new_pos, iter] = mean_shift(frame, target_hist, init_pos, params)
% 均值漂移迭代
current_pos = init_pos;
for iter = 1:params.max_iter
% 1. 计算候选区域直方图
candidate_hist = calc_histogram(frame, current_pos, [params.window_radius*2, params.window_radius*2], params.bin_num);
% 2. 计算巴氏系数(相似性)
bc = bhattacharyya_coefficient(target_hist, candidate_hist);
% 3. 计算权重(均值漂移向量)
weights = zeros(params.window_radius*2, params.window_radius*2);
for i = 1:params.window_radius*2
for j = 1:params.window_radius*2
bin_idx = get_bin_index(frame, current_pos, [i,j], params.bin_num);
if bin_idx > 0
weights(i,j) = sqrt(target_hist(bin_idx) / (candidate_hist(bin_idx) + eps));
end
end
end
% 4. 计算新位置(加权平均)
[X, Y] = meshgrid(-params.window_radius:params.window_radius-1, ...
-params.window_radius:params.window_radius-1);
new_x = sum(sum(X .* weights)) / (sum(weights(:)) + eps);
new_y = sum(sum(Y .* weights)) / (sum(weights(:)) + eps);
% 5. 更新位置
new_pos = current_pos + [new_x, new_y];
% 6. 检查收敛
if norm(new_pos - current_pos) < params.eps
break;
end
current_pos = new_pos;
end
end
function bc = bhattacharyya_coefficient(h1, h2)
% 巴氏系数(衡量两个直方图的相似度)
bc = sum(sqrt(h1 .* h2));
end
function bin_idx = get_bin_index(frame, center, offset, bin_num)
% 获取像素点的直方图 bin 索引
x = round(center(1) + offset(1) - bin_num/2);
y = round(center(2) + offset(2) - bin_num/2);
if x < 1 || x > size(frame,2) || y < 1 || y > size(frame,1)
bin_idx = 0;
return;
end
% 简化:直接取 RGB 平均值作为 bin 索引(实际应用 HSV 更准确)
pixel = double(frame(y,x,:))/255;
bin_idx = round(mean(pixel) * bin_num);
bin_idx = max(1, min(bin_num, bin_idx));
end
三、运行说明
3.1 直接运行
- 保存所有函数为
.m文件 - 运行
mean_shift_tracking.m - 在第一帧图像上手动拖拽选择目标区域
- 自动开始跟踪并显示结果
3.2 参数调优建议
| 参数 | 建议值 | 作用 |
|---|---|---|
window_radius |
20~40 | 跟踪窗口大小,需略大于目标尺寸 |
bin_num |
8~32 | 直方图 bin 数量,越多越精细但越慢 |
max_iter |
5~15 | 迭代次数,通常 5 次即可收敛 |
3.3 预期效果
- 跟踪轨迹:平滑跟随目标移动
- 稳定性:对目标轻微形变、部分遮挡鲁棒
- 速度:实时(>30 FPS)
参考代码 基于均值漂移算法的物体跟踪算法 www.youwenfan.com/contentcnw/82039.html
四、算法优缺点
| 优点 | 缺点 |
|---|---|
| 计算高效,适合实时跟踪 | 对快速运动目标容易丢失 |
| 无需训练,初始化简单 | 依赖颜色特征,易受光照变化影响 |
| 对部分遮挡鲁棒 | 窗口大小固定,不适应目标尺度变化 |
五、改进方向
- CamShift(连续自适应均值漂移):自动调整窗口大小适应目标尺度变化
- 多特征融合:结合颜色、纹理、边缘特征提高鲁棒性
- 卡尔曼滤波:预测目标运动,减少快速运动丢失
- 抗遮挡策略:引入重检测机制(如模板匹配)

浙公网安备 33010602011771号