//gmm.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#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;
//定义gmm模型用到的变量
#define GMM_MAX_COMPONT 6
#define GMM_LEARN_ALPHA 0.005 //该学习率越大的话,学习速度太快,效果不好
#define GMM_THRESHOD_SUMW 0.7 //如果取值太大了的话,则更多树的部分都被检测出来了
#define END_FRAME 200
bool pause=false;
Mat w[GMM_MAX_COMPONT];
Mat u[GMM_MAX_COMPONT];
Mat sigma[GMM_MAX_COMPONT];
Mat fit_num,gmask,foreground;
vector<Mat> output_m;
Mat output_img;
float temp_w,temp_sigma;
unsigned char temp_u;
int i=-1;
//For connected components:
int CVCONTOUR_APPROX_LEVEL = 2; // Approx.threshold - the bigger it is, the simpler is the boundary
int CVCLOSE_ITR = 1;
//Just some convienience macros
#define CV_CVX_WHITE CV_RGB(0xff,0xff,0xff)
#define CV_CVX_BLACK CV_RGB(0x00,0x00,0x00)
//gmm整体初始化函数声明
void gmm_init(Mat img);
//gmm第一帧初始化函数声明
void gmm_first_frame(Mat img);
//gmm训练过程函数声明
void gmm_train(Mat img);
//对输入图像每个像素gmm选择合适的个数函数声明
void gmm_fit_num(Mat img);
//gmm测试函数的实现
void gmm_test(Mat img);
//连通域去噪函数声明
void find_connected_components(Mat img);
//void cvconnectedComponents(IplImage *mask, int poly1_hull0, float perimScale, int *num, CvRect *bbs, CvPoint *centers);
int main(int argc, const char* argv[])
{
Mat img,img_gray;
char str_num[5];
// char *str_num;//why does this definition not work?
String str="WavingTrees/b00";//string,the 's' can be a captial or lower-caseletters
/****read the first image,and reset the array w,u,sigma****/
img=imread("WavingTrees/b00000.bmp");
if(img.empty())
return -1;
output_img=Mat::zeros(img.size(),img.type());
cvtColor(img,img_gray,CV_BGR2GRAY);//covert the colorful image to the corresponding gray-level image
/****initialization the three parameters ****/
gmm_init(img_gray);
fit_num=Mat(img.size(),CV_8UC1,-1);//初始化为1
gmask=Mat(img.size(),CV_8UC1,-1);
foreground=img.clone();
split(img,output_m);
output_m[0]=Mat::zeros(img.size(),output_m[0].type());
output_m[1]=Mat::zeros(img.size(),output_m[0].type());
output_m[2]=Mat::zeros(img.size(),output_m[0].type());
namedWindow("src",WINDOW_AUTOSIZE);
namedWindow("gmask",WINDOW_AUTOSIZE);
//在定义视频输出对象时,文件名一定后面要加后缀,比如这里的.avi,否则是输出不了视频的!并且这里只能是avi格式的,当参数为('P','I','M','1')时
VideoWriter output_src("src.avi",CV_FOURCC('P','I','M','1'),20,Size(160,120),1);//c++版本的opencv用Size函数即可,c版本的用cvSize()函数
//VideoWriter output_src("src.avi",CV_FOURCC('M','J','P','G'),5,Size(160,120),1);//c++版本的opencv用Size函数即可,c版本的用cvSize()函数
VideoWriter output_dst("dst.avi",CV_FOURCC('P','I','M','1'),20,Size(160,120),1);//这样输出的是3个通道的数据
while(1)
{
if(!pause)
{
/****read image from WavingTrees****/
i++;
_itoa_s(i,str_num,10);//the latest name is _itoa_s or _itoa,not the itoa,although iota can be used,deprecated
if(i<10)
str+="00";
else if(i<100)
str+="0";
else if(i>285)//we used the first 285 frames to learn the gmm model
i=-1;
str+=str_num;
str+=".bmp";
img=imread(str);
if(img.empty())
break;
str="WavingTrees/b00";//after read,str must be reseted ;
cvtColor(img,img_gray,CV_BGR2GRAY);//covert the colorful image to the corresponding gray-level image
/****when it is the first frame,set the default parameter****/
if(1==i)
{
gmm_first_frame(img_gray);
}
//the train of gmm phase
//if(1<i&&i<5&&i!=3)//由此可知当i大于等于3以后,就会一直出现错误,且错误在内部排序的部分
if(1<i<END_FRAME)
{
gmm_train(img_gray);
}//end the train phase
cout<<i<<endl;
/****chose the fitting number of component in gmm****/
if(END_FRAME==i)
{
gmm_fit_num(img_gray);
// cout<<fit_num<<endl;//其输出值有4个高斯的,但也有0个高斯的,why?照理说不可能的啊!
}
/****start the test phase****/
if(i>=END_FRAME)
{
output_src<<img;
gmm_test(img_gray);
find_connected_components(img_gray);
output_m[0]=gmask.clone();
output_m[1]=gmask.clone();
output_m[2]=gmask.clone();
merge(output_m,output_img);
output_dst<<output_img;
}
if(285==i)
{
return 0;
}
imshow("src",img);
imshow("gmask",gmask);
}
char c=(char)waitKey(1);
if(c==27)//if press the ESC key,the exit the proggram
break;
if(c==' ')
// pause=~pause;//if use '~',then the pause key cannot work,why?
pause=!pause;
}
return 0;
}
//gmm初始化函数实现
void gmm_init(Mat img)
{
/****initialization the three parameters ****/
for(int j=0;j<GMM_MAX_COMPONT;j++)
{
w[j]=Mat(img.size(),CV_32FC1,0.0);//CV_32FC1本身体现了正负符号
u[j]=Mat(img.size(),CV_8UC1,-1);//为什么这里赋值为0时,后面的就一直出错?暂时还不知道原因,先赋值-1,其实内部存储的也是0
sigma[j]=Mat(img.size(),CV_32FC1,0.0);//float类型
}
//为什么一下语句不能放在这个函数里面呢
// output_m[0]=Mat(img.size(),CV_8UC1,0);
// output_m[1]=Mat(img.size(),CV_8UC1,0);
// output_m[2]=Mat(img.size(),CV_8UC1,0);
}
//gmm第一帧初始化函数实现
void gmm_first_frame(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;
//if the pixvel is gray-clever,then we should use unsigned char,not the unsigned int
u[0].at<unsigned char>(m,n)=img.at<unsigned char>(m,n);// 一定要注意其类型转换,否则会得不得预期的结果
sigma[0].at<float>(m,n)=15.0;//opencv 自带的gmm代码中用的是15.0
for(int k=1;k<GMM_MAX_COMPONT;k++)
{
/****when assigment this,we must be very carefully****/
w[k].at<float>(m,n)=0.0;
u[k].at<unsigned char>(m,n)=-1;
sigma[k].at<float>(m,n)=15.0;//防止后面排序时有分母为0的情况
}
}
}
//gmm训练过程函数实现
void gmm_train(Mat img)
{
for(int m=0;m<img.rows;m++)
for(int n=0;n<img.cols;n++)
{
int k=0;
int nfit=0;
for(;k<GMM_MAX_COMPONT;k++)
{
// if(w[k].at<float>(m,n)!=0)//只有在权值不为0的情况下才进行比较
// {
int delam=abs(img.at<unsigned char>(m,n)-u[k].at<unsigned char>(m,n));//防止溢出
long dis=