一直希望能实现混合高斯算法,查找了一下OpenCV中现有的东西,发现有关于EM的实现,于是尝试去使用,实现函数在……\OpenCV\ml\src中mlem.cpp中,但是关于使用的资料比较少,操作文档里有一个例程,首先从这个例程开始吧。
其中主要注意的问题就是数据格式,训练数据与测试数据要有共同的数据格式,而且测试数据必须为1维数据。
问题一:但是关于predict这个函数返回的数据是得分最高的聚类类别,而是否能利用这个函数第二个参数probs返回每个概率还有待验证,google到的结果是
直接应用prob矩阵:http://tech.groups.yahoo.com/group/OpenCV/message/40633
但是有些数据返回NAN 有同样问题 http://tech.groups.yahoo.com/group/OpenCV/message/48530,不知道怎样解决
需要改mlem.cpp:https://code.ros.org/trac/opencv/ticket/964
问题二:关于em中参数返回的数据格式是float还是double,如果想知道这些数据,又涉及到读取CvMat中数据,难道要尝试才能得到结果?
想要应用还需要弄清楚很多问题,还需要继续努力……
#include "stdio.h"
#include "ml.h"
#include "highgui.h"
#include "iostream.h"
int main( int argc, char** argv )
{
const int N = 4;//高斯个数
const int N1 = (int)sqrt((double)N);
const CvScalar colors[] = {{{0,0,255}},{{0,255,0}},{{0,255,255}},{{255,255,0}}};
int i, j;
int nsamples = 100;//训练个数
CvRNG rng_state = cvRNG(-1);
CvMat* samples = cvCreateMat( nsamples, 2,CV_32FC1 );//浮点1通道
CvMat* labels = cvCreateMat( nsamples, 1, CV_32SC1 );
IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 );
float _sample[2];
CvMat sample = cvMat( 1, 2, CV_32FC1, _sample );
CvEM em_model;
CvEMParams params;
CvMat samples_part;
cvReshape( samples, samples, 2, 0 );//不拷贝数据修改矩阵/图像形状 ;2为新的通道数
for( i = 0; i < N; i++ )
{
CvScalar mean, sigma;
//数组的一行或在一定跨度内的行 //输入,输出,起始索引,结束索引
cvGetRows(samples, &samples_part, i*nsamples/N, (i+1)*nsamples/N );
//均值,方差?
mean = cvScalar(((i%N1)+1.)*img->width/(N1+1), ((i/N1)+1.)*img->height/(N1+1));
sigma = cvScalar(30,30);
//用随机数填充数组并更新 RNG 状态
cvRandArr( &rng_state, &samples_part, CV_RAND_NORMAL, mean, sigma );
}
cvReshape( samples, samples, 1, 0 );//重新为1通道数
// initialize model's parameters
params.covs = NULL;
params.means = NULL;
params.weights = NULL;
params.probs = NULL;
params.nclusters = N;
params.cov_mat_type = CvEM::COV_MAT_SPHERICAL;
params.start_step = CvEM::START_AUTO_STEP;
params.term_crit.max_iter = 10;
params.term_crit.epsilon = 0.1;
params.term_crit.type = CV_TERMCRIT_ITER|CV_TERMCRIT_EPS;
// cluster the data
em_model.train( samples, 0, params, labels );
// classify every image pixel
cvZero( img );
for( i = 0; i < img->height; i++ )
{
for( j = 0; j < img->width; j++ )
{
CvPoint pt = cvPoint(j, i);
float *data=sample.data.fl;
data[0] = (float)j;
data[1] = (float)i;
int response = cvRound(em_model.predict( &sample, NULL ));
CvScalar c = colors[response];
cvCircle( img, pt, 1, cvScalar(c.val[0]*0.75,c.val[1]*0.75,c.val[2]*0.75), CV_FILLED );
}
}
//draw the clustered samples
for( i = 0; i < nsamples; i++ )
{
CvPoint pt;
pt.x = cvRound(samples->data.fl[i*2]);
pt.y = cvRound(samples->data.fl[i*2+1]);
cvCircle( img, pt, 1 , colors[labels->data.i[i]], CV_FILLED );
}
cvNamedWindow( "EM-clustering result", 1 );
cvShowImage( "EM-clustering result", img );
cvWaitKey(0);
cvReleaseMat( &samples );
cvReleaseMat( &labels );
return 0;
}