基于meanshift的目标跟踪详细解读代码(卡尔曼滤波及CAMshift)

本文深入探讨了目标跟踪领域的三大核心算法:MeanShift、Kalman滤波器和CAMShift。通过结合理论与代码实践,详细解析了每种算法的工作原理、优缺点及应用场景,特别强调了在目标跟踪过程中遮挡问题的处理策略。

近期学习了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

目标跟踪的分类

  1. 生成式模型(generative)

在当前帧对目标区域建模,下一帧寻找与模型最相似的区域为预测位置,比较著名的有卡尔曼滤波,粒子滤波,mean-shift。
但这一类方法没有考虑目标的背景信息,图像信息没有得到较好的应用。

  1. 判别式模型(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结合一下改进。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值