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 }