运动物体跟踪实际上就是对运动物体位置的测量和估计,和称小兔兔体重一样,我们也有两个渠道可以知道运动物体的位置,一个是我们观察到的,目标A在的某一帧图像的某个坐标点,另一个是我们根据前面几帧里目标的运动情况估计出来的,这个估计是假定目标运动是光滑的(当然也可以有其他模型),在这个根据以前运动做出的估计和我们测出来的目标点位置之间做个加权平均,就是现在的估计值,对下一帧做同样处理,加权平均的权值就是Kalman增益,根据Kalman提供的算法可由以往的误差大小和分布推出,这就是全部的用Kalman滤波做目标跟踪的概念。
Kalman滤波理论主要应用在现实世界中个,并不是理想环境。主要是来跟踪的某一个变量的值,跟踪的依据是首先根据系统的运动方程来对该值做预测,比如说我们知道一个物体的运动速度,那么下面时刻它的位置按照道理是可以预测出来的,不过该预测肯定有误差,只能作为跟踪的依据。另一个依据是可以用测量手段来测量那个变量的值,当然该测量也是有误差的,也只能作为依据,不过这2个依据的权重比例不同。最后kalman滤波就是利用这两个依据进行一些列迭代进行目标跟踪的。
在这个理论框架中,有2个公式一定要懂,即:
clear,clc
% 计算背景图像
Imzero = zeros(240,320,3);
for i = 1:5
Im{i} = double(imread(['DATA/',int2str(i),'.jpg']));
Imzero = Im{i}+Imzero;
end
Imback = Imzero/5;
[MR,MC,Dim] = size(Imback);
% Kalman滤波器初始化
R=[[0.2845,0.0045]',[0.0045,0.0455]'];
H=[[1,0]',[0,1]',[0,0]',[0,0]'];
Q=0.01*eye(4);
P = 100*eye(4);
dt=1;
A=[[1,0,0,0]',[0,1,0,0]',[dt,0,1,0]',[0,dt,0,1]'];
g = 6;
Bu = [0,0,0,g]';
kfinit=0;
x=zeros(100,4);
% 循环遍历所有图像
for i = 1 : 60
% 导入图像
Im = (imread(['DATA/',int2str(i), '.jpg']));
imshow(Im)
imshow(Im)
Imwork = double(Im);
%提取球的质心坐标及半径
[cc(i),cr(i),radius,flag] = extractball(Imwork,Imback,i);
if flag==0
continue
end
%用绿色标出球实际运动的位置
hold on
for c = -1*radius: radius/20 : 1*radius
r = sqrt(radius^2-c^2);
plot(cc(i)+c,cr(i)+r,'g.')
plot(cc(i)+c,cr(i)-r,'g.')
end
% Kalman器更新
if kfinit==0
xp = [MC/2,MR/2,0,0]'
else
xp=A*x(i-1,:)' + Bu
end
kfinit=1;
PP = A*P*A' + Q
K = PP*H'*inv(H*PP*H'+R)
x(i,:) = (xp + K*([cc(i),cr(i)]' - H*xp))';
x(i,:)
[cc(i),cr(i)]
P = (eye(4)-K*H)*PP
%用红色画出球实际的运动位置
hold on
for c = -1*radius: radius/20 : 1*radius
r = sqrt(radius^2-c^2);
plot(x(i,1)+c,x(i,2)+r,'r.')
plot(x(i,1)+c,x(i,2)-r,'r.')
end
pause(0.3)
end
function [cc,cr,radius,flag]=extractball(Imwork,Imback,index)
% 功能:提取图像中最大斑点的质心坐标及半径
% 输入:Imwork-输入的当前帧的图像;Imback-输入的背景图像;index-帧序列图像序号
% 输出:cc-质心行坐标;cr-质心列坐标;radius-斑点区域半径;flag-标志
cc = 0;
cr = 0;
radius = 0;
flag = 0;
[MR,MC,Dim] = size(Imback);
% 将输入图像与背景图像相减,获得差异最大的区域
fore = zeros(MR,MC);
fore = (abs(Imwork(:,:,1)-Imback(:,:,1)) > 10) ...
| (abs(Imwork(:,:,2) - Imback(:,:,2)) > 10) ...
| (abs(Imwork(:,:,3) - Imback(:,:,3)) > 10);
foremm = bwmorph(fore,'erode',2); % 运用数学形态学去除微小的噪声
% 选择大的斑点对其周围进行标记
labeled = bwlabel(foremm,4);
stats = regionprops(labeled,['basic']);
[N,W] = size(stats);
if N < 1
return
end
% 如果大的斑点的数量大于1,则用冒泡法进行排序
id = zeros(N);
for i = 1 : N
id(i) = i;
end
for i = 1 : N-1
for j = i+1 : N
if stats(i).Area < stats(j).Area
tmp = stats(i);
stats(i) = stats(j);
stats(j) = tmp;
tmp = id(i);
id(i) = id(j);
id(j) = tmp;
end
end
end