00001 #include "gmm.h"
00002
00003
00004 float Gaussian::density(const GMMFloatPnt& x) const {
00005
00006 cv::Mat p(NUM_GMM_DIMS, 1, CV_32F);
00007 cv::Mat pt(1, NUM_GMM_DIMS, CV_32F);
00008 float val;
00009
00010 for (unsigned int d = 0; d < NUM_GMM_DIMS; d++)
00011 p.at<float>(d, 0) = x[d] - mv[d];
00012 memcpy(pt.data, p.data, NUM_GMM_DIMS*sizeof(float));
00013 cv::Mat v(pt * imat * p);
00014
00015 val = (float) exp(-0.5 * v.at<float>(0, 0)) / prob_norm;
00016
00017 return val;
00018 }
00019
00027 float Gaussian::mahal(const GMMFloatPnt& x) const
00028 {
00029
00030
00031
00032 cv::Mat p(NUM_GMM_DIMS, 1, CV_32F);
00033 cv::Mat pt(1, NUM_GMM_DIMS, CV_32F);
00034
00035 for (unsigned int d = 0; d < NUM_GMM_DIMS; d++)
00036 p.at<float>(d, 0) = x[d] - mv[d];
00037 memcpy(pt.data, p.data, NUM_GMM_DIMS*sizeof(float));
00038 cv::Mat v(pt * imat * p);
00039 return v.at<float>(0, 0);
00040 }
00041
00042 void Gaussian::serialize(std::ofstream& fd) const {
00043 int num_dims = NUM_GMM_DIMS;
00044
00045 fd.write(reinterpret_cast<const char *>(&num_dims), sizeof(int));
00046
00047 for (int i = 0; i < NUM_GMM_DIMS; i++) {
00048 fd.write(reinterpret_cast<const char *>(&(mv[i])), sizeof(float));
00049 }
00050
00051 for (int d = 0; d < NUM_GMM_DIMS; d++) {
00052 for (int e = d; e < NUM_GMM_DIMS; e++) {
00053 fd.write(reinterpret_cast<const char *>(&(mat.at<float>(d, e))), sizeof(float));
00054 }
00055 }
00056 }
00057
00058
00059 void Gaussian::deserialize(std::ifstream& fd) {
00060 int num_dims;
00061
00062 fd.read(reinterpret_cast<char *>(&num_dims), sizeof(int));
00063
00064 if (num_dims != NUM_GMM_DIMS)
00065 throw "The number of dimensions for the Gaussian loaded is inconsistent with NUM_GMM_DIMS";
00066
00067 for (int i = 0; i < NUM_GMM_DIMS; i++) {
00068 fd.read(reinterpret_cast<char *>(&(mv[i])), sizeof(float));
00069 }
00070
00071 for (int d = 0; d < NUM_GMM_DIMS; d++) {
00072 for (int e = d; e < NUM_GMM_DIMS; e++) {
00073 fd.read(reinterpret_cast<char *>(&(mat.at<float>(d, e))), sizeof(float));
00074 mat.at<float>(e, d) = mat.at<float>(d, e);
00075 }
00076 }
00077
00078 imat = cv::Mat(mat.inv());
00079
00080
00081 adjustProbNorm();
00082 }
00083
00084
00085 int GMM::which_kernel(const GMMFloatPnt& x) const {
00086
00087
00088
00089 int maxk = 0;
00090 float maxprob = kernel[0].density(x);
00091 float prob;
00092
00093 for (int i = 1; i < nk; i++) {
00094 prob = kernel[i].density(x);
00095 if (maxprob < prob) {
00096 maxk = i;
00097 maxprob = prob;
00098 }
00099 }
00100
00101 return maxk;
00102 }
00103
00104
00105 double GMM::learn(const std::vector<GMMFloatPnt>& pts) {
00106
00107
00108
00109
00110
00111 GMMFloatPnt km;
00112 GMMSigmaVal ks;
00113 float N_k;
00114 float x, y, z;
00115 double likelihood;
00116 int curr_idx;
00117
00118 float weight[nk];
00119
00120
00121
00122 float **prob = new float*[nk];
00123
00124 for (int i = 0; i < nk; i++)
00125 prob[i] = new float[pts.size()];
00126 float *px = new float[pts.size()];
00127
00128
00129 for (unsigned int i = 0; i < pts.size(); i++) {
00130 px[i] = probability(pts[i]);
00131 }
00132
00133
00134 for (int k = 0; k < nk; k++) {
00135 weight[k] = 0.0;
00136
00137
00138 for (unsigned int i = 0; i < pts.size(); i++) {
00139
00140
00141 prob[k][i] = w[k] * kernel[k].density(pts[i]);
00142
00143
00144 if (px[i] > 0.0)
00145 prob[k][i] /= px[i];
00146 else
00147 prob[k][i] = 0.0;
00148
00149
00150 weight[k] += prob[k][i];
00151 }
00152
00153
00154 weight[k] /= (float) pts.size();
00155
00156
00157 N_k = pts.size() * weight[k];
00158
00159
00160 for (unsigned int d = 0; d < NUM_GMM_DIMS; d++)
00161 km[d] = 0.0;
00162 for (unsigned int s = 0; s < NUM_SIGMA_VALS; s++)
00163 ks[s] = 0.0;
00164
00165
00166 for (unsigned int i = 0; i < pts.size(); i++) {
00167
00168 for (unsigned int d = 0; d < NUM_GMM_DIMS; d++) {
00169 km[d] += prob[k][i] * pts[i][d];
00170 }
00171
00172
00173 curr_idx = 0;
00174 for (int d = 0; d < NUM_GMM_DIMS; d++) {
00175 for (int e = d; e < NUM_GMM_DIMS; e++) {
00176 ks[curr_idx] += prob[k][i] * pts[i][d] * pts[i][e];
00177 ++curr_idx;
00178 }
00179 }
00180 }
00181
00182
00183 for (int d = 0; d < NUM_GMM_DIMS; d++)
00184 km[d] /= N_k;
00185
00186
00187
00188 for (unsigned int s = 0; s < NUM_SIGMA_VALS; s++)
00189 ks[s] /= N_k;
00190 curr_idx = 0;
00191 for (int d = 0; d < NUM_GMM_DIMS; d++) {
00192 for (int e = d; e < NUM_GMM_DIMS; e++) {
00193 ks[curr_idx] -= km[d] * km[e];
00194 ++curr_idx;
00195 }
00196 }
00197
00198
00199 kernel[k].SetMean(km);
00200 kernel[k].SetSigma(ks);
00201 }
00202
00203
00204
00205 float sum = 0.0;
00206
00207 for (int k = 0; k < nk; k++)
00208 sum += weight[k];
00209 for (int k = 0; k < nk; k++) {
00210
00211
00212 w[k] = weight[k] / sum;
00213 }
00214
00215
00216 double loglikelihood = 0.0;
00217 for (unsigned int i = 0; i < pts.size(); i++) {
00218 likelihood = probability(pts[i]);
00219 loglikelihood += log(likelihood);
00220 }
00221 loglikelihood /= pts.size();
00222
00223 for (int i = 0; i < nk; i++)
00224 delete[] prob[i];
00225
00226 delete[] prob;
00227 delete[] px;
00228
00229 return loglikelihood;
00230 }
00231
00232
00233 double GMM::GmmEm(const std::vector<GMMFloatPnt>& pts) {
00234 double normloglikelihood = 0.0;
00235 double new_normloglikelihood = -std::numeric_limits<double>::max();
00236 double diff;
00237 int iteration = 0;
00238
00239 std::cout << "EM diff threshold: " << em_thresh << std::endl;
00240 do {
00241 iteration++;
00242
00243
00244 normloglikelihood = new_normloglikelihood;
00245
00246
00247 new_normloglikelihood = this->learn(pts);
00248 if (iteration == 1)
00249 diff = std::numeric_limits<double>::quiet_NaN();
00250 else
00251 diff = new_normloglikelihood - normloglikelihood;
00252
00253 std::cout << "Log likelihood: iter " <<
00254 boost::format("%3d : %+8.4f | %+8.4f") % iteration %
00255 new_normloglikelihood % diff << "\n";
00256
00257
00258
00259
00260
00261 } while(iteration <= min_iter ||
00262 (diff > em_thresh && iteration < max_iter));
00263
00264 if (iteration >= max_iter && new_normloglikelihood - normloglikelihood > em_thresh) {
00265 std::cout << "EM failed to converge after " << iteration << " iterations : "
00266 << new_normloglikelihood;
00267 }
00268
00269 return new_normloglikelihood;
00270 }
00271
00272
00273 void GMM::kmeansInit(const std::vector<GMMFloatPnt>& pts, const float sigma) {
00274
00275
00276 GMMFloatPnt temp_pnt;
00277
00278 const int NUM_RETRIES = 3;
00279 const int MAX_ITERS = 100;
00280 const float DIST_THRESH = 0.001;
00281
00282 cv::Mat bestlabels;
00283 cv::Mat clustercenters;
00284
00285 cv::Mat rgbmat(pts.size(), 1, CV_32FC(NUM_GMM_DIMS));
00286
00287
00288 for (int i = 0; i < rgbmat.rows; i++) {
00289 for (int d = 0; d < NUM_GMM_DIMS; d++)
00290 temp_pnt[d] = pts[i][d];
00291
00292 rgbmat.at<GMMFloatPnt>(i) = temp_pnt;
00293
00294
00295
00296
00297
00298
00299 }
00300
00301
00302
00303
00304
00305 if (rgbmat.rows < nk || nk == 0) {
00306
00307 alloc(rgbmat.rows);
00308 std::cout << "Reduced the number of kernels to " << nk << " because not enough data points available" << std::endl;
00309 }
00310
00311
00312 cv::TermCriteria termcrit(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, MAX_ITERS, 0.0001);
00313
00314
00315 kmeans(rgbmat, nk, bestlabels, termcrit, NUM_RETRIES, cv::KMEANS_RANDOM_CENTERS, clustercenters);
00316
00317
00318 float dist;
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 for (int i = 0; i < clustercenters.rows; i++) {
00374 for (int d = 0; d < NUM_GMM_DIMS; d++)
00375 temp_pnt[d] = clustercenters.at<float>(i,d);
00376
00377 kernel[i].SetMean(temp_pnt);
00378
00379 kernel[i].SetSigma(Gaussian::returnFixedSigma(sigma));
00380 }
00381 }
00382
00383
00384 void GMM::initkernels(const std::vector<GMMFloatPnt>& pts, const float sigma) {
00385
00386 GMMFloatPnt xmin, xmax, temp_mean;
00387
00388 for (int d = 0; d < NUM_GMM_DIMS; d++)
00389 xmin[d] = xmax[d] = pts[0][d];
00390
00391
00392 for (unsigned int i = 0; i < pts.size(); i++) {
00393 for (int d = 0; d < NUM_GMM_DIMS; d++) {
00394 if (pts[i][d] < xmin[d])
00395 xmin[d] = pts[i][d];
00396 if (pts[i][d] > xmax[d])
00397 xmax[d] = pts[i][d];
00398 }
00399 }
00400
00401 time_t ti;
00402
00403 time(&ti);
00404 srand(ti);
00405
00406
00407
00408
00409 for (int i = 0; i < nk; i++) {
00410 for (int d = 0; d < NUM_GMM_DIMS; d++)
00411 temp_mean[d] = xmin[d] + (float)((xmax[d] - xmin[d]) * rand()) / (float) RAND_MAX;
00412
00413 kernel[i].SetMean(temp_mean);
00414 kernel[i].SetSigma(Gaussian::returnFixedSigma(sigma));
00415 }
00416 }
00417
00418
00419 void GMM::savegmm(const fs::path& savefilepath) const {
00420 std::ofstream fd_gmm;
00421
00422 fd_gmm.open(savefilepath.string().c_str(), std::ofstream::binary | std::ofstream::trunc);
00423
00424 fd_gmm.write(reinterpret_cast<const char *>(&nk), sizeof(int));
00425 fd_gmm.write(reinterpret_cast<const char *>(&em_thresh), sizeof(double));
00426 fd_gmm.write(reinterpret_cast<const char *>(&max_iter), sizeof(double));
00427 fd_gmm.write(reinterpret_cast<const char *>(&min_iter), sizeof(double));
00428 fd_gmm.write(reinterpret_cast<const char *>(w), sizeof(float)*nk);
00429
00430
00431 for (int i = 0; i < nk; i++) {
00432 kernel[i].serialize(fd_gmm);
00433 }
00434
00435 fd_gmm.close();
00436 }
00437
00438
00439 void GMM::loadgmm(const fs::path& loadfilepath) {
00440 std::ifstream fd_gmm;
00441
00442 fd_gmm.open(loadfilepath.string().c_str(), std::ofstream::binary);
00443
00444
00445 free();
00446
00447
00448 int num_kernels;
00449 fd_gmm.read(reinterpret_cast<char *>(&num_kernels), sizeof(int));
00450 fd_gmm.read(reinterpret_cast<char *>(&em_thresh), sizeof(double));
00451 fd_gmm.read(reinterpret_cast<char *>(&max_iter), sizeof(double));
00452 fd_gmm.read(reinterpret_cast<char *>(&min_iter), sizeof(double));
00453
00454 alloc(num_kernels);
00455
00456 fd_gmm.read(reinterpret_cast<char *>(w), sizeof(float)*nk);
00457
00458
00459 for (int i = 0; i < nk; i++) {
00460 kernel[i].deserialize(fd_gmm);
00461 }
00462
00463 fd_gmm.close();
00464 }