% 高斯背景建模,根据Seth Benton的代码修改得到。
clear all;
% 获取视频文件
read_obj = VideoReader('F:\pic\test16.mp4');
% pixel_depth = 8; % 转成灰度图像后每个像素点使用的位数
% pixel_range = 2 ^ pixel_depth - 1; % 灰度图像亮度值范围
height = read_obj.Height; % 图片的高度(像素数)
width = read_obj.Width; % 图片的宽度(像素数)
fr_num = read_obj.NumberOfFrames; % 视频帧数
tmp = read(read_obj, [1 fr_num-1]); % 读取n1-n2帧并转化为灰度图、双精度
fr_all = zeros(height, width, fr_num-1); % 存放n1-n2帧的灰度图
for i = 1 : fr_num-1 % 第一帧到第n2帧循环
fr_all(:, :, i) = rgb2gray(tmp(:, :, :, i)); %??????
end
fr_all = double(fr_all); % 转换成双精度,适合后面的运算
K = 3; % 高斯分布的个数
D = 2.5; % 与某个分布的均值距离在2.5个标准差之内即与此高斯分布匹配
alpha = 0.01; % 权重w的学习率
T = 0.75; % 前景、背景的门限
sd_init = 6; % 初始化标准差,一个比较大的值
dist = zeros(height, width, K); % 存放新来的一张图像的像素值与各个高斯均值的差
% 初始化各个高斯分布的权重、均值、标准差
w = zeros(height, width, K); % 第一个高斯分布的初始权重为1,其余分布的权重为0
w(:, :, 1) = 1;
w(:, :, 2:K) = 2^-8;
mean = zeros(height, width, K); % 第一个高斯分布的初始均值为第一帧的值,其余分布的均值为0
mean(:, :, 1) = fr_all(:, :, 1);
sd = sd_init * ones(height, width, K); % 各个高斯分布的初始标准差
matchcnt = ones(height, width, K); % 匹配的次数,初始值都设为1
fg_bg = zeros(height, width); % 前景、背景的二值图像,白色代表前景,黑色代表背景
bg = zeros(height, width); % 背景图像,是前面比例之和大于T的高斯的均值的加权和
%write_obj1 = VideoWriter('gm_hand.avi'); % 新建avi视频,存放二值图像序列
%write_obj2 = VideoWriter('background_traffic_2.avi'); % 新建avi视频,存放背景图像序列
%open(write_obj1);
%open(write_obj2);
%for n = n1+1 : n2
% 从第二帧开始处理
for n = 3 : fr_num-1
G =read(read_obj,n);
G =rgb2gray(G);
new_fr = fr_all(:, :, n) ; % 读取第n帧灰度图
%new_fr = double( rgb2gray( read(read_obj, n) ) ); % 读取第n帧,并转换为灰度图
dist = abs( repmat(new_fr, [1, 1, K]) - mean ) ; % 求出与各个高斯分布均值的差值
% 每个像素点都进行匹配、更新
for i = 1 : height
for j = 1 : width
match = 0; % 像素值与至少一个高斯匹配的标志
match_ind = 0; % match_ind为最匹配的高斯的序号
% 与K个高斯分别进行匹配判断,然后更新参数
for k = 1 : K
if( (dist(i, j, k) <= D * sd(i, j, k)) && (match == 0) ) % 当与多个高斯匹配时,选择fitness(匹配程度,w/sd)最大的。这里假定K个高斯已经按照fitness从大到小
% 排好序了,只有当上面的分布没匹配才判断与下面的分布是否匹配。
match = 1; % 若匹配,则标志置1,忽略后面其它可能匹配的高斯
match_ind = k; % 记录匹配的高斯的序号
p = alpha / w(i, j, k); % 均值、方差的学习率
mean(i, j, k) = (1 - p) * mean(i, j, k) + p * new_fr(i, j); % 先更新均值
sd(i, j, k) = sqrt((1 - p) * sd(i, j, k) ^ 2 + p * (new_fr(i, j) - mean(i, j, k)) ^ 2); % 再更新方差
w(i, j, k) = (1 - alpha) * w(i, j, k) + alpha; % 增加权重
if matchcnt(i, j, k) ~= 255 % 匹配次数达到255就不加了。在实时视频序列中,上限是必须的,否则可能溢出。
matchcnt(i, j, k) = matchcnt(i, j, k) + 1;
end
else
w(i, j, k) = (1 - alpha) * w(i, j, k); % 减小权重
end
end
if(match == 0) % 没有匹配的高斯,建立新的高斯取代fitness最低的(排序后排在最后面的那个)
matchcnt(i, j, K) = 1; % 匹配次数设为1,一个小值
w(i, j, K) = 1 / ( sum( matchcnt(i, j, :) ) - 1 ); % 权值为其它高斯分布匹配次数之和的倒数
mean(i, j, K) = new_fr(i, j); % 均值为当前像素值
sd(i, j, K) = sd_init; % 标准差为一个预设定的较大值
end
% 再归一化权重
w_sum = sum(w(i, j, :));
w(i, j, :) = w(i, j, :) / w_sum;
% 从大到小对几个高斯分布的fitness排序
fitness = w(i, j, :) ./ sd(i, j, :);
[sorted_fit, ind] = sort(fitness, 'descend');
% 根据权重(论文公式(9))求出前景-背景二值图像
% 这里我简化了的方法只适合于3个高斯的情况
fg_bg(i, j) = 255;
if(match == 1)
switch match_ind
case ind(1) % 与最上面的高斯匹配,肯定是归为背景点
fg_bg(i, j) = 0;
case ind(2) % 与中间的高斯匹配,如果最上面一个高斯的权值小于T,则这点归为背景点
if w(i, j, ind(1)) < T
fg_bg(i, j) = 0;
end
case ind(3) % 与最下面的高斯匹配,如果最下面的高斯权值大于1-T(或者前两个高斯权值和小于T),则这点归为背景点
if w(i, j, ind(3)) > 1 - T
% if w(i, j, ind(1)) + w(i, j, ind(2)) < T
fg_bg(i, j) = 0;
end
end
% else % 不执行,节省运行时间
% fg_bg(i, j) = 255;
end
% 根据fitness的排序结果调整参数的顺序
tmp = [mean(i, j, :); sd(i, j, :); w(i, j, :); matchcnt(i, j, :)]; % 为了排序时,几个参数同步调整,所以组合在一起
mean(i, j, :) = tmp(1, ind);
sd(i, j, :) = tmp(2, ind);
w(i, j, :) = tmp(3, ind);
matchcnt(i, j, :) = tmp(4, ind);
% 根据权重求出背景图像
if w(i, j, 1) > T
bg(i, j) = w(i, j, 1) * mean(i, j, 1);
else
if w(i, j, 1) + w(i, j, 2) > T
bg(i, j) = w(i, j, 1) * mean(i, j, 1) + w(i, j, 2) * mean(i, j, 2);
else
bg(i, j) = sum(w(i, j, :) .* mean(i, j, :));
end
end
end
end
figure(1),imshow(uint8(bg));
处理一帧需要3秒左右,能不能提高效率,运行的时间短点?
2017-3-25 19:01 上传
点击文件名下载附件
891.33 KB, 下载次数: 8
测试视频