高斯混合模型 Gaussian Mixture Model (GMM)
Gaussian Mixture Model (GMM) 高斯混合模型 常用於影像處理中背景消去(Background Subtraction)中建立影像背景模型。同時也可以應用在
樣型識別(Pattern Recognition)以及
機器學習(Machine Learning)領域中的分群方法(Clustering)。
常見的背景消去法
最簡單靜態的背景消去方法是事先拍一張背景影像B(X,Y,t),接下來再拍攝相同背景含有物體在內的影像I(X,Y,t),接著再將兩張影像相減,得到所有像素的差值,自行訂立一個閥值(
Threshold),若大於閥值者,找出該相差值
大於閥值像素與其所在位置,即可找到該物體(前景, Foreground )。
|I(X,Y,t) - B(X,Y,t)| > Threshold
另一種應用於影片的背景消去方法是利用連續的影像,求出連續影像的平均值,以該平均值訂為背景,再利用上述的背景消方法找出物體。
但是上述的方式有以下優缺點
- 優點 : 簡單、計算快速
- 缺點 : 準確性不佳、影像幀數高則需要更多記憶體資源、若影像變動大則沒有一個固定的閥值(Ex. 白天到黑夜)
高斯混合模型 Gaussian Mixture Model (GMM)
為了解決上述的問題,Stauffer, C. and Grimson, W.E.L 等人在其
Adaptive Background Mixture Models for Real-Time Tracking, Computer Vision and Pattern Recognition (1999) 的論文中提出一種具有適應性的方法來嘗試解決上述缺點。
若將一幀影像視作一個統計模型,例如,灰階影像直方圖即是針對像素灰階值,我們可以將某個灰階值出現的可能性視作一個機率事件,而如此,此即為機率模型。而所謂的機率模型,就是在針對不同幀的影像進行一個統計過程,並由未知數X來求得Y的相關資訊。但是所求得的結果不是一個準確的數值,而是代表例如該像素
屬於前景物體像素的
機率是多少(符合的機率有多高?),而非該像素
是否屬於前景像素(Yes/No 的是非問題)。
而機率模型的好處就在於能夠判讀與操作的空間相對大了許多,而非非黑即白的問題。而在數學理論上,高斯模型能夠透過增加模型的個數以符合(fit)特定的機率分布情形。
(詳細的數學計算流程請參考這兩篇博文
聚类(1)——混合高斯模型 Gaussian Mixture Model 、
漫谈 Clustering (3): Gaussian Mixture Model)
若將自然分布(高斯分布)的概念引入這個問題中,我可以將像素視為同時有好幾個模式存在(Ex. 白天模式、傍晚模式、黑夜模式),及同時有好多個高斯模型(Gaussians)存在,此概念為mixture of adaptive Gaussians。若該像素不符合背景的高斯模型(Background Gaussian),則視作前景。我們可以將影像的分布機率視作K個高斯模型混合再一起(Mixture of Gaussians)
當然,GMM本身也是有優缺點
- 優點 : 每個像素可以有不同的閥值、閥值可以隨不同帧的影像調整、物體可以成為背景的一部分而不破壞背景
- 缺點 : 無法應對背景快速變動的光影變化、初始化的高斯模型(Gaussian)相當重要、太多參數需要決定
下面是以MATLAB所撰寫的程式,使用的版本為
R2014b,謝謝學弟黃博揚提供
%% - - Initail System - ->>
close all;
clear all;
clc;
%% - - Input Video - ->>
video_file = 'D:\20150922\2x2_B3\after_rot\1\canny20151018_4_otsu_canny_roi.avi';
video = VideoReader(video_file);
% -- Video Parameter Setting -->
frameRate = round(video.FrameRate);
nb_frame = get(video, 'numberOfFrames');
duration = video.Duration;
resize_ratio = 1;
frame_offset = 0;
% -- Video Save Setting -->
video_save = 0; %控制存檔與否
videoName = '檔案名稱.avi';
videoExtension = 'Uncompressed AVI'; %檔案格式
% -- GMM Background Substraction Setting -->
trainFrame = fix(frameRate * duration);
initVariance = 10^2;
minRatio = 0.7;
numGauss = 8;
fgDetector = vision.ForegroundDetector('NumTrainingFrames',trainFrame,...
'MinimumBackgroundRatio',minRatio,'NumGaussians',numGauss,...
'InitialVariance',initVariance);
%% - - Read First Frame - ->>
frame = read(video,1 + frame_offset);
frame = imresize(frame,resize_ratio);
[h,w,~] = size(frame);
%% - - Initial Display - ->>
figure(1);
fig = imshow(frame,'border','tight');
hold on;
%% - - Run Tracking Program - ->>
for k = 1 : nb_frame - frame_offset
tic;
%% - - Read Frame & Pre-processing - ->>
frame = read(video,k + frame_offset);
frame = imresize(frame,resize_ratio);
% -- GMM Background Substraction -->
segmentation = step(fgDetector,frame); % foregroundMask = step(H,I), I = input image
%% - - Corner Detection Setting - ->>
C = corner(frame(:,:,1), method, N);
%% - - Display Image - ->>
set(fig,'CData',segmentation); % fig為圖形的握把物件代稱
drawnow;
%% - - Save Video - ->>
if video_save == 1;
FrameSave(k) = getframe(gcf);
end
toc;
end
%% - - Save Video - ->>
if video_save == 1
VideoSave = VideoWriter(videoName,videoExtension);
VideoSave.FrameRate = frameRate;
open(VideoSave);
writeVideo(VideoSave,FrameSave);
close(VideoSave);
end