需要使用摄像头
#include"opencv2/opencv.hpp"
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include"opencv2/imgproc/imgproc.hpp"
#include"opencv2/video/background_segm.hpp"
#include
using namespace cv;
using namespace std;
int main()
{
VideoCapture capture(0);
Ptr bg_model = createBackgroundSubtractorMOG2();
Mat image, fgimage, fgmask;
while (1)
{
capture >> image; //get new frame from camera
if (!image.data)
{
cerr << "picture error!";
return -1;
}
if (fgimage.empty())
fgimage.create(image.size(), image.type());
bg_model->apply(image, fgmask, -1);
fgimage = Scalar::all(0);
image.copyTo(fgimage, fgmask);
Mat bgimage;
bg_model->getBackgroundImage(bgimage);
imshow("image", image);
imshow("fgimage", fgimage);
imshow("fgmask", fgmask);
if (!bgimage.empty())
imshow("bgimage", bgimage);
waitKey(30);
}
return 0;
}
具体的算法实现函数在
opencv\sources\modules\video\src\bgfg_gaussmix2.cpp
可以对照算法原理查看
以下算法原理参考混合高斯模型算法原理
个人认为这篇文章将的比较通俗易懂,公式也比较简洁,比较适合入门理解。
文中介绍的是基础部分的内容,通常现在使用的GMM都带有一些后续改进,比如阴影检测等。
将图像中每一个像素点的颜色值看成一个随机过程,并假设其出现概率服从高斯分布。对每一个像素位置建立一个高斯模型,模型中保存其均值的方差。比如对于一个像素点 ( x , y ) (x,y) (x,y) ,可设其均值: μ ( x , y ) \mu(x,y) μ(x,y) ,方差: σ 2 ( x , y ) \sigma^2(x,y) σ2(x,y),标准差 σ ( x , y ) \sigma(x,y) σ(x,y)。
同时由于视频序列的输入,模型参数会不断更新,对应不同时刻参数有不同的值,可将模型参数表示为三个变量 ( x , y , t ) (x,y,t) (x,y,t)的函数。均值: μ ( x , y , t ) \mu(x,y,t) μ(x,y,t) ,方差: σ 2 ( x , y , t ) \sigma^2(x,y,t) σ2(x,y,t),标准差: σ ( x , y , t ) \sigma(x,y,t) σ(x,y,t)。
单高斯模型运动检测的基本过程:
1、 模型初始化
{ μ ( x , y , 0 ) = I ( x , y , 0 ) σ 2 ( x , y , 0 ) = s t d _ i n i t 2 σ ( x , y , 0 ) = s t d _ i n i t \begin{cases}\mu(x,y,0)=I(x,y,0)\\\sigma^2(x,y,0)=std\_init^2\\\sigma(x,y,0)=std\_init\end{cases} ⎩⎪⎨⎪⎧μ(x,y,0)=I(x,y,0)σ2(x,y,0)=std_init2σ(x,y,0)=std_init
其中 I ( x , y , 0 ) I(x,y,0) I(x,y,0)表示视频序列中的第一张图像在 ( x , y ) (x,y) (x,y)处的像素值,std_init为设置的初始常数。
2、更新参数并检测
每当读入一帧新的图象时,需要判断新图像中对应点像素是否在高斯模型描述的范围内,是则为背景(表示没有突变),否则为前景。假设前景检测的结果图是 o u t p u t output output
o u t p u t ( x , y , t ) = { 0 , ∣ I ( x , y , t ) − μ ( x , y , t − 1 ) ∣ < λ × σ ( x , y , t − 1 ) 1 , o t h e r w i s e output(x,y,t)=\begin{cases}0, |I(x,y,t)-\mu(x,y,t-1)|<\lambda\times\sigma(x,y,t-1)\\1,otherwise\end{cases} output(x,y,t)={0,∣I(x,y,t)−μ(x,y,t−1)∣<λ×σ(x,y,t−1)1,otherwise
其中 λ \lambda λ是设置的常数,含义:判断新图片中对应点像素和对象模型中像素的均值的距离小于标准差的 λ \lambda λ倍,则该点为背景,否则为前景。
模型的更新
{ μ ( x , y , t = ( 1 − α ) × μ ( x , y , t − 1 ) + α × μ ( x , y , t ) σ 2 ( x , y , t ) = ( 1 − α ) × σ 2 ( x , y , t − 1 ) + α × [ I ( x , y , t ) − μ ( x , y , t ) ] 2 σ ( x , y , t ) = σ 2 ( x , y , t ) \begin{cases}\mu(x,y,t=(1-\alpha)\times\mu(x,y,t-1)+\alpha\times\mu(x,y,t)\\\sigma^2(x,y,t)=(1-\alpha)\times\sigma^2(x,y,t-1)+\alpha\times[I(x,y,t)-\mu(x,y,t)]^2\\\sigma(x,y,t)=\sqrt{\sigma^2(x,y,t)}\end{cases} ⎩⎪⎨⎪⎧μ(x,y,t=(1−α)×μ(x,y,t−1)+α×μ(x,y,t)σ2(x,y,t)=(1−α)×σ2(x,y,t−1)+α×[I(x,y,t)−μ(x,y,t)]2σ(x,y,t)=σ2(x,y,t)
其中 α \alpha α表示更新率,此常数使模型在背景缓慢变化时具有一定的鲁棒性。
单高斯模型只能描述单一模式的背景,多模态形式下的背景检测极易出错。
多模态:模态(modality),在这里可以理解为背景可能呈现的多种状态。比如树叶的晃动,树叶在不同图像中会呈现几种固定的状态。
混合高斯模型的原理,就是对每个像素点建立多个高斯模型,试图将可能出现微小律动的像素点的几种状态都预估,那么当背景出现微小变化时,其仍然符合某个高斯模型,以此滤除非关注区域。
每个像素都由多个单模型描述: P ( p ) = [ ω i ( x , y , t ) , μ i ( x , y , t ) , σ i ( x , y , t ) 2 ] , i = 1 , 2 , . . . , K P(p)={[\omega_i(x,y,t),\mu_i(x,y,t),\sigma_i(x,y,t)^2]},i=1,2,...,K P(p)=[ωi(x,y,t),μi(x,y,t),σi(x,y,t)2],i=1,2,...,K。其中K就表示为每个像素点创立几个高斯模型,其值一般在3~5之间。 ω i ( x , y , t ) \omega_i(x,y,t) ωi(x,y,t)表示每个模型的权重,满足:
∑ i = 1 K ω i ( x , y , t ) = 1 \sum^K_{i=1}\omega_i(x,y,t)=1 i=1∑Kωi(x,y,t)=1
三个参数(权,均值,方差)确定一个单模型。
Step1:
判断如果新读入的视频图像序列中的图片在 ( x , y ) (x,y) (x,y)处的像素值对 i = 1 , 2 , . . . , K i=1,2,...,K i=1,2,...,K
o u t p u t ( x , y , t ) = { 0 , ∣ I ( x , y , t ) − μ i ( x , y , t − 1 ) ∣ < λ × σ i ( x , y , t − 1 ) 1 , o t h e r w i s e output(x,y,t)=\begin{cases}0, |I(x,y,t)-\mu_i(x,y,t-1)|<\lambda\times\sigma_i(x,y,t-1)\\1,otherwise\end{cases} output(x,y,t)={0,∣I(x,y,t)−μi(x,y,t−1)∣<λ×σi(x,y,t−1)1,otherwise
如果判断为背景,进入step2,如果判断为前景,进入step3
Step2:
修正与新像素匹配的单模型的权值,权值增量为 d w = α × ( 1 − ω i ( x , y , t − 1 ) ) dw=\alpha\times(1-\omega_i(x,y,t-1)) dw=α×(1−ωi(x,y,t−1)),则新的权值为
ω i ( x , y , t ) = ω i ( x , y , t − 1 ) + α × ( 1 − ω i ( x , y , t − 1 ) ) \omega_i(x,y,t)=\omega_i(x,y,t-1)+\alpha\times(1-\omega_i(x,y,t-1)) ωi(x,y,t)=ωi(x,y,t−1)+α×(1−ωi(x,y,t−1))
修正匹配模型的均值和方差,同高斯模型。
Step2完成后直接进入Step4
Step3:
如果新像素不如任何一个单模型匹配,则:
1、如果但钱单模型的数目已经到达允许的最大数目,则去除当前重要性(计算见后文)最小的单模型
2、增加一个新的单模型,新模型的权重为一个很小的值(比如0.001),均值为新像素值,方差为给定的较大的值(比如20)。(这样可以做到背景模型的更新)
Step4:权重归一化
ω i ( x , y , t ) = ω i ( x , y , t ) ∑ i = 1 K ω i ( x , y , t ) , ( i = 1 , 2 , . . . , K ) \omega_i(x,y,t)=\frac{\omega_i(x,y,t)}{\sum^K_{i=1}\omega_i(x,y,t)},(i=1,2,...,K) ωi(x,y,t)=∑i=1Kωi(x,y,t)ωi(x,y,t),(i=1,2,...,K)
根据背景模型的两个特点:
1、权重大:背景出现的频率高
2、方差小:像素值变化不大
则定义
s o r t _ k e y = ω i ( x , y , t ) σ i ( x , y , t ) sort\_key = \frac{\omega_i(x,y,t)}{\sigma_i(x,y,t)} sort_key=σi(x,y,t)ωi(x,y,t)
作为排序依据。
过程如下:
1、计算每个单模型的重要性值sort_key
2、对于各个单模型按照重要性的大小进行排序,重要性大的排在前面
3、若前N个单模型的权重满足
∑ i = 1 K ω i ( x , y , t ) > T \sum^K_{i=1}\omega_i(x,y,t)>T ∑i=1Kωi(x,y,t)>T,则仅用这N个单模型作为北京模型,删除其他模型,一般T=0.7