1.参考
http://www.cnblogs.com/tornadomeet/archive/2012/06/02/2531565.html
http://www.doc88.com/p-7435437562598.html
2.没有形态学处理的代码
#include "cv.h"
#include "highgui.h"
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <stdio.h>
#include <iostream>
using namespace cv;
using namespace std;
const char* openfile="C:\\Users\\dell\\Desktop\\hall_night.avi";
#define GMM_MAX_COMPONT 5
#define GMM_LEARN_ALPHA1 0.01 //该学习率越大的话,学习速度太快,效果不好
#define GMM_LEARN_ALPHA2 0.005 //采用前20帧训练GMM时,学习速率较大。建立好后学习速率改小
#define GMM_THRESHOD_SUMW 0.7 //如果取值太大了的话,则更多树的部分都被检测出来了
#define END_FRAME 100
Mat w[GMM_MAX_COMPONT];
Mat u[GMM_MAX_COMPONT];
Mat sigma[GMM_MAX_COMPONT];
Mat w_sigma[GMM_MAX_COMPONT]; //用来给高斯模型排序的量
Mat fit_num,gmask;
bool pause=false;
//gmm模型初始化函数声明
void gmm_init(Mat img);
//gmm第一帧初始化函数声明
void gmm_firstframe_init(Mat img);
//高斯模型更新函数声明,并且将高斯模型按w/sigma从大到小排序
void gmm_renew(Mat img,float GMM_LEARN_ALPHA);
//对输入图像每个像素gmm选择合适的个数函数声明
void gmm_fit_num(Mat img);
//gmm测试函数的实现
void gmm_test(Mat img);
void main()
{
cvNamedWindow("1",CV_WINDOW_AUTOSIZE);
cvNamedWindow("2",CV_WINDOW_AUTOSIZE);
CvCapture* capture=cvCreateFileCapture(openfile);
IplImage* frame;
int t=0;
while(1)
{
frame=cvQueryFrame(capture); //每3帧提取一次背景
frame=cvQueryFrame(capture);
frame=cvQueryFrame(capture);
if(!frame)break;
t=t+1;
IplImage *frame_gray=cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
cvCvtColor(frame,frame_gray,CV_BGR2GRAY);
cvShowImage("1",frame_gray);
Mat img=Mat(frame_gray);
if(t==1){
gmm_init(img);
gmm_firstframe_init(img);
}
else if(t<END_FRAME){ //注意这里没有=
float GMM_LEARN_ALPHA=GMM_LEARN_ALPHA1;
gmm_renew(img,GMM_LEARN_ALPHA);
gmm_fit_num(img);
gmm_test(img);
imshow("2",gmask);
}
else{
float GMM_LEARN_ALPHA=GMM_LEARN_ALPHA2;
gmm_renew(img,GMM_LEARN_ALPHA);
gmm_fit_num(img);
gmm_test(img);
imshow("2",gmask);
}
char c = cvWaitKey(33);
if(c==27)break;
}
}
void gmm_init(Mat img){
for(int j=0;j<GMM_MAX_COMPONT;j++)
{
w[j]=Mat(img.size(),CV_32FC1,0.0);
u[j]=Mat(img.size(),CV_8UC1,-1); //为什么如果这个地方赋值为0就会出错??
sigma[j]=Mat(img.size(),CV_32FC1,0.0);
w_sigma[j]=Mat(img.size(),CV_32FC1,0.0);
}
}
void gmm_firstframe_init(Mat img){
for(int m=0;m<img.rows;m++)
for(int n=0;n<img.cols;n++)
{
w[0].at<float>(m,n)=1.0;
u[0].at<unsigned char>(m,n)=img.at<unsigned char>(m,n);
sigma[0].at<float>(m,n)=15.0;
for(int k=1;k<GMM_MAX_COMPONT;k++)
{
w[k].at<float>(m,n)=0.0;
u[k].at<unsigned char>(m,n)=-1;
sigma[k].at<float>(m,n)=15.0;
}
}
}
void gmm_renew(Mat img,float GMM_LEARN_ALPHA){
for(int m=0;m<img.rows;m++)
for(int n=0;n<img.cols;n++)
{
pause=false;
int k=0;
for(k=0;k<GMM_MAX_COMPONT;k++)
{
//如果有匹配的高斯模型则将该高斯模型按下面方法来更新,对于不匹配的高斯模型,其权值会变化。说明每个高斯组件在3*sigma内不会相交。
if((double)(abs(img.at<unsigned char>(m,n)-u[k].at<unsigned char>(m,n))*abs(img.at<unsigned char>(m,n)-u[k].at<unsigned char>(m,n)))<9*sigma[k].at<float>(m,n)) //
{
pause=true; //如果有匹配成功的,则成功匹配的标志标记为1
w[k].at<float>(m,n)=(1-GMM_LEARN_ALPHA)*w[k].at<float>(m,n)+GMM_LEARN_ALPHA;
u[k].at<unsigned char>(m,n)=u[k].at<unsigned char>(m,n)+GMM_LEARN_ALPHA*(img.at<unsigned char>(m,n)-u[k].at<unsigned char>(m,n))/w[k].at<float>(m,n);
sigma[k].at<float>(m,n)=sigma[k].at<float>(m,n)+(GMM_LEARN_ALPHA/w[k].at<float>(m,n))*((img.at<unsigned char>(m,n)-u[k].at<unsigned char>(m,n))*(img.at<unsigned char>(m,n)-u[k].at<unsigned char>(m,n))-sigma[k].at<float>(m,n));
}
else
{
w[k].at<float>(m,n)=(1-GMM_LEARN_ALPHA)*w[k].at<float>(m,n);
}
w_sigma[k].at<float>(m,n)=w[k].at<float>(m,n)/sigma[k].at<float>(m,n);
}
//把高斯模型按w/sigma从大到小进行排序
for(int i=1;i<GMM_MAX_COMPONT;i++) //插入排序
{
if(w_sigma[i-1].at<float>(m,n)<w_sigma[i].at<float>(m,n))
{
float temp1=w_sigma[i].at<float>(m,n);
float temp2=w[i].at<float>(m,n);
unsigned char temp3=u[i].at<unsigned char>(m,n);
float temp4=sigma[i].at<float>(m,n);
int j=i;
while(j>0&&w_sigma[j-1].at<float>(m,n)<temp1)
{
w_sigma[j].at<float>(m,n)=w_sigma[j-1].at<float>(m,n);
w[j].at<float>(m,n)=w[j-1].at<float>(m,n);
u[j].at<unsigned char>(m,n)=u[j-1].at<unsigned char>(m,n);
sigma[j].at<float>(m,n)=sigma[j-1].at<float>(m,n);
j--;
}
w_sigma[j].at<float>(m,n)=temp1;
w[j].at<float>(m,n)=temp2;
u[j].at<unsigned char>(m,n)=temp3;
sigma[j].at<float>(m,n)=temp4;
}
}
//当有新值出现的时候,如果组件个数小于 GMM_MAX_COMPONENT ,则新添加一个组件,新采样值作为均值,赋予较大方差 较小权值
if(k==GMM_MAX_COMPONT&&pause==false&&u[k-1].at<unsigned char>(m,n)==0)
{
int c=0;
for(;c<GMM_MAX_COMPONT;c++)
{
if(u[c].at<unsigned char>(m,n)==0)
{
w[c].at<float>(m,n)=GMM_LEARN_ALPHA;
u[c].at<unsigned char>(m,n)=img.at<unsigned char>(m,n);
sigma[c].at<float>(m,n)=15.0;
//归一化权重,使其总和为1
int d=0;
for(;d<GMM_MAX_COMPONT&&d!=c;d++)
{
w[d].at<float>(m,n) *=(1-GMM_LEARN_ALPHA);
}
break;
}
}
}
//如果GMM_MAX_COMPONENT 都赋有值 ,则用新的高斯组件 代替 权值最弱的高斯组件,权值不变,只更新均值和方差
else if(k==GMM_MAX_COMPONT&&pause==false&&u[k-1].at<unsigned char>(m,n)!=0){
u[k-1].at<unsigned char>(m,n)=img.at<unsigned char>(m,n);
sigma[k-1].at<float>(m,n)=15.0;
}
}
}
void gmm_fit_num(Mat img){
fit_num=Mat(img.size(),CV_8UC1,-1);
for(int m=0;m<img.rows;m++)
for(int n=0;n<img.cols;n++)
{
float sum=0;
for(int k=0;k<GMM_MAX_COMPONT;k++)
{
sum=sum+w[k].at<float>(m,n);
if(sum>=GMM_THRESHOD_SUMW)
{
fit_num.at<unsigned char>(m,n)=k+1;
break;
}
}
}
}
void gmm_test(Mat img){
gmask=Mat(img.size(),CV_8UC1,-1);
for(int m=0;m<img.rows;m++)
for(int n=0;n<img.cols;n++)
{
unsigned char a=0;
for(;a<fit_num.at<unsigned char>(m,n);a++)
{
if((double)(abs(img.at<unsigned char>(m,n)-u[a].at<unsigned char>(m,n))*abs(img.at<unsigned char>(m,n)-u[a].at<unsigned char>(m,n)))<(9*sigma[a].at<float>(m,n))) //注意这里是9,另外要有double
{
gmask.at<unsigned char>(m,n)=0; //背景
break;
}
}
if(a==fit_num.at<unsigned char>(m,n))
gmask.at<unsigned char>(m,n)=255; //前景
}
}