运动目标分割
- 这次图像处理的老师布置了运动目标分割的实验。具体要求如下:
- 采用差分法,背景差法实现运动目标提取,基本掌握运动目标提取的基本原理和方法。
- 了解不同帧率、不同运动速度条件下对检测结果的影响。
实验步骤
帧差法
读取训练视频文件
mov = aviread('raw.avi');
frameNumbers = size(mov,2);
x = mov(1,1).cdata; %获取一帧图片
fr_size = size(x); %获取帧的大小
width = fr_size(2);
height = fr_size(1);
c = zeros(height, width);
目标检测
for k=1:frameNumbers-1
x = frame2im(mov(1,k));
y = frame2im(mov(1,k+1)); %获取下一帧
m = rgb2gray(x);
n = rgb2gray(y);
q=im2double(n);
w=im2double(m);
c = q-w;
t=20; %%阈值,此值可以调节
t=t/255;%%转化为double型数据
id = c > t;
cc =zeros(height, width);
cc(id) = 1;
figure(1),subplot(2,2,1),imshow(m),title('当前帧');
subplot(2,2,2),imshow(n),title('下一帧');
subplot(2,2,3),imshow(c),title('差值帧');
subplot(2,2,4),imshow(cc),title('检测结果');
disp(k);
end
-
中间结果
-
这里我们使用帧差法获得了运动目标的二值图像。不过,由上图可以看出,噪点过多,不利于提取运动目标信息。接下来,我们对检测结果图像进行处理,提取运动目标。
中值滤波
cc = medfilt2(cc, [5 5]);
-
中间结果
-
这段代码添加在获得检测图像后,对结果图像进行中值滤波。针对上一步差值图像按阈值处理后的检测结果图像,我们使用中值滤波去除噪点。由上图可以看出,处理效果不错。不过,运动目标变得残缺。为了使得运动目标完整,我们将使用形态学操作处理滤波后的图像。
形态学操作
se=strel('disk',30);
cc=imclose(cc,se);
-
中间结果
-
这段代码添加在中值滤波处理后,对结果图像进行形态学操作。通过该步骤,我们获得了完整的运动目标区域。最后,使用连通域标记的方法,对运动目标进行检测标识。
连通域标记
subplot(1,2,1),imshow(cc),title('二值图像');
position = regionprops(logical(cc));
subplot(1,2,2),imshow(y),title('检测标记后');
hold on;
for i=1:size(position,1)
rectangle('Position', position(i).BoundingBox, 'edgecolor','r', 'LineWidth', 2);
if position(i).BoundingBox(3) > position(i).BoundingBox(4)
text(position(i).BoundingBox(1), position(i).BoundingBox(2), 'car');
else
text(position(i).BoundingBox(1), position(i).BoundingBox(2), 'person');
end
end
-
中间结果
-
通过连通域标记的方式,我们对运动物体进行了标记,如上图所示。同时,为了对车与行人进行区分,我使用了几何特征进行分类。当连通域的长宽比大于1时判定为车,而相反则判定为行人。至此,我们完成了对运动目标的检测标记,同时对运动物体进行了简单分类。
检测结果
背景差法(之时间平均法)
训练前N帧
% 时间平均法
clear all;
IMG_FILE = 'RawImages/';
N = 40;% N frames to train the Gaussian model
h = fspecial('gaussian');
imagedata = filter2(h,rgb2gray(imread(strcat(IMG_FILE,'seq00.avi0001.bmp'))));
mu = imagedata;
[m,n] = size(mu);
pro = zeros(m,n);
for i=1:N
filename = strcat(IMG_FILE, sprintf('seq00.avi%04d.bmp',i));
tmp =filter2(h,rgb2gray(imread(filename)));
mu = mu+tmp;%(tmp+(i-1)*sav_mu)./i;%
end;
mu=mu./N;
figure(1),imshow(uint8(mu));
- 中间结果
目标检测
% test the new frame
for num = N+1:500
filename = strcat(IMG_FILE, sprintf('seq00.avi%04d.bmp',num));
ori_img = imread(filename);
imagedata = filter2(h,rgb2gray(ori_img));
t=10; % 阈值,可调节
pro = abs(imagedata-mu)> t;
imshow(pro),title(sprintf('第 %d 帧', num));
%%update mean
mu = (mu*(num-1) +imagedata)/num;
end;
-
中间结果
-
我们基于前40帧重构的背景进行运动物体检测,而检测的同时更新背景矩阵。这里我们得到了运动物体的二值图像。不过,同样存在噪点影响提取运动物体信息。按照上面的方法,进行中值滤波。
中值滤波
pro = medfilt2(pro, [5 5]);
-
中间结果
-
经过中值滤波,大部分噪点已经去除,不过还是存在面积较大的噪点。为了去除噪点,同时使运动物体的形状更加完整,接下来进行形态学操作。
形态学操作
pro = imerode(pro,strel('disk',7));
pro = imdilate(pro, strel('disk',25));
pro = imerode(pro, strel('disk',10));
-
中间结果
-
经过一系列形态学操作,我们成功地将所有的噪点去除,同时保留了运动物体的全部信息。最后,我们还是用连通域标记的方法,对运动物体进行标记。
连通域标记
subplot(1,2,1),imshow(pro),title(sprintf('第 %d 帧', num));
%连通域标记
position = regionprops(logical(pro));
subplot(1,2,2),imshow(ori_img),title('检测标记后');
hold on;
for i=1:size(position,1)
rectangle('Position', position(i).BoundingBox, 'edgecolor','w', 'LineWidth', 2);
if position(i).BoundingBox(3) > position(i).BoundingBox(4)
text(position(i).BoundingBox(1), position(i).BoundingBox(2), 'car','color','r');
else
text(position(i).BoundingBox(1), position(i).BoundingBox(2), 'person','color','r');
end
end
-
中间结果
-
通过连通域标记的方式,我们对运动物体进行了标记,如上图所示。同时,为了对车与行人进行区分,我使用了几何特征进行分类。当连通域的长宽比大于1时判定为车,而相反则判定为行人。至此,我们完成了对运动目标的检测标记,同时对运动物体进行了简单分类。
总结
- 这次实验中,使用了 帧差法 时间平均法 单高斯法 混合高斯法 等处理方法。上面只给出了其中两种的实验流程及代码。
- 其实在图像处理部分,尤其是对二值图像进行滤波、形态学操作的基本步骤都相同,只是在一些参数上需要调整。比如:形态学操作中结构元素的大小(简直玄学了。。。。)
- 最后,基于人与车的长宽特征进行了简单的分类。不过,效果一般,毕竟这个特征并不能完全区分人与车。还是要靠 SSD 等等运动目标检测的深度网络算法。