1261 lines
28 KiB
C++
1261 lines
28 KiB
C++
#include <mex.h>
|
||
#include <mat.h>
|
||
#include <iostream>
|
||
#include <algorithm>
|
||
#include <vector>
|
||
#include <string>
|
||
#include <unordered_set>
|
||
#include <ctime>
|
||
#include <math.h>
|
||
#include <cassert>
|
||
#include <fstream>
|
||
#include <string.h>
|
||
#include <queue>
|
||
using std::cout;
|
||
using std::endl;
|
||
using namespace std;
|
||
#define M_PI 3.1415926535897932384626433832795
|
||
|
||
|
||
class KMeans
|
||
{
|
||
public:
|
||
enum InitMode
|
||
{
|
||
InitRandom,
|
||
InitManual,
|
||
InitUniform,
|
||
};
|
||
|
||
KMeans(int dimNum = 1, int clusterNum = 1);
|
||
~KMeans();
|
||
|
||
void SetMean(int i, const double* u) { memcpy(m_means[i], u, sizeof(double) * m_dimNum); }
|
||
void SetInitMode(int i) { m_initMode = i; }
|
||
void SetMaxIterNum(int i) { m_maxIterNum = i; }
|
||
void SetEndError(double f) { m_endError = f; }
|
||
|
||
double* GetMean(int i) { return m_means[i]; }
|
||
int GetInitMode() { return m_initMode; }
|
||
int GetMaxIterNum() { return m_maxIterNum; }
|
||
double GetEndError() { return m_endError; }
|
||
|
||
|
||
/* SampleFile: <size><dim><data>...
|
||
LabelFile: <size><label>...
|
||
*/
|
||
void Cluster(const char* sampleFileName, const char* labelFileName);
|
||
void Init(std::ifstream& sampleFile);
|
||
void Init(double* data, int N);
|
||
void Cluster(double* data, int N, int* Label);
|
||
friend std::ostream& operator<<(std::ostream& out, KMeans& kmeans);
|
||
|
||
private:
|
||
int m_dimNum;
|
||
int m_clusterNum;
|
||
double** m_means;
|
||
|
||
int m_initMode;
|
||
int m_maxIterNum; // The stopping criterion regarding the number of iterations
|
||
double m_endError; // The stopping criterion regarding the error
|
||
|
||
double GetLabel(const double* x, int* label);
|
||
double CalcDistance(const double* x, const double* u, int dimNum);
|
||
};
|
||
|
||
KMeans::KMeans(int dimNum, int clusterNum)
|
||
{
|
||
m_dimNum = dimNum;
|
||
m_clusterNum = clusterNum;
|
||
|
||
m_means = new double* [m_clusterNum];
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
m_means[i] = new double[m_dimNum];
|
||
memset(m_means[i], 0, sizeof(double) * m_dimNum);
|
||
}
|
||
|
||
m_initMode = InitRandom;
|
||
m_maxIterNum = 100;
|
||
m_endError = 0.001;
|
||
}
|
||
|
||
KMeans::~KMeans()
|
||
{
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
delete[] m_means[i];
|
||
}
|
||
delete[] m_means;
|
||
}
|
||
|
||
void KMeans::Cluster(const char* sampleFileName, const char* labelFileName)
|
||
{
|
||
// Check the sample file
|
||
ifstream sampleFile(sampleFileName, ios_base::binary);
|
||
assert(sampleFile);
|
||
|
||
int size = 0;
|
||
int dim = 0;
|
||
sampleFile.read((char*)&size, sizeof(int));
|
||
sampleFile.read((char*)&dim, sizeof(int));
|
||
assert(size >= m_clusterNum);
|
||
assert(dim == m_dimNum);
|
||
|
||
// Initialize model
|
||
Init(sampleFile);
|
||
|
||
// Recursion
|
||
double* x = new double[m_dimNum]; // Sample data
|
||
int label = -1; // Class index
|
||
double iterNum = 0;
|
||
double lastCost = 0;
|
||
double currCost = 0;
|
||
int unchanged = 0;
|
||
bool loop = true;
|
||
int* counts = new int[m_clusterNum];
|
||
double** next_means = new double* [m_clusterNum]; // New model for reestimation
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
next_means[i] = new double[m_dimNum];
|
||
}
|
||
|
||
while (loop)
|
||
{
|
||
memset(counts, 0, sizeof(int) * m_clusterNum);
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
memset(next_means[i], 0, sizeof(double) * m_dimNum);
|
||
}
|
||
|
||
lastCost = currCost;
|
||
currCost = 0;
|
||
|
||
sampleFile.clear();
|
||
sampleFile.seekg(sizeof(int) * 2, ios_base::beg);
|
||
|
||
// Classification
|
||
for (int i = 0; i < size; i++)
|
||
{
|
||
sampleFile.read((char*)x, sizeof(double) * m_dimNum);
|
||
currCost += GetLabel(x, &label);
|
||
|
||
counts[label]++;
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
next_means[label][d] += x[d];
|
||
}
|
||
}
|
||
currCost /= size;
|
||
|
||
// Reestimation
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
if (counts[i] > 0)
|
||
{
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
next_means[i][d] /= counts[i];
|
||
}
|
||
memcpy(m_means[i], next_means[i], sizeof(double) * m_dimNum);
|
||
}
|
||
}
|
||
|
||
// Terminal conditions
|
||
iterNum++;
|
||
if (fabs(lastCost - currCost) < m_endError * lastCost)
|
||
{
|
||
unchanged++;
|
||
}
|
||
if (iterNum >= m_maxIterNum || unchanged >= 3)
|
||
{
|
||
loop = false;
|
||
}
|
||
//DEBUG
|
||
//cout << "Iter: " << iterNum << ", Average Cost: " << currCost << endl;
|
||
}
|
||
|
||
// Output the label file
|
||
ofstream labelFile(labelFileName, ios_base::binary);
|
||
assert(labelFile);
|
||
|
||
labelFile.write((char*)&size, sizeof(int));
|
||
sampleFile.clear();
|
||
sampleFile.seekg(sizeof(int) * 2, ios_base::beg);
|
||
|
||
for (int i = 0; i < size; i++)
|
||
{
|
||
sampleFile.read((char*)x, sizeof(double) * m_dimNum);
|
||
GetLabel(x, &label);
|
||
labelFile.write((char*)&label, sizeof(int));
|
||
}
|
||
|
||
sampleFile.close();
|
||
labelFile.close();
|
||
|
||
delete[] counts;
|
||
delete[] x;
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
delete[] next_means[i];
|
||
}
|
||
delete[] next_means;
|
||
}
|
||
|
||
//
|
||
void KMeans::Cluster(double* data, int N, int* Label)
|
||
{
|
||
int size = 0;
|
||
size = N;
|
||
|
||
assert(size >= m_clusterNum);
|
||
|
||
// Initialize model
|
||
Init(data, N);
|
||
|
||
// Recursion
|
||
double* x = new double[m_dimNum]; // Sample data
|
||
int label = -1; // Class index
|
||
double iterNum = 0;
|
||
double lastCost = 0;
|
||
double currCost = 0;
|
||
int unchanged = 0;
|
||
bool loop = true;
|
||
int* counts = new int[m_clusterNum];
|
||
double** next_means = new double* [m_clusterNum]; // New model for reestimation
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
next_means[i] = new double[m_dimNum];
|
||
}
|
||
|
||
while (loop)
|
||
{
|
||
memset(counts, 0, sizeof(int) * m_clusterNum);
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
memset(next_means[i], 0, sizeof(double) * m_dimNum);
|
||
}
|
||
|
||
lastCost = currCost;
|
||
currCost = 0;
|
||
|
||
// Classification
|
||
for (int i = 0; i < size; i++)
|
||
{
|
||
for (int j = 0; j < m_dimNum; j++)
|
||
x[j] = data[i * m_dimNum + j];
|
||
|
||
currCost += GetLabel(x, &label);
|
||
|
||
counts[label]++;
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
next_means[label][d] += x[d];
|
||
}
|
||
}
|
||
currCost /= size;
|
||
|
||
// Reestimation
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
if (counts[i] > 0)
|
||
{
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
next_means[i][d] /= counts[i];
|
||
}
|
||
memcpy(m_means[i], next_means[i], sizeof(double) * m_dimNum);
|
||
}
|
||
}
|
||
|
||
// Terminal conditions
|
||
iterNum++;
|
||
if (fabs(lastCost - currCost) < m_endError * lastCost)
|
||
{
|
||
unchanged++;
|
||
}
|
||
if (iterNum >= m_maxIterNum || unchanged >= 3)
|
||
{
|
||
loop = false;
|
||
}
|
||
|
||
//DEBUG
|
||
//cout << "Iter: " << iterNum << ", Average Cost: " << currCost << endl;
|
||
}
|
||
|
||
// Output the label file
|
||
for (int i = 0; i < size; i++)
|
||
{
|
||
for (int j = 0; j < m_dimNum; j++)
|
||
x[j] = data[i * m_dimNum + j];
|
||
GetLabel(x, &label);
|
||
Label[i] = label;
|
||
}
|
||
delete[] counts;
|
||
delete[] x;
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
delete[] next_means[i];
|
||
}
|
||
delete[] next_means;
|
||
}
|
||
|
||
void KMeans::Init(double* data, int N)
|
||
{
|
||
int size = N;
|
||
|
||
if (m_initMode == InitRandom)
|
||
{
|
||
int inteval = size / m_clusterNum;
|
||
double* sample = new double[m_dimNum];
|
||
|
||
// Seed the random-number generator with current time
|
||
srand((unsigned)time(NULL));
|
||
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
int select = inteval * i + (inteval - 1) * rand() / RAND_MAX;
|
||
for (int j = 0; j < m_dimNum; j++)
|
||
sample[j] = data[select * m_dimNum + j];
|
||
memcpy(m_means[i], sample, sizeof(double) * m_dimNum);
|
||
}
|
||
|
||
delete[] sample;
|
||
}
|
||
else if (m_initMode == InitUniform)
|
||
{
|
||
double* sample = new double[m_dimNum];
|
||
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
int select = i * size / m_clusterNum;
|
||
for (int j = 0; j < m_dimNum; j++)
|
||
sample[j] = data[select * m_dimNum + j];
|
||
memcpy(m_means[i], sample, sizeof(double) * m_dimNum);
|
||
}
|
||
|
||
delete[] sample;
|
||
}
|
||
else if (m_initMode == InitManual)
|
||
{
|
||
// Do nothing
|
||
}
|
||
}
|
||
|
||
void KMeans::Init(ifstream& sampleFile)
|
||
{
|
||
int size = 0;
|
||
sampleFile.seekg(0, ios_base::beg);
|
||
sampleFile.read((char*)&size, sizeof(int));
|
||
|
||
if (m_initMode == InitRandom)
|
||
{
|
||
int inteval = size / m_clusterNum;
|
||
double* sample = new double[m_dimNum];
|
||
|
||
// Seed the random-number generator with current time
|
||
srand((unsigned)time(NULL));
|
||
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
int select = inteval * i + (inteval - 1) * rand() / RAND_MAX;
|
||
int offset = sizeof(int) * 2 + select * sizeof(double) * m_dimNum;
|
||
|
||
sampleFile.seekg(offset, ios_base::beg);
|
||
sampleFile.read((char*)sample, sizeof(double) * m_dimNum);
|
||
memcpy(m_means[i], sample, sizeof(double) * m_dimNum);
|
||
}
|
||
|
||
delete[] sample;
|
||
}
|
||
else if (m_initMode == InitUniform)
|
||
{
|
||
double* sample = new double[m_dimNum];
|
||
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
int select = i * size / m_clusterNum;
|
||
int offset = sizeof(int) * 2 + select * sizeof(double) * m_dimNum;
|
||
|
||
sampleFile.seekg(offset, ios_base::beg);
|
||
sampleFile.read((char*)sample, sizeof(double) * m_dimNum);
|
||
memcpy(m_means[i], sample, sizeof(double) * m_dimNum);
|
||
}
|
||
|
||
delete[] sample;
|
||
}
|
||
else if (m_initMode == InitManual)
|
||
{
|
||
// Do nothing
|
||
}
|
||
}
|
||
|
||
double KMeans::GetLabel(const double* sample, int* label)
|
||
{
|
||
double dist = -1;
|
||
for (int i = 0; i < m_clusterNum; i++)
|
||
{
|
||
double temp = CalcDistance(sample, m_means[i], m_dimNum);
|
||
if (temp < dist || dist == -1)
|
||
{
|
||
dist = temp;
|
||
*label = i;
|
||
}
|
||
}
|
||
return dist;
|
||
}
|
||
|
||
double KMeans::CalcDistance(const double* x, const double* u, int dimNum)
|
||
{
|
||
double temp = 0;
|
||
for (int d = 0; d < dimNum; d++)
|
||
{
|
||
temp += (x[d] - u[d]) * (x[d] - u[d]);
|
||
}
|
||
return sqrt(temp);
|
||
}
|
||
|
||
ostream& operator<<(ostream& out, KMeans& kmeans)
|
||
{
|
||
out << "<KMeans>" << endl;
|
||
out << "<DimNum> " << kmeans.m_dimNum << " </DimNum>" << endl;
|
||
out << "<ClusterNum> " << kmeans.m_clusterNum << " </CluterNum>" << endl;
|
||
|
||
out << "<Mean>" << endl;
|
||
for (int i = 0; i < kmeans.m_clusterNum; i++)
|
||
{
|
||
for (int d = 0; d < kmeans.m_dimNum; d++)
|
||
{
|
||
out << kmeans.m_means[i][d] << " ";
|
||
}
|
||
out << endl;
|
||
}
|
||
out << "</Mean>" << endl;
|
||
|
||
out << "</KMeans>" << endl;
|
||
return out;
|
||
}
|
||
|
||
class GMM
|
||
{
|
||
public:
|
||
GMM(int dimNum = 1, int mixNum = 1);
|
||
~GMM();
|
||
|
||
void Copy(GMM* gmm);
|
||
|
||
void SetMaxIterNum(int i) { m_maxIterNum = i; }
|
||
void SetEndError(double f) { m_endError = f; }
|
||
|
||
int GetDimNum() { return m_dimNum; }
|
||
int GetMixNum() { return m_mixNum; }
|
||
int GetMaxIterNum() { return m_maxIterNum; }
|
||
double GetEndError() { return m_endError; }
|
||
|
||
double& Prior(int i) { return m_priors[i]; }
|
||
double* Mean(int i) { return m_means[i]; }
|
||
double* Variance(int i) { return m_vars[i]; }
|
||
|
||
void setPrior(int i, double val) { m_priors[i] = val; }
|
||
void setMean(int i, double* val) { for (int j = 0;j < m_dimNum;j++) m_means[i][j] = val[j]; }
|
||
void setVariance(int i, double* val) { for (int j = 0;j < m_dimNum;j++) m_vars[i][j] = val[j]; }
|
||
|
||
double GetProbability(const double* sample);
|
||
|
||
/* SampleFile: <size><dim><data>...*/
|
||
void Init(const char* sampleFileName);
|
||
void Train(const char* sampleFileName);
|
||
void Init(double* data, int N);
|
||
void Train(double* data, int N);
|
||
|
||
void DumpSampleFile(const char* fileName);
|
||
|
||
friend std::ostream& operator<<(std::ostream& out, GMM& gmm);
|
||
friend std::istream& operator>>(std::istream& in, GMM& gmm);
|
||
|
||
private:
|
||
int m_dimNum; // <20><><EFBFBD><EFBFBD>ά<EFBFBD><CEAC>
|
||
int m_mixNum; // Gaussian<61><6E>Ŀ
|
||
double* m_priors; // GaussianȨ<6E><C8A8>
|
||
double** m_means; // Gaussian<61><6E>ֵ
|
||
double** m_vars; // Gaussian<61><6E><EFBFBD><EFBFBD>
|
||
|
||
// A minimum variance is required. Now, it is the overall variance * 0.01.
|
||
double* m_minVars;
|
||
int m_maxIterNum; // The stopping criterion regarding the number of iterations
|
||
double m_endError; // The stopping criterion regarding the error
|
||
|
||
private:
|
||
// Return the "j"th pdf, p(x|j).
|
||
double GetProbability(const double* x, int j);
|
||
void Allocate();
|
||
void Dispose();
|
||
};
|
||
GMM::GMM(int dimNum, int mixNum)
|
||
{
|
||
m_dimNum = dimNum;
|
||
m_mixNum = mixNum;
|
||
|
||
m_maxIterNum = 100;
|
||
m_endError = 0.001;
|
||
|
||
Allocate();
|
||
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
m_priors[i] = 1.0 / m_mixNum;
|
||
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
m_means[i][d] = 0;
|
||
m_vars[i][d] = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
GMM::~GMM()
|
||
{
|
||
Dispose();
|
||
}
|
||
|
||
void GMM::Allocate()
|
||
{
|
||
m_priors = new double[m_mixNum];
|
||
m_means = new double* [m_mixNum];
|
||
m_vars = new double* [m_mixNum];
|
||
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
m_means[i] = new double[m_dimNum];
|
||
m_vars[i] = new double[m_dimNum];
|
||
}
|
||
|
||
m_minVars = new double[m_dimNum];
|
||
}
|
||
|
||
void GMM::Dispose()
|
||
{
|
||
delete[] m_priors;
|
||
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
delete[] m_means[i];
|
||
delete[] m_vars[i];
|
||
}
|
||
delete[] m_means;
|
||
delete[] m_vars;
|
||
|
||
delete[] m_minVars;
|
||
}
|
||
|
||
void GMM::Copy(GMM* gmm)
|
||
{
|
||
assert(m_mixNum == gmm->m_mixNum && m_dimNum == gmm->m_dimNum);
|
||
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
m_priors[i] = gmm->Prior(i);
|
||
memcpy(m_means[i], gmm->Mean(i), sizeof(double) * m_dimNum);
|
||
memcpy(m_vars[i], gmm->Variance(i), sizeof(double) * m_dimNum);
|
||
}
|
||
memcpy(m_minVars, gmm->m_minVars, sizeof(double) * m_dimNum);
|
||
}
|
||
|
||
double GMM::GetProbability(const double* sample)
|
||
{
|
||
double p = 0;
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
p += m_priors[i] * GetProbability(sample, i);
|
||
}
|
||
return p;
|
||
}
|
||
|
||
double GMM::GetProbability(const double* x, int j)
|
||
{
|
||
double p = 1;
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
p *= 1 / sqrt(2 * M_PI * m_vars[j][d]);
|
||
p *= exp(-0.5 * (x[d] - m_means[j][d]) * (x[d] - m_means[j][d]) / m_vars[j][d]);
|
||
}
|
||
return p;
|
||
}
|
||
|
||
void GMM::Train(const char* sampleFileName)
|
||
{
|
||
//DumpSampleFile(sampleFileName);
|
||
Init(sampleFileName);
|
||
|
||
ifstream sampleFile(sampleFileName, ios_base::binary);
|
||
assert(sampleFile);
|
||
|
||
int size = 0;
|
||
sampleFile.seekg(0, ios_base::beg);
|
||
sampleFile.read((char*)&size, sizeof(int));
|
||
|
||
// Reestimation
|
||
bool loop = true;
|
||
double iterNum = 0;
|
||
double lastL = 0;
|
||
double currL = 0;
|
||
int unchanged = 0;
|
||
double* x = new double[m_dimNum]; // Sample data
|
||
double* next_priors = new double[m_mixNum];
|
||
double** next_vars = new double* [m_mixNum];
|
||
double** next_means = new double* [m_mixNum];
|
||
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
next_means[i] = new double[m_dimNum];
|
||
next_vars[i] = new double[m_dimNum];
|
||
}
|
||
|
||
while (loop)
|
||
{
|
||
// Clear buffer for reestimation
|
||
memset(next_priors, 0, sizeof(double) * m_mixNum);
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
memset(next_vars[i], 0, sizeof(double) * m_dimNum);
|
||
memset(next_means[i], 0, sizeof(double) * m_dimNum);
|
||
}
|
||
|
||
lastL = currL;
|
||
currL = 0;
|
||
|
||
// Predict
|
||
sampleFile.seekg(2 * sizeof(int), ios_base::beg);
|
||
for (int k = 0; k < size; k++)
|
||
{
|
||
sampleFile.read((char*)x, sizeof(double) * m_dimNum);
|
||
double p = GetProbability(x);
|
||
|
||
for (int j = 0; j < m_mixNum; j++)
|
||
{
|
||
double pj = GetProbability(x, j) * m_priors[j] / p;
|
||
next_priors[j] += pj;
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
next_means[j][d] += pj * x[d];
|
||
next_vars[j][d] += pj * x[d] * x[d];
|
||
}
|
||
}
|
||
currL += (p > 1E-20) ? log10(p) : -20;
|
||
}
|
||
currL /= size;
|
||
|
||
// Reestimation: generate new priors, means and variances.
|
||
for (int j = 0; j < m_mixNum; j++)
|
||
{
|
||
m_priors[j] = next_priors[j] / size;
|
||
|
||
if (m_priors[j] > 0)
|
||
{
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
m_means[j][d] = next_means[j][d] / next_priors[j];
|
||
m_vars[j][d] = next_vars[j][d] / next_priors[j] - m_means[j][d] * m_means[j][d];
|
||
if (m_vars[j][d] < m_minVars[d])
|
||
{
|
||
m_vars[j][d] = m_minVars[d];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Terminal conditions
|
||
iterNum++;
|
||
if (fabs(currL - lastL) < m_endError * fabs(lastL))
|
||
{
|
||
unchanged++;
|
||
}
|
||
if (iterNum >= m_maxIterNum || unchanged >= 3)
|
||
{
|
||
loop = false;
|
||
}
|
||
//--- Debug ---
|
||
//cout << "Iter: " << iterNum << ", Average Log-Probability: " << currL << endl;
|
||
}
|
||
|
||
sampleFile.close();
|
||
delete[] next_priors;
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
delete[] next_means[i];
|
||
delete[] next_vars[i];
|
||
}
|
||
delete[] next_means;
|
||
delete[] next_vars;
|
||
delete[] x;
|
||
}
|
||
|
||
void GMM::Train(double* data, int N)
|
||
{
|
||
Init(data, N);
|
||
|
||
int size = N;
|
||
|
||
// Reestimation
|
||
bool loop = true;
|
||
double iterNum = 0;
|
||
double lastL = 0;
|
||
double currL = 0;
|
||
int unchanged = 0;
|
||
double* x = new double[m_dimNum]; // Sample data
|
||
double* next_priors = new double[m_mixNum];
|
||
double** next_vars = new double* [m_mixNum];
|
||
double** next_means = new double* [m_mixNum];
|
||
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
next_means[i] = new double[m_dimNum];
|
||
next_vars[i] = new double[m_dimNum];
|
||
}
|
||
|
||
while (loop)
|
||
{
|
||
// Clear buffer for reestimation
|
||
memset(next_priors, 0, sizeof(double) * m_mixNum);
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
memset(next_vars[i], 0, sizeof(double) * m_dimNum);
|
||
memset(next_means[i], 0, sizeof(double) * m_dimNum);
|
||
}
|
||
|
||
lastL = currL;
|
||
currL = 0;
|
||
|
||
// Predict
|
||
for (int k = 0; k < size; k++)
|
||
{
|
||
for (int j = 0;j < m_dimNum;j++)
|
||
x[j] = data[k * m_dimNum + j];
|
||
double p = GetProbability(x);
|
||
|
||
for (int j = 0; j < m_mixNum; j++)
|
||
{
|
||
double pj = GetProbability(x, j) * m_priors[j] / p;
|
||
|
||
next_priors[j] += pj;
|
||
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
next_means[j][d] += pj * x[d];
|
||
next_vars[j][d] += pj * x[d] * x[d];
|
||
}
|
||
}
|
||
|
||
currL += (p > 1E-20) ? log10(p) : -20;
|
||
}
|
||
currL /= size;
|
||
|
||
// Reestimation: generate new priors, means and variances.
|
||
for (int j = 0; j < m_mixNum; j++)
|
||
{
|
||
m_priors[j] = next_priors[j] / size;
|
||
|
||
if (m_priors[j] > 0)
|
||
{
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
m_means[j][d] = next_means[j][d] / next_priors[j];
|
||
m_vars[j][d] = next_vars[j][d] / next_priors[j] - m_means[j][d] * m_means[j][d];
|
||
if (m_vars[j][d] < m_minVars[d])
|
||
{
|
||
m_vars[j][d] = m_minVars[d];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Terminal conditions
|
||
iterNum++;
|
||
if (fabs(currL - lastL) < m_endError * fabs(lastL))
|
||
{
|
||
unchanged++;
|
||
}
|
||
if (iterNum >= m_maxIterNum || unchanged >= 3)
|
||
{
|
||
loop = false;
|
||
}
|
||
|
||
//--- Debug ---
|
||
//cout << "Iter: " << iterNum << ", Average Log-Probability: " << currL << endl;
|
||
}
|
||
delete[] next_priors;
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
delete[] next_means[i];
|
||
delete[] next_vars[i];
|
||
}
|
||
delete[] next_means;
|
||
delete[] next_vars;
|
||
delete[] x;
|
||
}
|
||
|
||
void GMM::Init(double* data, int N)
|
||
{
|
||
const double MIN_VAR = 1E-10;
|
||
|
||
KMeans* kmeans = new KMeans(m_dimNum, m_mixNum);
|
||
kmeans->SetInitMode(KMeans::InitUniform);
|
||
int* Label;
|
||
Label = new int[N];
|
||
kmeans->Cluster(data, N, Label);
|
||
|
||
int* counts = new int[m_mixNum];
|
||
double* overMeans = new double[m_dimNum]; // Overall mean of training data
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
counts[i] = 0;
|
||
m_priors[i] = 0;
|
||
memcpy(m_means[i], kmeans->GetMean(i), sizeof(double) * m_dimNum);
|
||
memset(m_vars[i], 0, sizeof(double) * m_dimNum);
|
||
}
|
||
memset(overMeans, 0, sizeof(double) * m_dimNum);
|
||
memset(m_minVars, 0, sizeof(double) * m_dimNum);
|
||
|
||
int size = 0;
|
||
size = N;
|
||
|
||
double* x = new double[m_dimNum];
|
||
int label = -1;
|
||
|
||
for (int i = 0; i < size; i++)
|
||
{
|
||
for (int j = 0;j < m_dimNum;j++)
|
||
x[j] = data[i * m_dimNum + j];
|
||
label = Label[i];
|
||
|
||
// Count each Gaussian
|
||
counts[label]++;
|
||
double* m = kmeans->GetMean(label);
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
m_vars[label][d] += (x[d] - m[d]) * (x[d] - m[d]);
|
||
}
|
||
|
||
// Count the overall mean and variance.
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
overMeans[d] += x[d];
|
||
m_minVars[d] += x[d] * x[d];
|
||
}
|
||
}
|
||
|
||
// Compute the overall variance (* 0.01) as the minimum variance.
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
overMeans[d] /= size;
|
||
m_minVars[d] = max(MIN_VAR, 0.01 * (m_minVars[d] / size - overMeans[d] * overMeans[d]));
|
||
}
|
||
|
||
// Initialize each Gaussian.
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
m_priors[i] = 1.0 * counts[i] / size;
|
||
|
||
if (m_priors[i] > 0)
|
||
{
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
m_vars[i][d] = m_vars[i][d] / counts[i];
|
||
|
||
// A minimum variance for each dimension is required.
|
||
if (m_vars[i][d] < m_minVars[d])
|
||
{
|
||
m_vars[i][d] = m_minVars[d];
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
memcpy(m_vars[i], m_minVars, sizeof(double) * m_dimNum);
|
||
cout << "[WARNING] Gaussian " << i << " of GMM is not used!\n";
|
||
}
|
||
}
|
||
delete kmeans;
|
||
delete[] x;
|
||
delete[] counts;
|
||
delete[] overMeans;
|
||
delete[] Label;
|
||
|
||
}
|
||
|
||
void GMM::Init(const char* sampleFileName)
|
||
{
|
||
const double MIN_VAR = 1E-10;
|
||
|
||
KMeans* kmeans = new KMeans(m_dimNum, m_mixNum);
|
||
kmeans->SetInitMode(KMeans::InitUniform);
|
||
kmeans->Cluster(sampleFileName, "gmm_init.tmp");
|
||
|
||
int* counts = new int[m_mixNum];
|
||
double* overMeans = new double[m_dimNum]; // Overall mean of training data
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
counts[i] = 0;
|
||
m_priors[i] = 0;
|
||
memcpy(m_means[i], kmeans->GetMean(i), sizeof(double) * m_dimNum);
|
||
memset(m_vars[i], 0, sizeof(double) * m_dimNum);
|
||
}
|
||
memset(overMeans, 0, sizeof(double) * m_dimNum);
|
||
memset(m_minVars, 0, sizeof(double) * m_dimNum);
|
||
|
||
// Open the sample and label file to initialize the model
|
||
ifstream sampleFile(sampleFileName, ios_base::binary);
|
||
assert(sampleFile);
|
||
|
||
ifstream labelFile("gmm_init.tmp", ios_base::binary);
|
||
assert(labelFile);
|
||
|
||
int size = 0;
|
||
sampleFile.read((char*)&size, sizeof(int));
|
||
sampleFile.seekg(2 * sizeof(int), ios_base::beg);
|
||
labelFile.seekg(sizeof(int), ios_base::beg);
|
||
|
||
double* x = new double[m_dimNum];
|
||
int label = -1;
|
||
|
||
for (int i = 0; i < size; i++)
|
||
{
|
||
sampleFile.read((char*)x, sizeof(double) * m_dimNum);
|
||
labelFile.read((char*)&label, sizeof(int));
|
||
|
||
// Count each Gaussian
|
||
counts[label]++;
|
||
double* m = kmeans->GetMean(label);
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
m_vars[label][d] += (x[d] - m[d]) * (x[d] - m[d]);
|
||
}
|
||
|
||
// Count the overall mean and variance.
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
overMeans[d] += x[d];
|
||
m_minVars[d] += x[d] * x[d];
|
||
}
|
||
}
|
||
|
||
// Compute the overall variance (* 0.01) as the minimum variance.
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
overMeans[d] /= size;
|
||
m_minVars[d] = max(MIN_VAR, 0.01 * (m_minVars[d] / size - overMeans[d] * overMeans[d]));
|
||
}
|
||
|
||
// Initialize each Gaussian.
|
||
for (int i = 0; i < m_mixNum; i++)
|
||
{
|
||
m_priors[i] = 1.0 * counts[i] / size;
|
||
|
||
if (m_priors[i] > 0)
|
||
{
|
||
for (int d = 0; d < m_dimNum; d++)
|
||
{
|
||
m_vars[i][d] = m_vars[i][d] / counts[i];
|
||
|
||
// A minimum variance for each dimension is required.
|
||
if (m_vars[i][d] < m_minVars[d])
|
||
{
|
||
m_vars[i][d] = m_minVars[d];
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
memcpy(m_vars[i], m_minVars, sizeof(double) * m_dimNum);
|
||
cout << "[WARNING] Gaussian " << i << " of GMM is not used!\n";
|
||
}
|
||
}
|
||
|
||
delete kmeans;
|
||
delete[] x;
|
||
delete[] counts;
|
||
delete[] overMeans;
|
||
|
||
sampleFile.close();
|
||
labelFile.close();
|
||
}
|
||
|
||
void GMM::DumpSampleFile(const char* fileName)
|
||
{
|
||
ifstream sampleFile(fileName, ios_base::binary);
|
||
assert(sampleFile);
|
||
|
||
int size = 0;
|
||
sampleFile.read((char*)&size, sizeof(int));
|
||
cout << size << endl;
|
||
|
||
int dim = 0;
|
||
sampleFile.read((char*)&dim, sizeof(int));
|
||
cout << dim << endl;
|
||
|
||
double* f = new double[dim];
|
||
for (int i = 0; i < size; i++)
|
||
{
|
||
sampleFile.read((char*)f, sizeof(double) * dim);
|
||
|
||
cout << i << ":";
|
||
for (int j = 0; j < dim; j++)
|
||
{
|
||
cout << " " << f[j];
|
||
}
|
||
cout << endl;
|
||
}
|
||
|
||
delete[] f;
|
||
sampleFile.close();
|
||
}
|
||
|
||
ostream& operator<<(ostream& out, GMM& gmm)
|
||
{
|
||
out << "<GMM>" << endl;
|
||
out << "<DimNum> " << gmm.m_dimNum << " </DimNum>" << endl;
|
||
out << "<MixNum> " << gmm.m_mixNum << " </MixNum>" << endl;
|
||
|
||
out << "<Prior> ";
|
||
for (int i = 0; i < gmm.m_mixNum; i++)
|
||
{
|
||
out << gmm.m_priors[i] << " ";
|
||
}
|
||
out << "</Prior>" << endl;
|
||
|
||
out << "<Mean>" << endl;
|
||
for (int i = 0; i < gmm.m_mixNum; i++)
|
||
{
|
||
for (int d = 0; d < gmm.m_dimNum; d++)
|
||
{
|
||
out << gmm.m_means[i][d] << " ";
|
||
}
|
||
out << endl;
|
||
}
|
||
out << "</Mean>" << endl;
|
||
|
||
out << "<Variance>" << endl;
|
||
for (int i = 0; i < gmm.m_mixNum; i++)
|
||
{
|
||
for (int d = 0; d < gmm.m_dimNum; d++)
|
||
{
|
||
out << gmm.m_vars[i][d] << " ";
|
||
}
|
||
out << endl;
|
||
}
|
||
out << "</Variance>" << endl;
|
||
|
||
out << "</GMM>" << endl;
|
||
|
||
return out;
|
||
}
|
||
|
||
istream& operator>>(istream& in, GMM& gmm)
|
||
{
|
||
char label[50];
|
||
in >> label; // "<GMM>"
|
||
assert(strcmp(label, "<GMM>") == 0);
|
||
|
||
gmm.Dispose();
|
||
|
||
in >> label >> gmm.m_dimNum >> label; // "<DimNum>"
|
||
in >> label >> gmm.m_mixNum >> label; // "<MixNum>"
|
||
|
||
gmm.Allocate();
|
||
|
||
in >> label; // "<Prior>"
|
||
for (int i = 0; i < gmm.m_mixNum; i++)
|
||
{
|
||
in >> gmm.m_priors[i];
|
||
}
|
||
in >> label;
|
||
|
||
in >> label; // "<Mean>"
|
||
for (int i = 0; i < gmm.m_mixNum; i++)
|
||
{
|
||
for (int d = 0; d < gmm.m_dimNum; d++)
|
||
{
|
||
in >> gmm.m_means[i][d];
|
||
}
|
||
}
|
||
in >> label;
|
||
|
||
in >> label; // "<Variance>"
|
||
for (int i = 0; i < gmm.m_mixNum; i++)
|
||
{
|
||
for (int d = 0; d < gmm.m_dimNum; d++)
|
||
{
|
||
in >> gmm.m_vars[i][d];
|
||
}
|
||
}
|
||
in >> label;
|
||
|
||
in >> label; // "</GMM>"
|
||
return in;
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><D7BC>˹ģ<CBB9><C4A3>ѵ<EFBFBD><D1B5><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><CFB5>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϻ<EFBFBD><CFBA><EFBFBD>Yֵ<59><D6B5><EFBFBD><EFBFBD> */
|
||
struct cmpFunc {
|
||
bool operator()(const pair<double, double>& a, const pair<double, double>& b) { return a.first < b.first; }
|
||
};
|
||
void GMMToFactorEY(GMM& gmm, double binWidth, vector<double>& vYBin, vector<double>& vFactor, vector<double>& vEY) {
|
||
/* <20><>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߵ<EFBFBD>Ȩ<EFBFBD>أ<EFBFBD><D8A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD>˹<EFBFBD><CBB9><EFBFBD>ߣ<EFBFBD><DFA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ø<EFBFBD><C3B8><EFBFBD><EFBFBD>ܶ<EFBFBD> */
|
||
double zoomFactorSum = 0.0;
|
||
vEY.resize(vYBin.size());
|
||
// int topM = 2; // = (int)(vYBin.size() / 4);
|
||
int topM = (int)(vYBin.size() / 4);
|
||
if (topM < 1) topM = 1;
|
||
/* <20>ö<EFBFBD><C3B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD>ʽȡǰtopM<70><4D><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ų<EFBFBD><C5B2><EFBFBD>*/
|
||
priority_queue<pair<double, double>, vector<pair<double, double> >, cmpFunc> pqTopM;
|
||
|
||
for (int i = 0; i < vYBin.size(); ++i) {
|
||
double xVal = i * binWidth;
|
||
double probVal = gmm.GetProbability(&xVal);
|
||
vEY[i] = probVal;
|
||
pqTopM.push(make_pair(vYBin[i], probVal));
|
||
}
|
||
|
||
int realUsed = 1;
|
||
pair<double, double> topEle = pqTopM.top();
|
||
zoomFactorSum += topEle.first / topEle.second;
|
||
for (int i = 1; i < topM; ++i) {
|
||
topEle = pqTopM.top();
|
||
pqTopM.pop();
|
||
if (topEle.second > 0.05) { // <20><><EFBFBD>ʸ<EFBFBD><CAB8>ʳ<EFBFBD><CAB3><EFBFBD><EFBFBD>ض<EFBFBD>ֵ<EFBFBD>Ž<EFBFBD><C5BD>м<EFBFBD><D0BC><EFBFBD>
|
||
realUsed += 1;
|
||
zoomFactorSum += topEle.first / topEle.second;
|
||
}
|
||
}
|
||
|
||
double zoomFactor = zoomFactorSum / realUsed;
|
||
|
||
//zoomFactor = 0;
|
||
//for_each(vYBin.cbegin(), vYBin.cend(), [&](const double& val)->void { zoomFactor += val; });
|
||
|
||
for (int i = 0; i < vEY.size(); ++i) {
|
||
vEY[i] *= zoomFactor;
|
||
}
|
||
vFactor.clear();
|
||
vFactor.push_back(zoomFactor * gmm.Prior(0) / sqrt(2 * M_PI * *gmm.Variance(0)));
|
||
vFactor.push_back(*gmm.Mean(0));
|
||
vFactor.push_back(sqrt(2 * *gmm.Variance(0)));
|
||
vFactor.push_back(zoomFactor * gmm.Prior(1) / sqrt(2 * M_PI * *gmm.Variance(1)));
|
||
vFactor.push_back(*gmm.Mean(1));
|
||
vFactor.push_back(sqrt(2 * *gmm.Variance(1)));
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD> */
|
||
template <typename T>
|
||
T Average(vector<T>& vVal) {
|
||
T sumVal = T(0);
|
||
for (int i = 0; i < vVal.size(); ++i) {
|
||
sumVal += vVal[i];
|
||
}
|
||
return sumVal / vVal.size();
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD><EFBFBD>ľ<EFBFBD>ֵ */
|
||
template <typename T>
|
||
T SquareAverage(vector<T>& vVal) {
|
||
vector<T> vSquare(vVal.size());
|
||
for (int i = 0; i < vVal.size(); ++i) {
|
||
vSquare[i] = vVal[i] * vVal[i];
|
||
}
|
||
return Average(vSquare);
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>x<EFBFBD><78>y<EFBFBD><79><EFBFBD><EFBFBD><EFBFBD>ؾ<EFBFBD><D8BE><EFBFBD>, <20><><EFBFBD><EFBFBD>ά<EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||
double CorrelationDistance(vector<double>& vX, vector<double>& vY) {
|
||
double xMean = Average(vX);
|
||
transform(vX.cbegin(), vX.cend(), vX.begin(), [&](double val) { return val - xMean; });
|
||
double yMean = Average(vY);
|
||
transform(vY.cbegin(), vY.cend(), vY.begin(), [&](double val) { return val - yMean; });
|
||
|
||
vector<double> vXY(vX.size());
|
||
for (int i = 0; i < vXY.size(); ++i) {
|
||
vXY[i] = vX[i] * vY[i];
|
||
}
|
||
double uv = Average(vXY);
|
||
double uu = SquareAverage(vX);
|
||
double vv = SquareAverage(vY);
|
||
|
||
double dist = 1.0 - uv / sqrt(uu * vv);
|
||
return abs(dist);
|
||
}
|
||
|
||
/*
|
||
nlhs<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ(Number Left - hand side)<29><><EFBFBD>Ⱥ<EFBFBD><C8BA><EFBFBD><EFBFBD><EFBFBD>
|
||
plhs<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>(Point Left - hand side)<29><><EFBFBD>Ⱥ<EFBFBD><C8BA><EFBFBD><EFBFBD><EFBFBD>
|
||
nrhs<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ(Number Right - hand side)<29><><EFBFBD>Ⱥ<EFBFBD><C8BA>ұ<EFBFBD>
|
||
prhs<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>(Point Right - hand side)<29><><EFBFBD>Ⱥ<EFBFBD><C8BA>ұߡ<D2B1>Ҫע<D2AA><D7A2>prhs<68><73>const<73><74>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>飬<EFBFBD><E9A3AC><EFBFBD><EFBFBD><EFBFBD>ܸı<DCB8><C4B1><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>ݡ<EFBFBD>
|
||
*/
|
||
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) {
|
||
// cout << "GaussFit" << endl;
|
||
// cout << nlhs << '\t' << nrhs << endl;
|
||
if (nrhs != 2) {
|
||
cout << "2 arguments should be given for this function!" << endl;
|
||
return;
|
||
}
|
||
clock_t begin, finish;
|
||
begin = clock();
|
||
|
||
// <20><><EFBFBD><EFBFBD>x,y<><79><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><D0B5>ĺ<EFBFBD><C4BA><EFBFBD><EFBFBD>꣬<EFBFBD><EAA3AC>ΪGMM<4D><4D><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
vector<double> vPoint;
|
||
vector<double> vYBin;
|
||
vPoint.reserve(1000);
|
||
int rowNum = (int)mxGetM(prhs[0]);
|
||
int colNum = (int)mxGetN(prhs[0]);
|
||
|
||
int dataSize = rowNum * colNum;
|
||
vYBin.resize(dataSize);
|
||
double* pX = (double*)mxGetData(prhs[0]);
|
||
double* pY = (double*)mxGetData(prhs[1]);
|
||
|
||
for (int i = 0; i < dataSize; ++i) {
|
||
double x = pX[i];
|
||
double y = pY[i];
|
||
vYBin[i] = y;
|
||
vPoint.reserve(vPoint.size() + (int)y);
|
||
for (int j = 0; j < (int)y; ++j) {
|
||
vPoint.push_back(x);
|
||
}
|
||
}
|
||
|
||
// ѵ<><D1B5><EFBFBD><EFBFBD>˹ģ<CBB9><C4A3>
|
||
GMM gmm(1, 2); // 1ά<31><CEAC> 2<><32><EFBFBD><EFBFBD>˹ģ<CBB9><C4A3>
|
||
gmm.Train(vPoint.data(), (int)vPoint.size());
|
||
|
||
vector<double>vEY;
|
||
vector<double>vFactor;
|
||
|
||
GMMToFactorEY(gmm, 0.2, vYBin, vFactor, vEY);
|
||
double correlationDist = CorrelationDistance(vYBin, vEY);
|
||
|
||
/* д<><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||
if (nlhs > 0) { // b
|
||
mxArray* pWriteArray = NULL;
|
||
//<2F><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>rowNum*colNum<75>ľ<EFBFBD><C4BE><EFBFBD>
|
||
pWriteArray = mxCreateDoubleMatrix(1, 6, mxREAL);
|
||
memcpy((void*)(mxGetPr(pWriteArray)), (void*)vFactor.data(), sizeof(double) * 6);
|
||
plhs[0] = pWriteArray; // <20><>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||
}
|
||
if (nlhs > 1) { // r
|
||
mxArray* pWriteArray = NULL;
|
||
//<2F><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>rowNum*colNum<75>ľ<EFBFBD><C4BE><EFBFBD>
|
||
pWriteArray = mxCreateDoubleMatrix(1, 1, mxREAL);
|
||
memcpy((void*)(mxGetPr(pWriteArray)), (void*)&correlationDist, sizeof(double) * 1);
|
||
plhs[1] = pWriteArray; // <20><>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||
}
|
||
if (nlhs > 2) { // c
|
||
mxArray* pWriteArray = NULL;
|
||
//<2F><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>rowNum*colNum<75>ľ<EFBFBD><C4BE><EFBFBD>
|
||
pWriteArray = mxCreateDoubleMatrix(1, vEY.size(), mxREAL);
|
||
memcpy((void*)(mxGetPr(pWriteArray)), (void*)vEY.data(), sizeof(double) * vEY.size());
|
||
plhs[2] = pWriteArray; // <20><>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||
}
|
||
|
||
// cout << "Point size:" << vPoint.size() << endl;
|
||
|
||
finish = clock();
|
||
// cout << "Gauss Fit Total time: " << (double)(finish - begin) / CLOCKS_PER_SEC << " s" << endl;
|
||
} |