运动前景分割在视频监控中有很大的应用,可以应用在超市、机场、广场等人流密集的场景,对于可疑对象侦查,可以物体发现有重大意义。最简单的运动前景分割的算法为帧对帧差分,通过两幅图像相减,固定不变的背景就剪掉了,只剩下运动前景,这种算法的优点是算法复杂度低,缺点是,对于运动速度较慢的目标很难检测出来。由于在运动前景检测这一应用中,背景大多是固定不变的,因此提出了很多背景建模算法,通过某种数学模型描述每一帧图像中某一像素点在时间序列上满足的统计规律,当出现不符合这个统计规律的像素点认为是运动前景,常有的背景建模算法有单高斯模型、混合高斯模型,单高斯模型即认为每一个像素值在时间序列上满足高斯分布,这是符合实际情况的,单高斯模型可能不能完全描述这一个像素值的规律,比如背景中有摇曳的树枝等运动背景,此时可以考虑混合高斯模型。
为了完成行人检测任务,使用了基于单高斯模型的检测。算法流程如下图,首先读入原始视频,读取一帧图像,更新每个像素的高斯模型,判断本帧像素是否符合高斯模型,设置检测阈值将图像二值化,此时可以较好地检测出行人,同时还会检测出很多干扰区域,使用开运算这种滤波方法可以很好地去除干扰区域,使用填充、膨胀运算、闭运算可以补充行人的内部空白和不连续区域,接下来找到所有的连通区域,并按连通区域的面积排序,找出相对最大连通区域面积来说较大的区域,认为这些连通区域为行人,使用Sobel算子进行边缘检测。
高斯分布又叫正态分布,自然界的很多事物符合高斯分布。图像中背景基本固定,变化的只有行人,因此使用单高斯模型就可以较好的拟合像素值分布。高斯模型的概率密度函数为:,其中为当前的像素值,和分别为该坐标下像素的均值和标准差,理论上符合该模型的数据有99.7%的概率落在范围内,因此可以利用此规律将异常点检测出来。
%===============================================================
% Tracking.m:行人检测
% Environment:MATLAB R2017a
% 实现方法:采用的算法为单高斯模型,将图像转换为灰度图,建立像素级的
% 单高斯模型,判断每一帧的像素是否大概率符合模型,如果不符合,判断
% 为行人,利用单高斯模型检测出行人,同时也有很多干扰区域,使用开运
% 算、填充、闭运算等操作去除干扰区域,使用Sobel算子进行边缘检测。
%===============================================================
close all;
clear all;
clc;
vidObj = VideoReader('level_2.mp4');
vidHeight = vidObj.Height;
vidWidth = vidObj.Width;
M = zeros(vidHeight, vidWidth);
V = zeros(vidHeight, vidWidth);
%===================单高斯模型========================================
i = 0;
while hasFrame(vidObj)
Fig = readFrame(vidObj);
Fig = rgb2gray(Fig);
Fig = double(Fig);
M = (M * i + Fig) / (i + 1);
i = i + 1;
Ph{i} = Fig;
end
for j = 1 : i
V = V + (Ph{i} - M) .^ 2;
end
V = sqrt(V / (i));
vidObj = VideoReader('level_2.mp4');
s = struct('cdata', zeros(vidHeight, vidWidth, 'double'), 'colormap', []);
k = 1;
j = 10;
k = 50;
ii = 0;
writeObj = VideoWriter('P_data2.avi');
open(writeObj)
while hasFrame(vidObj)
ii = ii + 1;
Fig = readFrame(vidObj);
FigReal = Fig;
Fig = rgb2gray(Fig);
Fig = double(Fig);
%===================单高斯模型========================================
M = (M * (k - 1) + Fig) / k;
V = sqrt((V .^2 * (k - 2) + (Fig - M) .^ 2) / (k - 1));
ind_B = find(Fig > M - 3 * V & Fig < M + 3 * V);
ind_F = find(Fig < M - 2 * V | Fig > M + 2 * V);
Fig(ind_F) = 1;
Fig(find(Fig ~= 1)) = 0;
%====================================================================
%=================开运算、填充、闭运算=================================
se1 = strel('disk', 5, 6);
se2 = strel('disk', 9, 6);
ser = strel('rectangle', [7, 7]);
bw2 = Fig;
bw2 = imopen(bw2, se1);
bw2 = imfill(bw2, 'holes');
bw2 = imdilate(bw2, se1);
bw2 = imclose(bw2, se2);
%====================================================================
%================寻找连通区域=====================================
[B, L] = bwboundaries(bw2);
stats = regionprops(L, 'Area', 'Centroid');
Stat2Array = struct2array(stats);
Stat2Array = reshape(Stat2Array, [3, length(Stat2Array) / 3]);
tempArray = Stat2Array;
BigestArea = max(Stat2Array(1, :));
%===================================================================
%==============边缘检测==============================================
while ~ isempty(BigestArea)
tempBigestArea = max(tempArray(1, :));
if tempBigestArea(1) / BigestArea(1) < 0.5
break
end
tempAreaIndex = find(Stat2Array(1, :) == tempBigestArea(1));
tempArray(find(tempArray == tempBigestArea(1))) = 0;
if ~ isempty(tempAreaIndex)
boundary = B{tempAreaIndex(1)};
plot(boundary(:, 2), boundary(:, 1), 'w', 'LineWidth', 2, ...
'Color', 'red');
for kk = 1 : size(boundary, 1)
for kii = -1 : 1
for kjj = -1 : 1
if boundary(kk, 1) + kii < 1 | ...
boundary(kk, 1) + kii > size(FigReal, 1) |...
boundary(kk, 2) + kjj < 1 |...
boundary(kk, 2) + kjj > size(FigReal, 2)
continue
end
FigReal(boundary(kk, 1) + kii, ...
boundary(kk, 2) + kjj, 1) = 0;
FigReal(boundary(kk, 1) + kii, ...
boundary(kk, 2) + kjj, 2) = 255;
FigReal(boundary(kk, 1) + kii, ...
boundary(kk, 2) + kjj, 3) = 0;
end
end
end
else
break
end
end
%======================================================================
writeVideo(writeObj, FigReal(1: size(bw2, 1), 1: size(bw2, 2), :));
k = k + 1;
end
close(writeObj);