1.利用matlab中的VideoReader函数读取视频流。
2.帧差法:获得视频帧数,用for循环对图像每相邻两帧之间做差,得到差分后的每一帧视频图像(以二帧差法为例,此处也可采用三帧法、ViBe方法、高斯混合建模法得到动态目标检测的二值图像)。
3.对差分后的图像进行二值化处理,然后填充图形区域和空洞,并进行中值滤波实现图形的去噪。
4.利用形态学知识,对图像进行腐蚀和膨胀,实现进一步去噪和细化图形中的目标。
5.对图形的每一行进行行扫描,找出每一行白色区域的临界端点,并将中间的区域填充为白色,实现目标的区域填充。
6.找到差分图像的上下左右边界,用矩形框将目标在视频中框起来。
7.重复以上操作,即可实现视频流中目标的检测。
利用matlab中的VideoReader函数读取视频流。
利用帧差法获得视频帧数,用for循环对图像每相邻两帧之间做差,得到差分后的每一帧视频图像。
对差分后的图像进行二值化处理并中值滤波去噪处理后,将其叠加在原图像上
对差分后的图像填充图形区域和空洞,并进行中值滤波实现图形的去噪,利用形态学知识,对图像进行腐蚀和膨胀,实现进一步去噪和细化图形中的目标
对图形的每一行进行行扫描,找出每一行白色区域的临界端点,并将中间的区域填充为白色,实现目标的区域填充
算法实现:第三帧与第二帧做差,第二帧与第一帧做差,对这两个差分图像进行交集运算
与二帧差法的区别:相比相邻两帧差法,三帧差法比较适合对运动速度较快物体的检测,但是仍然会有空洞出现,并且物体移动速度较慢时容易丢失轮廓。
% --- Executes on button press in pushbutton6.
function pushbutton6_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton6 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
videoName = get(handles.edit1, 'String');
videoSource = vision.VideoFileReader(videoName,...
'ImageColorSpace', 'RGB', 'VideoOutputDataType', 'uint8');
videoInfo = info(videoSource);
videoRate = videoInfo.VideoFrameRate;
waitTime = 1.0/videoRate;
frame_first = rgb2gray(step(videoSource));
frame = step(videoSource);
global exit_flag;
global pause_flag;
exit_flag = false;
pause_flag = false;
while ~isDone(videoSource) && ~exit_flag
if pause_flag
uiwait(handles.figure1);
end
frame_second = rgb2gray(frame);
frame = step(videoSource);%读取图像
frame_third = rgb2gray(frame);
frame_diff1 = abs(frame_second - frame_first);%第二帧和第一帧做差
frame_diff2 = abs(frame_third - frame_second);%第三帧和第二帧做差
c3= imbinarize(max(frame_diff1,frame_diff2));%对这两个差分图像进行交集运算
c3 = imopen(c3, strel('rectangle', [3, 3]));
c3= imfill(c3, 'hole');
se = strel('disk', 4);
c3 = imerode(c3, se);
se1 = strel('square', 12);
c3= imdilate(c3, se1);
c3=medfilt2(c3);%中值滤波
[m,n] = size(c3);
%%
ViBe算法,其原理为通过提取像素点(x, y)周围的像素值及以前的像素值建立像素点的样本集,然后再将另一帧(x,y)处的像素值与样本集中的像素值进行比较,如果其与样本集中的像素值的距离大于某阈值的话,则认为该像素点为前景像素点,否则为背景像素点。
% --- Executes on button press in pushbutton9.
function pushbutton9_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton9 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
videoName = get(handles.edit1, 'String');
videoSource = vision.VideoFileReader(videoName,...
'ImageColorSpace', 'RGB', 'VideoOutputDataType', 'uint8');
videoInfo = info(videoSource);
% 参数设置
sample_num = 10; % 样本库
match_thres = 20; % 匹配阈值
match_num = 2; % 最小匹配数
update_factor = 1; % 一开始50帧内采用该更新因
next_update_factor = 5; % 50帧以后的更新因子
cols = videoInfo.VideoSize(1); % 图像的宽度
rows = videoInfo.VideoSize(2); % 图像的高度
fore_thres = 20; % 前景阈值
frame_count = 0; % 处理帧数
neighbor = [1, 0, -1, -1, 1, 0, 0, -1, 1]; % 邻域选择
% 外部控制标记
global exit_flag;
global pause_flag;
exit_flag = false;
pause_flag = false;
% 判断是否为第一帧
first_flag = true;
while ~isDone(videoSource) && ~exit_flag
if pause_flag
uiwait(handles.figure1);
end
frame = step(videoSource);
frame_gray = double(rgb2gray(frame));
if first_flag
first_flag = false;
%% 开始初始化
samples = cell(1, sample_num);
% 前两个样本设置初始像素
samples{1} = frame_gray;
samples{2} = frame_gray;
% 剩下的样本初始化
for i = 3:sample_num
samples{i} = frame_gray + double(floor(rand(rows, cols) * 20) - 10);
end
fore_count = uint8(zeros(rows, cols));
frame_count = frame_count + 1
% 初始化结束
continue
end
%% 前景分割
fgMask = uint8(ones(rows, cols) * match_num);
for i = 1:sample_num
distance = uint8(abs(samples{i} - frame_gray) <= match_thres);
fgMask = fgMask - distance;
end
fgMask = logical(fgMask * 255);
% 更新前景计数
for r = 1 : rows
for c = 1:cols
if fgMask(r, c) == 1
fore_count(r, c) = fore_count(r, c) + 1;
if fore_count(r, c) >= fore_thres
fore_count(r,c) = 0;
fgMask(r, c) = 0;
end
else
fore_count(r, c) = 0;
end
end
end
updateMask = fgMask;
updateMask = imfill(updateMask, 'hole');
%% 更新样本库
% 一边更新前景计数,一边更新样本库
for r = 2:rows-1
for c = 2:cols-1
% 为背景时,更新背景样本库
if updateMask(r, c) == 0
fore_count(r, c) = 0;
% 有一定概率更新自身
if update_factor == 1 || floor(rand() * update_factor) == 0
samples{floor(rand() * sample_num) + 1}(r, c) = frame_gray(r, c);
end
% 也有一定概率更新周围像素样本库
if update_factor == 1 || floor(rand() * update_factor) == 0
samples{floor(rand() * sample_num) + 1}(r + neighbor(floor(rand() * 9) + 1), ...
c + neighbor(floor(rand() * 9) + 1)) = frame_gray(r, c);
end
end
end
end
frame_count = frame_count + 1
if frame_count >= 50
update_factor = next_update_factor;
end
高斯混合模型,其原理为将图像中每一个像素点的颜色值看成是一个随机过程,并假设该点的像素值出现的概率服从高斯分布。每一个像素位置建立多个高斯模型,各个模型中保存该处像素的均值和方差。若新的图片中相应位置的像素值与对应模型中像素的均值的距离小于标准差的λ倍,则该点为背景,否则为前景。
% --- Executes on button press in pushbutton8.
function pushbutton8_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton8 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
videoName = get(handles.edit1, 'String');
videoSource = vision.VideoFileReader(videoName,...
'ImageColorSpace', 'RGB', 'VideoOutputDataType', 'uint8');
videoInfo = info(videoSource);
videoRate = videoInfo.VideoFrameRate;
waitTime = 1.0/videoRate;
global exit_flag;
global pause_flag;
exit_flag = false;
pause_flag = false;
% 参数设置
first_flag = true;
cols = videoInfo.VideoSize(1);
rows = videoInfo.VideoSize(2);
fgMask = zeros(rows, cols); % 前景矩阵
K = 3; % K值为3
D = 2.5; % 偏差阈值
alpha = 0.01; % 学习速率
Tframe = 50; % 帧数阈值
T = 0.8; % 前景阈值
sd_init = 15; % 初始标准差
w_init = 0.1; % 初始权值
ratio = w_init/sd_init; % 自适应选择高斯分布
W = zeros(rows, cols, K); % 权值矩阵
mean = zeros(rows, cols, K); % 均值矩阵
sd = zeros(rows, cols, K); % 标准差矩阵
g_num = ones(rows, cols); % 记录每个像素的高斯分布数
u_dist = zeros(rows, cols, K); % 新像素值与高斯分布均值的绝对值距离
frame_count = 0; % 处理的帧数
gframe = 10; % 每隔几帧,删除无用高斯分布
disk1 = strel('disk', 1); % 形态学结构元素
disk2 = strel('disk', 4); % 形态学结构元素
while ~isDone(videoSource) && ~exit_flag
if pause_flag
uiwait(handles.figure1);
end
frame = step(videoSource);
frame_now = double(rgb2gray(frame));
if first_flag
first_flag = false;
% 初始化混合高斯模型
w_init_m = ones(rows, cols) * 1/K;
sd_init_m = ones(rows, cols) * sd_init;
for i = 1:K
% 均值设为第一帧对应位置的像素
mean(:, :, i) = frame_now;
W(:, :, i) = w_init_m;
sd(:, :, i) = sd_init_m;
end
frame_count = frame_count + 1
g_num = g_num .* 3;
continue;
end
if frame_count <= Tframe
alpha = 1/(2 * frame_count);
end
% 前景检测与模型更新
for i=1:K
u_dist(:, :, i) = abs(frame_now - mean(:, :, i));
end
% 自适应选择高斯分布标志
adapt_flag = false;
if mod(frame_count, gframe) == 0
adapt_flag = true;
end
% 更新每个高斯模型的参数
for i=1:rows
for j=1:cols
match_ground = false;
match = 0;
gnum = g_num(i, j);
for k = 1:gnum
% 符合,3σ原则,则像素值匹配该高斯模型
if abs(u_dist(i, j, k)) <= D * sd(i, j, k)
match = 1;
if ~match_ground && W(i, j, k) >= 0.2
match_ground = true;
end
% 更新权值
W(i, j, k) = (1 - alpha) * W(i, j, k) + alpha;
p = alpha * normpdf(frame_now(i, j), mean(i, j, k), sd(i, j, k));
mean(i, j, k) = (1 - p) * mean(i, j, k) + p * frame_now(i, j);
sd(i, j, k) = sqrt((1 - p) * sd(i, j, k)^2 + p * ...
(mean(i, j, k) - frame_now(i, j))^2);
else
% 不匹配
W(i, j, k) = (1 - alpha) * W(i, j, k);
end
end
% 如果全部不匹配,替换最小权值的高斯分布或者添加新的高斯分布
if match == 0
if gnum == K
% 替换权值最小的高斯分布
[~, min_w_index] = min(W(i, j, :));
mean(i, j, min_w_index) = double(frame_now(i, j));
sd(i, j, min_w_index) = sd_init;
else
% 添加新的高斯分布
gnum = gnum + 1;
W(i, j, gnum) = w_init;
mean(i, j, gnum) = double(frame_now(i, j));
sd(i, j, gnum) = sd_init;
g_num(i, j) = gnum;
end
end
% 权值归一化
w_sum = sum(W(i, j, :));
W(i, j, :) = W(i, j, :) ./ w_sum;
% 进行自适应选择高斯分布个数
if adapt_flag
rank = W(i, j, :) ./ sd(i, j, :);
[~, rank_index] = sort(rank, 'descend');
W_temp = W(i, j, :);
mean_temp = mean(i, j, :);
sd_temp = sd(i, j, :);
udist_temp = u_dist(i, j, :);
% 根据优先级替换相应的权值,均值和标准差
for m = 1:gnum
index = rank_index(m);
W(i, j, m) = W_temp(index);
mean(i, j, m) = mean_temp(index);
sd(i, j, m) = sd_temp(index);
u_dist(i, j, m) = udist_temp(index);
end
% 删除无用高斯分布
for m = gnum:-1:1
if W(i, j, m) < w_init && rank(rank_index(m)) < ratio
W(i, j, m) = 0;
g_num(i, j) = g_num(i, j) - 1;
else
break;
end
end
gnum = g_num(i, j);
% 由于部分高斯分布可能被删除,所以需要再进行权值归一化
w_sum = sum(W(i, j, :));
W(i, j, :) = W(i, j, :) ./ w_sum;
end
% 已经匹配,则不需要再进行优先级排序判定
if match_ground
fgMask(i, j) = 0;
continue;
end
% 优先级排序
rank = W(i, j, :) ./ sd(i, j, :);
[~, rank_index] = sort(rank, 'descend');
fgMask(i, j) = 0;
k = 1;
temp_T = 0;
while (match == 0) && (temp_T < T)
index = rank_index(k);
if abs(u_dist(i, j, index) <= D * sd(i, j, index))
fgMask(i, j) = 0;
break;
else
temp_T = temp_T + W(i, j, index);
fgMask(i, j) = 255;
end
k = k + 1;
end
end
end
% 使用混合高斯背景建模
fgMask = logical(fgMask);
fgMask = imdilate(imerode(fgMask, disk1), disk2);
axes(handles.axes1);
imshow(frame);
axes(handles.axes2);
imshow(fgMask);
drawnow;
frame_count = frame_count + 1
end
release(videoSource);