Commit b8c31006 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

modified EM interface; updated tests & samples

parent 1c1c6b98
......@@ -66,7 +66,6 @@ struct CV_EXPORTS CvMotionModel
}
float low_pass_gain; // low pass gain
cv::EM::Params em_params; // EM parameters
};
// Mean Shift Tracker parameters for specifying use of HSV channel and CamShift parameters.
......@@ -109,7 +108,6 @@ struct CV_EXPORTS CvHybridTrackerParams
float ms_tracker_weight;
CvFeatureTrackerParams ft_params;
CvMeanShiftTrackerParams ms_params;
cv::EM::Params em_params;
int motion_model;
float low_pass_gain;
};
......@@ -182,7 +180,6 @@ private:
CvMat* samples;
CvMat* labels;
cv::EM em_model;
Rect prev_window;
Point2f prev_center;
......
......@@ -132,17 +132,6 @@ void CvHybridTracker::newTracker(Mat image, Rect selection) {
mstracker->newTrackingWindow(image, selection);
fttracker->newTrackingWindow(image, selection);
params.em_params.covs = NULL;
params.em_params.means = NULL;
params.em_params.probs = NULL;
params.em_params.nclusters = 1;
params.em_params.weights = NULL;
params.em_params.covMatType = cv::EM::COV_MAT_SPHERICAL;
params.em_params.startStep = cv::EM::START_AUTO_STEP;
params.em_params.termCrit.maxCount = 10000;
params.em_params.termCrit.epsilon = 0.001;
params.em_params.termCrit.type = cv::TermCriteria::COUNT + cv::TermCriteria::EPS;
samples = cvCreateMat(2, 1, CV_32FC1);
labels = cvCreateMat(2, 1, CV_32SC1);
......@@ -222,12 +211,15 @@ void CvHybridTracker::updateTrackerWithEM(Mat image) {
}
cv::Mat lbls;
em_model.train(samples, cv::Mat(), params.em_params, &lbls);
EM em_model(1, EM::COV_MAT_SPHERICAL, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10000, 0.001));
em_model.train(cvarrToMat(samples), lbls);
if(labels)
*labels = lbls;
lbls.copyTo(cvarrToMat(labels));
curr_center.x = (float)em_model.getMeans().at<double> (0, 0);
curr_center.y = (float)em_model.getMeans().at<double> (0, 1);
Mat em_means = em_model.get<Mat>("means");
curr_center.x = (float)em_means.at<float>(0, 0);
curr_center.y = (float)em_means.at<float>(0, 1);
}
void CvHybridTracker::updateTrackerWithLowPassFilter(Mat image) {
......
......@@ -1821,10 +1821,10 @@ public:
CV_WRAP virtual double calcLikelihood( const cv::Mat &sample ) const;
CV_WRAP int getNClusters() const;
CV_WRAP const cv::Mat& getMeans() const;
CV_WRAP cv::Mat getMeans() const;
CV_WRAP void getCovs(CV_OUT std::vector<cv::Mat>& covs) const;
CV_WRAP const cv::Mat& getWeights() const;
CV_WRAP const cv::Mat& getProbs() const;
CV_WRAP cv::Mat getWeights() const;
CV_WRAP cv::Mat getProbs() const;
CV_WRAP inline double getLikelihood() const { return emObj.isTrained() ? likelihood : DBL_MAX; }
#endif
......
......@@ -41,6 +41,8 @@
#include "precomp.hpp"
using namespace cv;
CvEMParams::CvEMParams() : nclusters(10), cov_mat_type(CvEM::COV_MAT_DIAGONAL),
start_step(CvEM::START_AUTO_STEP), probs(0), weights(0), means(0), covs(0)
{
......@@ -76,38 +78,44 @@ void CvEM::clear()
void CvEM::read( CvFileStorage* fs, CvFileNode* node )
{
cv::FileNode fn(fs, node);
FileNode fn(fs, node);
emObj.read(fn);
set_mat_hdrs();
}
void CvEM::write( CvFileStorage* _fs, const char* name ) const
{
cv::FileStorage fs = _fs;
FileStorage fs = _fs;
if(name)
fs << name << "{";
emObj.write(fs);
if(name)
fs << "}";
fs.fs.obj = 0;
}
double CvEM::calcLikelihood( const cv::Mat &input_sample ) const
double CvEM::calcLikelihood( const Mat &input_sample ) const
{
double likelihood;
emObj.predict(input_sample, 0, &likelihood);
emObj.predict(input_sample, noArray(), &likelihood);
return likelihood;
}
float
CvEM::predict( const CvMat* _sample, CvMat* _probs, bool isNormalize ) const
{
cv::Mat prbs;
int cls = emObj.predict(_sample, _probs ? &prbs : 0);
Mat prbs0 = cvarrToMat(_probs), prbs = prbs0, sample = cvarrToMat(_sample);
int cls = emObj.predict(sample, _probs ? _OutputArray(prbs) : _OutputArray::_OutputArray());
if(_probs)
{
if(isNormalize)
cv::normalize(prbs, prbs, 1, 0, cv::NORM_L1);
*_probs = prbs;
normalize(prbs, prbs, 1, 0, NORM_L1);
if( prbs.data != prbs0.data )
{
CV_Assert( prbs.size == prbs0.size );
prbs.convertTo(prbs0, prbs0.type());
}
}
return (float)cls;
}
......@@ -116,73 +124,55 @@ void CvEM::set_mat_hdrs()
{
if(emObj.isTrained())
{
meansHdr = emObj.getMeans();
covsHdrs.resize(emObj.getNClusters());
covsPtrs.resize(emObj.getNClusters());
const std::vector<cv::Mat>& covs = emObj.getCovs();
meansHdr = emObj.get<Mat>("means");
int K = emObj.get<int>("nclusters");
covsHdrs.resize(K);
covsPtrs.resize(K);
const std::vector<Mat>& covs = emObj.get<vector<Mat> >("covs");
for(size_t i = 0; i < covsHdrs.size(); i++)
{
covsHdrs[i] = covs[i];
covsPtrs[i] = &covsHdrs[i];
}
weightsHdr = emObj.getWeights();
weightsHdr = emObj.get<Mat>("weights");
probsHdr = probs;
}
}
static
void init_params(const CvEMParams& src, cv::EM::Params& dst,
cv::Mat& prbs, cv::Mat& weights,
cv::Mat& means, cv::vector<cv::Mat>& covsHdrs)
void init_params(const CvEMParams& src,
Mat& prbs, Mat& weights,
Mat& means, vector<Mat>& covsHdrs)
{
dst.nclusters = src.nclusters;
dst.covMatType = src.cov_mat_type;
dst.startStep = src.start_step;
dst.termCrit = src.term_crit;
prbs = src.probs;
dst.probs = &prbs;
weights = src.weights;
dst.weights = &weights;
means = src.means;
dst.means = &means;
if(src.covs)
{
covsHdrs.resize(src.nclusters);
for(size_t i = 0; i < covsHdrs.size(); i++)
covsHdrs[i] = src.covs[i];
dst.covs = &covsHdrs;
}
}
bool CvEM::train( const CvMat* _samples, const CvMat* _sample_idx,
CvEMParams _params, CvMat* _labels )
{
cv::EM::Params params;
cv::Mat prbs, weights, means;
std::vector<cv::Mat> covsHdrs;
init_params(_params, params, prbs, weights, means, covsHdrs);
cv::Mat lbls;
cv::Mat likelihoods;
bool isOk = emObj.train(_samples, _sample_idx, params, _labels ? &lbls : 0, &probs, &likelihoods );
if(isOk)
{
if(_labels)
*_labels = lbls;
likelihood = cv::sum(likelihoods)[0];
set_mat_hdrs();
}
CV_Assert(_sample_idx == 0);
Mat samples = cvarrToMat(_samples), labels0, labels;
if( _labels )
labels0 = labels = cvarrToMat(_labels);
bool isOk = train(samples, Mat(), _params, _labels ? &labels : 0);
CV_Assert( labels0.data == labels.data );
return isOk;
}
int CvEM::get_nclusters() const
{
return emObj.getNClusters();
return emObj.get<int>("nclusters");
}
const CvMat* CvEM::get_means() const
......@@ -215,16 +205,29 @@ CvEM::CvEM( const Mat& samples, const Mat& sample_idx, CvEMParams params )
bool CvEM::train( const Mat& _samples, const Mat& _sample_idx,
CvEMParams _params, Mat* _labels )
{
cv::EM::Params params;
cv::Mat prbs, weights, means;
std::vector<cv::Mat> covsHdrs;
init_params(_params, params, prbs, weights, means, covsHdrs);
cv::Mat likelihoods;
bool isOk = emObj.train(_samples, _sample_idx, params, _labels, &probs, &likelihoods);
Mat prbs, weights, means, likelihoods;
std::vector<Mat> covsHdrs;
init_params(_params, prbs, weights, means, covsHdrs);
emObj = EM(_params.nclusters, _params.cov_mat_type, _params.term_crit);
bool isOk = false;
if( _params.start_step == EM::START_AUTO_STEP )
isOk = emObj.train(_samples, _labels ? _OutputArray(*_labels) : _OutputArray::_OutputArray(),
probs, likelihoods);
else if( _params.start_step == EM::START_E_STEP )
isOk = emObj.trainE(_samples, means, covsHdrs, weights,
_labels ? _OutputArray(*_labels) : _OutputArray::_OutputArray(),
probs, likelihoods);
else if( _params.start_step == EM::START_M_STEP )
isOk = emObj.trainM(_samples, prbs,
_labels ? _OutputArray(*_labels) : _OutputArray::_OutputArray(),
probs, likelihoods);
else
CV_Error(CV_StsBadArg, "Bad start type of EM algorithm");
if(isOk)
{
likelihoods = cv::sum(likelihoods).val[0];
likelihoods = sum(likelihoods).val[0];
set_mat_hdrs();
}
......@@ -234,34 +237,34 @@ bool CvEM::train( const Mat& _samples, const Mat& _sample_idx,
float
CvEM::predict( const Mat& _sample, Mat* _probs, bool isNormalize ) const
{
int cls = emObj.predict(_sample, _probs);
int cls = emObj.predict(_sample, _probs ? _OutputArray(*_probs) : _OutputArray::_OutputArray());
if(_probs && isNormalize)
cv::normalize(*_probs, *_probs, 1, 0, cv::NORM_L1);
normalize(*_probs, *_probs, 1, 0, NORM_L1);
return (float)cls;
}
int CvEM::getNClusters() const
{
return emObj.getNClusters();
return emObj.get<int>("nclusters");
}
const Mat& CvEM::getMeans() const
Mat CvEM::getMeans() const
{
return emObj.getMeans();
return emObj.get<Mat>("means");
}
void CvEM::getCovs(vector<Mat>& _covs) const
{
_covs = emObj.getCovs();
_covs = emObj.get<vector<Mat> >("covs");
}
const Mat& CvEM::getWeights() const
Mat CvEM::getWeights() const
{
return emObj.getWeights();
return emObj.get<Mat>("weights");
}
const Mat& CvEM::getProbs() const
Mat CvEM::getProbs() const
{
return probs;
}
......
......@@ -371,19 +371,20 @@ protected:
virtual void run( int /*start_from*/ )
{
int code = cvtest::TS::OK;
cv::EM em;
Mat samples = Mat(3,1,CV_32F);
samples.at<float>(0,0) = 1;
samples.at<float>(1,0) = 2;
samples.at<float>(2,0) = 3;
Mat labels(samples.rows, 1, CV_32S);
cv::EM::Params params;
CvEMParams params;
params.nclusters = 2;
Mat labels;
CvMat samples_c = samples, labels_c = labels;
em.train(samples, Mat(), params, &labels);
CvEM em(&samples_c, 0, params, &labels_c);
Mat firstResult(samples.rows, 1, CV_32FC1);
for( int i = 0; i < samples.rows; i++)
......@@ -396,9 +397,7 @@ protected:
FileStorage fs = FileStorage(filename, FileStorage::WRITE);
try
{
fs << "em" << "{";
em.write(fs);
fs << "}";
em.write(fs.fs, "em");
}
catch(...)
{
......@@ -416,7 +415,7 @@ protected:
FileNode fn = fs["em"];
try
{
em.read(fn);
em.read(fs.fs, (CvFileNode*)fn.node);
}
catch(...)
{
......
......@@ -555,61 +555,66 @@ protected:
\****************************************************************************************/
namespace cv
{
class CV_EXPORTS EM : public Algorithm
class CV_EXPORTS_W EM : public Algorithm
{
public:
// Type of covariation matrices
enum {COV_MAT_SPHERICAL=0, COV_MAT_DIAGONAL=1, COV_MAT_GENERIC=2};
enum {COV_MAT_SPHERICAL=0, COV_MAT_DIAGONAL=1, COV_MAT_GENERIC=2, COV_MAT_DEFAULT=COV_MAT_DIAGONAL};
// Default parameters
enum {DEFAULT_NCLUSTERS=10, DEFAULT_MAX_ITERS=100};
// The initial step
enum {START_E_STEP=1, START_M_STEP=2, START_AUTO_STEP=0};
class CV_EXPORTS Params
{
public:
Params(int nclusters=10, int covMatType=EM::COV_MAT_DIAGONAL, int startStep=EM::START_AUTO_STEP,
const cv::TermCriteria& termCrit=cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 100, FLT_EPSILON),
const cv::Mat* probs=0, const cv::Mat* weights=0,
const cv::Mat* means=0, const std::vector<cv::Mat>* covs=0);
int nclusters;
int covMatType;
int startStep;
// all 4 following matrices should have type CV_32FC1
const cv::Mat* probs;
const cv::Mat* weights;
const cv::Mat* means;
const std::vector<cv::Mat>* covs;
cv::TermCriteria termCrit;
};
EM();
EM(const cv::Mat& samples, const cv::Mat samplesMask=cv::Mat(),
const EM::Params& params=EM::Params(), cv::Mat* labels=0, cv::Mat* probs=0, cv::Mat* likelihoods=0);
CV_WRAP EM(int nclusters=EM::DEFAULT_NCLUSTERS, int covMatType=EM::COV_MAT_DIAGONAL,
const TermCriteria& termcrit=TermCriteria(TermCriteria::COUNT+
TermCriteria::EPS,
EM::DEFAULT_MAX_ITERS, FLT_EPSILON));
virtual ~EM();
virtual void clear();
virtual bool train(const cv::Mat& samples, const cv::Mat& samplesMask=cv::Mat(),
const EM::Params& params=EM::Params(), cv::Mat* labels=0, cv::Mat* probs=0, cv::Mat* likelihoods=0);
int predict(const cv::Mat& sample, cv::Mat* probs=0, double* likelihood=0) const;
CV_WRAP virtual void clear();
bool isTrained() const;
int getNClusters() const;
int getCovMatType() const;
CV_WRAP virtual bool train(InputArray samples,
OutputArray labels=noArray(),
OutputArray probs=noArray(),
OutputArray likelihoods=noArray());
CV_WRAP virtual bool trainE(InputArray samples,
InputArray means0,
InputArray covs0=noArray(),
InputArray weights0=noArray(),
OutputArray labels=noArray(),
OutputArray probs=noArray(),
OutputArray likelihoods=noArray());
CV_WRAP virtual bool trainM(InputArray samples,
InputArray probs0,
OutputArray labels=noArray(),
OutputArray probs=noArray(),
OutputArray likelihoods=noArray());
CV_WRAP int predict(InputArray sample,
OutputArray probs=noArray(),
CV_OUT double* likelihood=0) const;
const cv::Mat& getWeights() const;
const cv::Mat& getMeans() const;
const std::vector<cv::Mat>& getCovs() const;
CV_WRAP bool isTrained() const;
AlgorithmInfo* info() const;
virtual void read(const FileNode& fn);
protected:
virtual void setTrainData(const cv::Mat& samples, const cv::Mat& samplesMask, const EM::Params& params);
bool doTrain(const cv::TermCriteria& termCrit);
virtual void setTrainData(int startStep, const Mat& samples,
const Mat* probs0,
const Mat* means0,
const vector<Mat>* covs0,
const Mat* weights0);
bool doTrain(int startStep,
OutputArray labels,
OutputArray probs,
OutputArray likelihoods);
virtual void eStep();
virtual void mStep();
......@@ -617,27 +622,28 @@ protected:
void decomposeCovs();
void computeLogWeightDivDet();
void computeProbabilities(const cv::Mat& sample, int& label, cv::Mat* probs, float* likelihood) const;
void computeProbabilities(const Mat& sample, int& label, Mat* probs, float* likelihood) const;
// all inner matrices have type CV_32FC1
int nclusters;
int covMatType;
int startStep;
cv::Mat trainSamples;
cv::Mat trainProbs;
cv::Mat trainLikelihoods;
cv::Mat trainLabels;
cv::Mat trainCounts;
cv::Mat weights;
cv::Mat means;
std::vector<cv::Mat> covs;
std::vector<cv::Mat> covsEigenValues;
std::vector<cv::Mat> covsRotateMats;
std::vector<cv::Mat> invCovsEigenValues;
cv::Mat logWeightDivDet;
CV_PROP_RW int nclusters;
CV_PROP_RW int covMatType;
CV_PROP_RW int maxIters;
CV_PROP_RW double epsilon;
Mat trainSamples;
Mat trainProbs;
Mat trainLikelihoods;
Mat trainLabels;
Mat trainCounts;
CV_PROP Mat weights;
CV_PROP Mat means;
CV_PROP vector<Mat> covs;
vector<Mat> covsEigenValues;
vector<Mat> covsRotateMats;
vector<Mat> invCovsEigenValues;
Mat logWeightDivDet;
};
} // namespace cv
......
This diff is collapsed.
......@@ -320,6 +320,30 @@ void CV_KNearestTest::run( int /*start_from*/ )
ts->set_failed_test_info( code );
}
class EM_Params
{
public:
EM_Params(int nclusters=10, int covMatType=EM::COV_MAT_DIAGONAL, int startStep=EM::START_AUTO_STEP,
const cv::TermCriteria& termCrit=cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 100, FLT_EPSILON),
const cv::Mat* probs=0, const cv::Mat* weights=0,
const cv::Mat* means=0, const std::vector<cv::Mat>* covs=0)
: nclusters(nclusters), covMatType(covMatType), startStep(startStep),
probs(probs), weights(weights), means(means), covs(covs), termCrit(termCrit)
{}
int nclusters;
int covMatType;
int startStep;
// all 4 following matrices should have type CV_32FC1
const cv::Mat* probs;
const cv::Mat* weights;
const cv::Mat* means;
const std::vector<cv::Mat>* covs;
cv::TermCriteria termCrit;
};
//--------------------------------------------------------------------------------------------
class CV_EMTest : public cvtest::BaseTest
{
......@@ -327,13 +351,13 @@ public:
CV_EMTest() {}
protected:
virtual void run( int start_from );
int runCase( int caseIndex, const cv::EM::Params& params,
int runCase( int caseIndex, const EM_Params& params,
const cv::Mat& trainData, const cv::Mat& trainLabels,
const cv::Mat& testData, const cv::Mat& testLabels,
const vector<int>& sizes);
};
int CV_EMTest::runCase( int caseIndex, const cv::EM::Params& params,
int CV_EMTest::runCase( int caseIndex, const EM_Params& params,
const cv::Mat& trainData, const cv::Mat& trainLabels,
const cv::Mat& testData, const cv::Mat& testLabels,
const vector<int>& sizes )
......@@ -343,8 +367,13 @@ int CV_EMTest::runCase( int caseIndex, const cv::EM::Params& params,
cv::Mat labels;
float err;
cv::EM em;
em.train( trainData, Mat(), params, &labels );
cv::EM em(params.nclusters, params.covMatType, params.termCrit);
if( params.startStep == EM::START_AUTO_STEP )
em.train( trainData, labels );
else if( params.startStep == EM::START_E_STEP )
em.trainE( trainData, *params.means, *params.covs, *params.weights, labels );
else if( params.startStep == EM::START_M_STEP )
em.trainM( trainData, *params.probs, labels );
// check train error
if( !calcErr( labels, trainLabels, sizes, err , false ) )
......@@ -363,7 +392,7 @@ int CV_EMTest::runCase( int caseIndex, const cv::EM::Params& params,
for( int i = 0; i < testData.rows; i++ )
{
Mat sample = testData.row(i);
labels.at<int>(i,0) = (int)em.predict( sample, 0 );
labels.at<int>(i,0) = (int)em.predict( sample, noArray() );
}
if( !calcErr( labels, testLabels, sizes, err, false ) )
{
......@@ -398,7 +427,7 @@ void CV_EMTest::run( int /*start_from*/ )
Mat testData( pointsCount, 2, CV_32FC1 ), testLabels;
generateData( testData, testLabels, sizes, means, covs, CV_32SC1 );
cv::EM::Params params;
EM_Params params;
params.nclusters = 3;
Mat probs(trainData.rows, params.nclusters, CV_32FC1, cv::Scalar(1));
params.probs = &probs;
......@@ -474,19 +503,16 @@ protected:
virtual void run( int /*start_from*/ )
{
int code = cvtest::TS::OK;
cv::EM em;
cv::EM em(2);
Mat samples = Mat(3,1,CV_32F);
samples.at<float>(0,0) = 1;
samples.at<float>(1,0) = 2;
samples.at<float>(2,0) = 3;
cv::EM::Params params;
params.nclusters = 2;
Mat labels;
em.train(samples, Mat(), params, &labels);
em.train(samples, labels);
Mat firstResult(samples.rows, 1, CV_32FC1);
for( int i = 0; i < samples.rows; i++)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment