近期学习了meanshift,kalman滤波器和CAMshift的原理,简单总结一下。
- 我觉得学习理论最好的方法就是结合代码一块取学。
因此通过讲解代码的方式学习,有助于理解
matlab代码的话等完善后上传一下。
2020.5.18 更新了meanshift和kalman的代码
2020.5.30 写了一点遮挡问题挖个坑,下个月把CAMshift的代码讲一讲
2020.6.13 上传了github代码,记得帮忙点个starhttps://github.com/SunHaoOne/CAMshift-matlab
2020.7.22 更新了下ppt讲解的内容,即本文的图片部分,有详尽的动画过程帮助你理解这些概念,有需要的希望支持一下。https://download.csdn.net/download/qwe900/12650199
目标跟踪的分类
- 生成式模型(generative)
在当前帧对目标区域建模,下一帧寻找与模型最相似的区域为预测位置,比较著名的有卡尔曼滤波,粒子滤波,mean-shift。
但这一类方法没有考虑目标的背景信息,图像信息没有得到较好的应用。
- 判别式模型(discrimination)
将目标跟踪看作一个二元分类问题,提取目标和背景信息训练分类器,将目标从背景中分离出来,得到当前帧的目标位置。
如支持向量机,当前帧以目标区域为正样本,背景区域为负样本,用机器学习方法训练分类器,下一帧用训练好的分类器找最优区域。
而主流的方向似乎都是机器学习多一些,但自己还没有了解清楚原理。SVM的话以前接触过,但数学理论方面不过关,推导的话比较吃力,准备最近再试着学习一遍。
此外,目标跟踪的学习需要指标的分析,来判断你跟踪效果好不好,常见的分析见[https://blog.csdn.net/qwe900/article/details/106587322],包含了matlab代码
Mean Shift
即均值漂移算法,向概率密度最大的方向移动。


具体数学推导可以参考相关文章,这里简单说一下它的特点。
是一种半自动的跟踪办法,首先取得起始帧的图片,通过比较相似度最大的图片方向移动。
- 搜索窗口不变,每次的搜索半径一样
- 每次计算质心,向概率密度最大的方向移动
下面是一段meanshift的代码,在前人基础上结合自己的理解简单想一下
MEANSHIFT代码
- main.c
主函数由两部分组成,其中
主函数的第一部分是载入图片,做预处理,将图片按顺序导入。
%% 载入图片
imPath = 'C:\Users\Administrator\Desktop\毕业设计\matlab学习\constrast'; imExt = 'jpg'; %定义文件路径
%检查图片文件路径是否存在
if isdir(imPath) == 0
error('USER ERROR : The image directory does not exist');
end
%载入路径中的文件
filearray = dir([imPath filesep '*.' imExt]); % 获取目录下所有文件
NumImages = size(filearray,1); %图片数量
if NumImages < 0
error('No image in the directory');
end
disp('Loading image files from the video sequence, please be patient...');
%获取图片参数
imgname = [imPath filesep filearray(1).name]; %获取图片名
I = imread(imgname);
VIDEO_WIDTH = size(I,2);
VIDEO_HEIGHT = size(I,1);
ImSeq = zeros(VIDEO_HEIGHT, VIDEO_WIDTH, NumImages);%读取目录下全部图片
for i=1:NumImages
imgname = [imPath filesep filearray(i).name]; %获取图片名
ImSeq(:,:,i) = imread(imgname); %放入所有图片
end
disp(' ... OK!');
主函数的第二部分是meanshift算法,主要思路是计算当前帧和上一帧的模型,比较相似度来判断跟踪目标。
%% 初始化跟踪器
%在第一帧图片中框出感兴趣区域作为跟踪目标
% 使用函数imcrop手动初始化,框出跟踪目标,该函数用于返回图像的一个裁剪区域。可把图像显示在一个图像窗口中, 并允许用户以交互方式使用鼠标选定要剪切的区域。
[patch, rect] = imcrop(ImSeq(:,:,1)./255);%rect输出左上角横纵坐标 宽度 高度
%获取ROI参数(中心点坐标/宽度/高度),ROI(region of interest),感兴趣区域
ROI_Center = round([rect(1)+rect(3)/2 , rect(2)+rect(4)/2]);
ROI_Width = rect(3);
ROI_Height = rect(4);
rectangle('Position', rect, 'EdgeColor','r');%画矩阵框出初始目标位置
%**********MEANSHIFT跟踪算法**********
%%首先定义目标的颜色模型,计算颜色概率分布
% compute target object color probability distribution given the center and size of the ROI
imPatch = extract_image_patch_center_size(ImSeq(:,:,1), ROI_Center, ROI_Width, ROI_Height);
%该函数截取了感兴趣区域的颜色数据
%RGB颜色空间中的颜色分布
Nbins = 8;
TargetModel = color_distribution(imPatch, Nbins);%以上函数用来计算目标模型的qu概率密度
%
figure('name', 'Mean Shift Algorithm', 'units', 'normalized', 'outerposition', [0 0 1 1]);
prev_center = ROI_Center;
disp(prev_center);
for n = 2:NumImages
%读取下一帧图片
I = ImSeq(:,:,n);
while(1)
% STEP 1
% 计算上一帧目标中心位置的PDF,即候选模型
imPatch = extract_image_patch_center_size(I, prev_center, ROI_Width, ROI_Height);
ColorModel = color_distribution(imPatch, Nbins);
% 计算目标模型和候选模型之间的相似程度-bhattacharyya距离
rho = compute_bhattacharyya_coefficient(TargetModel, ColorModel);
% STEP 2, 3
% 计算候选模型区域每个像素点的权重
weights = compute_weights_NG(imPatch, TargetModel, ColorModel, Nbins);
% 计算mean-shift vector得到新的候选中心位置
z = compute_meanshift_vector(imPatch, prev_center, weights);
new_center = round(z);
% STEP 4, 5计算新的候选模型和相似度
imPatch2 = extract_image_patch_center_size(I, new_center, ROI_Width, ROI_Height);
ColorModel2 = color_distribution(imPatch2, Nbins);
% 相似度
rho2 = compute_bhattacharyya_coefficient(TargetModel, ColorModel2);
while(rho2<rho)%当移动后的候选位置相似度小于移动前的时候 进行以下迭代搜索
new_center = (prev_center+new_center)/2;
imPatch2 = extract_image_patch_center_size(I, new_center, ROI_Width, ROI_Height);
ColorModel2 = color_distribution(imPatch2, Nbins);
rho2 = compute_bhattacharyya_coefficient(TargetModel, ColorModel2);% 相似度
end
% STEP 6
if norm(new_center-prev_center, 1) < 0.0001
break
end
prev_center = new_center;
end
disp(new_center);
subplot(1,1,1); imshow(I, []);
hold on;
plot(new_center(1), new_center(2) , '+', 'Color', 'r', 'MarkerSize',10);
rectangle('Position',[new_center(1)-ROI_Width/2,new_center(2)-ROI_Height/2,ROI_Width,ROI_Height], 'EdgeColor','r')
% drawnow;
end
- extract_image_patch_center_size.m
这个子函数主要是将当前的区域提取出来,取个整。
function imPatch = extract_image_patch_center_size(I, c, w, h)
% This function extract an image patch in image I given the center and size of the ROI
VIDEO_WIDTH = size(I,2);
VIDEO_HEIGHT = size(I,1);
y = c(2)-h/2;
x = c(1)-w/2;
r2 = round(min(VIDEO_HEIGHT, y+h+1));
c2 = round(min(VIDEO_WIDTH, x+w+1));
r = round(max(y, 1));
c = round(max(x, 1));
imPatch = I(r:r2, c:c2);
end
- compute_weights_NG.m
这里是根据当前模型和目标模型来计算权值wi,在meanshift的推导公式中我们可以看到这个变量。
function weights = compute_weights_NG(imPatch, TargetModel, ColorModel, Nbins)
w = zeros(size(imPatch));
b = floor(256/Nbins);
matrix_bin = floor(imPatch/b) + 1;
for u=1:Nbins
%this if to avoid empty element in bins that can lead into division by zero
if (sum(sum(matrix_bin==u))~=0)
w = w + (matrix_bin==u) * sqrt(TargetModel(u)/ColorModel(u));
end
end
weights = w;
- compute_meanshift_vector.m
这里是计算meanshift向量,质心,做一下归一化处理。
function z = compute_meanshift_vector(imPatch, prev_center, weights)
[h,w] = size(imPatch);
coordinate = [prev_center(1)-w/2 prev_center(2)-h/2];
[x,y] = meshgrid(coordinate(1):1:w+coordinate(1)-1, coordinate(2):1:h+coordinate(2)-1);
x_mass = sum(sum(x.*weights / sum(weights(:))));
y_mass = sum(sum(y.*weights / sum(weights(:))));
z = [x_mass, y_mass];
end
- compute_bhattacharyya_coefficient.m
这里是计算相似度那个系数。
function k = compute_bhattacharyya_coefficient(p,q)
k = sum(sqrt(p.*q));
end
- color_distribution.m
这里是计算颜色模型,采用的核函数是Epanechnikov。
bwdist是matlab中的一个函数,表示了零元素到非零元素的最短距离。
比如如果[D,L]=dwdist(a)
a = [ 0 0 0 0 1 0 0 0 0 ] a=\left[\begin{matrix}0&0&0\\0&1&0\\0&0&0\\\end{matrix}\right] a=⎣⎡000010000⎦⎤ ,那么 D = [ 1.414 1 1.414 1 0 1 1.414 1 1.414 ] . D=\left[\begin{matrix}1.414&1&1.414\\1&0&1\\1.414&1&1.414\\\end{matrix}\right]. D=⎣⎡1.41411.4141011.41411.414⎦⎤.
function cd = color_distribution(imPatch, Nbins)
b = floor(256/Nbins);
matrix_bin = floor(imPatch/b) + 1;
h=zeros(Nbins,1);
% since there is matlab function called bwdist,
% i want to make matrix 0 with 1 in the center,
% so i can calculate the distance of each pixel to the center with bwdist()
% then i should normalized the distance
center_imagePatch = round(size(imPatch)/2);
imagePatch_new = zeros(size(imPatch));
imagePatch_new(center_imagePatch(1), center_imagePatch(2)) = 1;
%以上矩阵中心点为1,其他为0
d_Center = bwdist(imagePatch_new);%%计算矩阵各元素离中心元素的距离
dN_Center = (d_Center - min(d_Center(:)))/(max(d_Center(:)) - min(d_Center(:)));%%归一化
Epanechnikov_profile=(2/pi)*(1-dN_Center.^2);
for u=1:Nbins
whatever = ((matrix_bin - u)==0).*Epanechnikov_profile; %multiplication for each element
h(u,1) = sum(whatever(:));
end
cd = h/sum(h);
end
Kalman滤波器
有时候很佩服这些搞基础理论研究的前辈们,是他们的努力推动着科学的发展。有些理论可能这一辈子也看不到它的应用价值,再过了几十年后才会逐渐应用上,但幸运的是卡尔曼的理论在火箭发射上应用了,当年的计算机存储量和计算能力有限,换了这个算法后节省了空间提高了速度,具有跨时代的意义。
卡尔曼滤波器由预测部分和观测两部分组成。
预测部分是根据上一时刻的状态预测当前的状态,而观测部分是通过预测的状态计算出观测值。
形象一点理解,比如有一辆小车,匀速前进,那么你知道了上一时刻的速度,位置就可以预测出以后的状态,而实际观测的值呢,和你预测的值又有一些偏差,因此需要去修正。
通过了一系列的更新后,反馈,有点像经典控制理论中的闭环反馈一样,通过结果来不断的修正初值再得到更好一点的结果。
- 那么我们如何去建立数学模型来表示这个过程呢?
如果我们把目标的跟踪看成一个个点的移动,就可以抽象成一个数学模型,在某个位置上的一个点,向其他方向移动。



X呢,表示它的位置和速度的状态,而Z表示实际的观测值,也就是用实际的值来修正这个模型。
如果我们取一个很小的t,就可以近似的认为物体的运动是一个匀速的过程。
在更新的过程中,噪声是一个很关键的东西,用一个随机的东西加进来会让它的效果更好,让它有更好的适应能力,像SVM里的分类那种软的分类一样。噪声则根据矩阵的维度用随机数定义。


可以参考上述的特殊情况思考一下,让K为0呢?K为1呢?

卡尔曼增益的更新我觉得是一个很精彩的部分,它是预测和观测更新的桥梁,下面展示一个关系图,可以直观的看出来他们的过程。
总之,一共有五个方程,很关键。


可以很清楚的看出他们的更新步骤,首先进行初始化,定义一下然后进行不断的用观测值来修正。即用Z来修正这个关系。
最近看书的时候初始化似乎也有些讲究,状态的初始值可以设成0,方差的初始值书上讲设成10的-6次方,但试了试好像没有说明影响。以后有机会的话研究研究这个。
而应用到Mean Shift只需要把Mean Shift的结果给Z就可以得到更好的跟踪结果了。
KALMAN代码
只需要将主函数进行修改即可:
N=100; %仿真时间,时间序列总数
%噪声
Q=eye(4);%过程噪声方差
R=eye(2); %观测噪声方差
W=sqrt(Q)*randn(4,N);
V=sqrt(R)*randn(2,N);%测量噪声V(k)
%系数矩阵
A=[1 0 0.1 0;0 1 0 0.1;0 0 1 0;0 0 0 1;];%状态转移矩阵
B=0;%控制量
U=0;
H=[1 0 0 0;0 1 0 0];%观测矩阵
%初始化
X=zeros(4,N);%位置,x速度,y速度
X_pre=zeros(4,N);
X(:,1)=[ROI_Center(1),ROI_Center(2),0,0]';%初始位移和速度
P0=0;%初始误差
Z=zeros(2,N);
Z(:,1)=H*X(:,1);%初始观测值
Xkf=zeros(4,N);%卡尔曼估计状态初始化
Xkf(:,1)=X(:,1);
I=eye(4); %四维
for n = 2:NumImages
%读取下一帧图片
I = ImSeq(:,:,n);
%物体下落,受状态方程的驱动
k=2;
X(:,k)=A*X(:,k-1)+B*U+W(k);
Z(:,k)=H*X(:,k)+V(k);
%卡尔曼滤波
X_pre(:,k)=A*Xkf(:,k-1)+B*U;%状态预测
X_pre_center= X_pre(1:2,k)';
while(1)
% STEP 1
% 计算上一帧目标中心位置的PDF,即候选模型
imPatch = extract_image_patch_center_size(I, X_pre_center, ROI_Width, ROI_Height);
ColorModel = color_distribution(imPatch, Nbins);
% 计算目标模型和候选模型之间的相似程度-bhattacharyya距离
rho = compute_bhattacharyya_coefficient(TargetModel, ColorModel);
% STEP 2, 3
% 计算候选模型区域每个像素点 的权重
weights = compute_weights_NG(imPatch, TargetModel, ColorModel, Nbins);
% 计算mean-shift vector得到新的候选中心位置
z = compute_meanshift_vector(imPatch, X_pre_center, weights);
new_center = z;
% STEP 4, 5计算新的候选模型和相似度
imPatch2 = extract_image_patch_center_size(I, new_center, ROI_Width, ROI_Height);
ColorModel2 = color_distribution(imPatch2, Nbins);
% 相似度
rho2 = compute_bhattacharyya_coefficient(TargetModel, ColorModel2);
while(rho2<rho)%当移动后的候选位置相似度小于移动前的时候 进行以下迭代搜索
new_center = (X_pre_center+new_center)/2;
imPatch2 = extract_image_patch_center_size(I, new_center, ROI_Width, ROI_Height);
ColorModel2 = color_distribution(imPatch2, Nbins);
rho2 = compute_bhattacharyya_coefficient(TargetModel, ColorModel2);% 相似度
end
% STEP 6
if norm(new_center-X_pre_center,1) < 0.001
break
end
X_pre_center= new_center;
end
X_pre(:,k)=[new_center(1),new_center(2),0,0]';
Z(1,k)=new_center(1);%把meanshift处理的值给zk
Z(2,k)=new_center(2);
P_pre=A*P0*A'+Q;%协方差预测
Kg=P_pre*H'*inv(H*P_pre*H'+R);%计算卡尔曼增益
Xkf(:,k)=X_pre(:,k)+Kg*(Z(:,k)-H*X_pre(:,k));%状态更新
P0=(eye(4)-Kg*H)*P_pre;%方差更新
disp(new_center);
subplot(1,1,1); imshow(I, []);
hold on;
plot(Xkf(1,k),Xkf(2,k) , '+', 'Color', 'r', 'MarkerSize',10);
rectangle('Position', [Xkf(1,k)-ROI_Width/2,Xkf(2,k)-ROI_Height/2,ROI_Width,ROI_Height], 'EdgeColor','r')
drawnow;
while(k<100)
k=k+1;
end
end
遮挡问题
这里先写一点,挖个坑,看了一些论文大概是讲什么意思呢,如果发生了遮挡现象,被跟踪目标的相似度会有显著的差异,那么取定义这个相似度函数,如果小于了2/3的相似度,说明发生了遮挡现象,在遮挡的时候还按照先前的建模方式,认为它在遮挡的一瞬间的方向继续匀速运动来建模。然后同样出来的时候也这样建模。
CAMshift
当时看的时候也不懂,看到英文缩写一定要学习一下它的全称。
即continuously adaptive mean shift,也就是说它是mean shift算法的一个改进过程,通过不断的调整能自适应的调整搜索框的大小。
meanshift算法它本身的局限性上面提到了一句句,搜索窗口它是不变的!这样随着人物的走进,它并不能因为人物变大而去改变搜索窗口最后导致跟踪的效果很差。
CAM shift的特点总结一下就是
- 采用HSV分量中的H色调分量,对光线的影响较弱(相比RGB)
- 是连续的meanshift,搜索窗口会改变
那搜索窗口是怎么变的呢?
和mean shift一样,我们要寻找它的质心,计算窗口的概率密度,如果这个比设定小,说明有地方多余了,还需要缩小搜索窗口,如果大了呢,说明这个搜索窗口装不下,那么得扩大搜索窗口。



通过不断的更新搜索窗口来实现目标的跟踪。
CAMshift主要的参数就有三个
1.每次扩大搜索窗口的像素值
2.认为距离差多少了就继续运算的临界值
3.迭代次数的上限值
有个不算太重要的就是搜索窗口的比例,默认有的1.5有的2什么,具体情况具体分析我觉得。
github链接,记得点个赞
[https://github.com/SunHaoOne/CAMshift-matlab
不足和以后的方向
可能有些地方写的不好甚至有问题,希望大家指出来交流学习。
以后可以试着学习一下方向
- 遮挡问题
- 搜索框的角度变化
- 背景的滤波预处理
- 机器学习方向的目标跟踪
看近年的大多数是机器学习的,那么准备学习推导一下SVM的理论,让自己有点认识,如果有可能的话可以和meanshift结合一下改进。
本文深入探讨了目标跟踪领域的三大核心算法:MeanShift、Kalman滤波器和CAMShift。通过结合理论与代码实践,详细解析了每种算法的工作原理、优缺点及应用场景,特别强调了在目标跟踪过程中遮挡问题的处理策略。
&spm=1001.2101.3001.5002&articleId=105841154&d=1&t=3&u=03ebe78dc00a4177b06db6c4d42751d3)
94

被折叠的 条评论
为什么被折叠?



