Go to the documentation of this file.00001
00002 #include "eigenfaces.h"
00003
00004
00005
00006 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00007 #include <vil1/vil1_save.h>
00008 #include <vcl_queue.h>
00009 #include <vcl_fstream.h>
00010 #include <vcl_cstdio.h>
00011 #include <vcl_cstring.h>
00012 #include <vcl_cassert.h>
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 EigenFace::~EigenFace()
00026 {
00027 delete average_training_image;
00028
00029
00030 vcl_vector<vnl_vector<double> *>::iterator iter;
00031 for (iter=training_images.begin();
00032 iter!=training_images.end(); iter++)
00033 delete *iter;
00034
00035
00036 for (iter=eigenvectors.begin(); iter!=eigenvectors.end(); iter++)
00037 delete *iter;
00038
00039
00040 for (iter=encoded_training_images.begin();
00041 iter!=encoded_training_images.end(); iter++)
00042 delete *iter;
00043
00044
00045 vcl_vector<char *>::iterator citer;
00046 for (citer=training_labels.begin(); citer!=training_labels.end(); citer++)
00047 delete *citer;
00048 }
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 bool EigenFace::add_training_image(Image *im, const char * label)
00065 {
00066
00067 assert(im!=NULL);
00068 vnl_vector<double> *image_vector = convert_image_to_vector(im);
00069 if (!image_vector) return false;
00070 if (image_size==0)
00071 image_size = image_vector->size();
00072 if (image_size!=image_vector->size())
00073 {
00074 vcl_cerr << "Error adding training image\n"
00075 << "Image of incorrect size\n";
00076 return false;
00077 }
00078 training_images.push_back(image_vector);
00079 training_labels.push_back(strdup(label));
00080
00081 assert(training_images.back()==image_vector);
00082 assert(vcl_strcmp(training_labels.back(),label)==0);
00083 return true;
00084 }
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 vnl_vector<double> *EigenFace::get_eigenvector(int i)
00099 {
00100 assert(i>=0);
00101 if ((unsigned int)i>=eigenvectors.size())
00102 {
00103 vcl_cerr << "Requesting eigenvector, " << i << " which doesn't exist\n"
00104 << "Number of eigenvectors is: " << eigenvectors.size() << vcl_endl;
00105 return NULL;
00106 }
00107 return eigenvectors[i];
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 double EigenFace::get_eigenvalue(int i)
00123 {
00124 assert(i>=0);
00125 if ((unsigned int)i>=eigenvalues.size())
00126 {
00127 vcl_cerr << "Requesting eigenvalue, " << i << " which doesn't exist\n"
00128 << "Number of eigenvalues is: " << eigenvalues.size() << vcl_endl;
00129 return 0.0;
00130 }
00131 return eigenvalues[i];
00132 }
00133
00134 void EigenFace::cleanup()
00135 {
00136
00137 if (!average_training_image)
00138 average_training_image = new vnl_vector<double>(training_images[0]->size(), 0.0);
00139 else average_training_image->fill(0.0);
00140
00141
00142 #if 0
00143 vector<vnl_vector<double> *>::iterator iter;
00144 for (iter=eigenvectors.begin(); iter!=eigenvectors.end(); iter++)
00145 delete *iter;
00146 eigenvectors.clear();
00147 eigenvalues.clear();
00148
00149 for (iter=encoded_training_images.begin();
00150 iter!=encoded_training_images.end(); iter++)
00151 {
00152 delete *iter;
00153 }
00154 encoded_training_images.clear();
00155 #endif
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 bool EigenFace::calculate_eigenfaces()
00169 {
00170 if (training_images.size()<=0)
00171 {
00172 vcl_cerr << "No training images\n";
00173 return false;
00174 }
00175
00176 vnl_matrix<double> A(image_size, training_images.size());
00177
00178 vcl_cout << "cleaning up\n";
00179 cleanup();
00180
00181
00182 vcl_cout << "Average training image\n"
00183 << "ati size = " << average_training_image->size() << vcl_endl;
00184 for (unsigned int i=0; i<training_images.size(); i++)
00185 {
00186 vcl_cout << "adding training image " << i << " size = "
00187 << training_images[i]->size() << vcl_endl;
00188 *average_training_image += *training_images[i];
00189 }
00190 *average_training_image /= (double)training_images.size();
00191 vcl_cout << "Populating A\n";
00192 for (unsigned int i=0; i<training_images.size(); i++)
00193 {
00194 vnl_vector<double> *training = training_images[i];
00195 for (unsigned int j=0; j<training->size(); j++)
00196 A(j, i) = (*training)[j]-(*average_training_image)[j];
00197 }
00198
00199 vcl_cout << "AtA\n";
00200
00201 vnl_matrix<double> AtA = A.transpose()*A;
00202 vnl_symmetric_eigensystem<double> eigen(AtA);
00203
00204 vcl_cout << "Eigenvectors\n";
00205 for (unsigned int i=0; i<training_images.size(); i++)
00206 {
00207 vnl_vector<double> *new_vec = new vnl_vector<double>(image_size);
00208 *new_vec = A*eigen.get_eigenvector(i);
00209
00210 eigenvectors.push_back(new_vec);
00211 eigenvalues.push_back(eigen.get_eigenvalue(i));
00212 }
00213
00214 vcl_cout << "Eigenvalues are:" ;
00215 vcl_vector<double>::iterator val_iter;
00216 for (val_iter=eigenvalues.begin(); val_iter!=eigenvalues.end(); val_iter++)
00217 vcl_cout << ' ' << (*val_iter);
00218 vcl_cout << "\nEncoding training images\n";
00219 encode_training_images();
00220
00221 return true;
00222 }
00223
00224 void EigenFace::check_training()
00225 {
00226 vcl_cout << "Check training image\n";
00227 if (average_training_image!=NULL)
00228 vcl_cout << "ati size = " << average_training_image->size() << vcl_endl;
00229 else
00230 vcl_cout << "ati not set\n";
00231 for (unsigned int i=0; i<training_images.size(); i++)
00232 {
00233 vcl_cout << "training image " << i << " size = "
00234 << training_images[i]->size() << vcl_endl;
00235 }
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 vnl_vector<double> *EigenFace::convert_image_to_vector(Image *im)
00252 {
00253 assert(im!=NULL);
00254 int index=0;
00255 vnl_vector<double> *new_vec = new vnl_vector<double>(im->width()*im->height());
00256 for (int j=0; j<im->height(); j++)
00257 for (int i=0; i<im->width(); i++)
00258 (*new_vec)[index++] = (double)(*im)(i,j);
00259 new_vec->normalize();
00260 return new_vec;
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274 bool EigenFace::check_eigenvectors()
00275 {
00276 if (eigenvectors.size()<=0) return false;
00277
00278 vcl_cout << "Eigenvalues are:" ;
00279 vcl_vector<double>::iterator val_iter;
00280 for (val_iter=eigenvalues.begin(); val_iter!=eigenvalues.end(); val_iter++)
00281 vcl_cout << ' ' << (*val_iter);
00282 vcl_cout << vcl_endl;
00283 vcl_vector<vnl_vector<double> *>::iterator iter1, iter2;
00284 for (iter1=eigenvectors.begin(); iter1!=eigenvectors.end(); iter1++)
00285 for (iter2=iter1+1; iter2!=eigenvectors.end(); iter2++)
00286 if (!epsilon_equals(dot_product(**iter1, **iter2), 0.0))
00287 {
00288 vcl_cout << "vectors aren't eigenvectors\n"
00289 << "offending vectors are: "
00290 << '\t' << **iter1 << vcl_endl
00291 << '\t' << **iter2 << vcl_endl
00292 << "dot product is: " << dot_product(**iter1, **iter2) << vcl_endl;
00293 return false;
00294 }
00295 return true;
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 void EigenFace::save_as_images(int width, int height)
00308 {
00309 assert(width > 0 && height > 0);
00310 if ((unsigned int)(width*height)!=image_size)
00311 {
00312 vcl_cerr << "width*height must be equal to image size\n"
00313 << "image size is: " << image_size << vcl_endl;
00314 return;
00315 }
00316
00317 Image im(width, height);
00318 vcl_vector<vnl_vector<double> *>::iterator iter;
00319 char name[100];
00320 int index=0;
00321 for (iter=eigenvectors.begin(); iter!=eigenvectors.end(); iter++)
00322 {
00323 double min = (**iter).min_value();
00324 double max = (**iter).max_value();
00325 for (int i=0; i<width; i++)
00326 for (int j=0; j<height; j++)
00327 im[i][j] = (unsigned char)
00328 (((**iter)[i+j*width]-min)/(max-min)*255);
00329 vcl_sprintf(name, "eigenface%03d.pgm", index++);
00330 vil1_save(im, name);
00331 }
00332 }
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 void EigenFace::encode_training_images()
00344 {
00345 vcl_vector<vnl_vector<double> *>::iterator iter;
00346 for (iter=training_images.begin(); iter!=training_images.end(); iter++)
00347 {
00348 encoded_training_images.push_back(encode(*iter));
00349 }
00350 }
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 vnl_vector<double>* EigenFace::encode(Image *im)
00365 {
00366 if (eigenvectors.size()<=0)
00367 {
00368 return NULL;
00369 }
00370 vnl_vector<double> *im_vec = convert_image_to_vector(im);
00371 *im_vec -= *average_training_image;
00372 vnl_vector<double> *wts = new vnl_vector<double>(eigenvectors.size());
00373 for (unsigned int i=0; i<eigenvectors.size(); i++)
00374 (*wts)[i] = dot_product(*im_vec, *(eigenvectors[i]));
00375 delete im_vec;
00376 return wts;
00377 }
00378
00379 vnl_vector<double>* EigenFace::encode(vnl_vector<double> *t_vec)
00380 {
00381 if (eigenvectors.size()<=0)
00382 {
00383 return NULL;
00384 }
00385 vnl_vector<double> *im_vec = new vnl_vector<double>(*t_vec);
00386 *im_vec -= *average_training_image;
00387 vnl_vector<double> *wts = new vnl_vector<double>(eigenvectors.size());
00388 for (unsigned int i=0; i<eigenvectors.size(); i++)
00389 (*wts)[i] = dot_product(*im_vec, *(eigenvectors[i]));
00390 delete im_vec;
00391 return wts;
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 vnl_vector<double>* EigenFace::decode(vnl_vector<double> *wts)
00407 {
00408 vnl_vector<double> *new_im = new vnl_vector<double>(image_size, 0.0);
00409 for (unsigned int i=0; i<eigenvectors.size(); i++)
00410 *new_im += ((*wts)[i])*(*(eigenvectors[i]));
00411
00412 return new_im;
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 char *EigenFace::classify(Image *im, double threshold, int k, int dim)
00432 {
00433 vcl_priority_queue<LabelDist> pq;
00434
00435 if (num_vectors()==0) return NULL;
00436 if (eigenvectors.size()==0) return NULL;
00437
00438 vnl_vector<double> *all_rep = encode(im);
00439 vnl_vector<double> rep(all_rep->extract(dim, all_rep->size()-dim));
00440 vnl_vector<double> diff(rep.size());
00441 double min_dist = DBL_MAX;
00442 int best=-1;
00443 char *ret=NULL;
00444 #if 0
00445 vcl_cout << "rep = " << *rep << vcl_endl;
00446 #endif
00447 for (int i=0; i<num_vectors(); i++)
00448 {
00449 vnl_vector<double> eigenvect=
00450 encoded_training_images[i]->extract
00451 (dim, encoded_training_images[i]->size()-dim);
00452
00453 diff = rep - eigenvect;
00454 double dist=diff.two_norm()/(double)diff.size();
00455 if ((dist<min_dist)&&(dist!=0.0))
00456 {
00457 min_dist=dist;
00458 best=i;
00459 }
00460 LabelDist t(get_label(i), dist);
00461 pq.push(t);
00462 }
00463 delete all_rep;
00464
00465 vcl_cout << "min_dist = " << min_dist << " label = " << get_label(best) << vcl_endl;
00466
00467 vcl_map<char *, int, ImageDatabase::ltstr> nns;
00468 for (int i=0; i<k; i++)
00469 {
00470 LabelDist t=pq.top();
00471 pq.pop();
00472 if ((t.dist<threshold)&&(t.dist!=0.0))
00473 nns[t.label]++;
00474 }
00475 vcl_map<char *, int, ImageDatabase::ltstr>::iterator iter;
00476 int max=0;
00477 for (iter=nns.begin(); iter!=nns.end(); iter++)
00478 {
00479 if ((*iter).second>max)
00480 {
00481 max = (*iter).second;
00482 ret = (*iter).first;
00483 }
00484 }
00485 vcl_cout << "label = " << ret << " num = " << max << vcl_endl;
00486 if (max<k/2+1) ret=NULL;
00487 #if 0
00488 char ch;
00489 vcl_cin >> ch;
00490 #endif
00491 return ret;
00492 }
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 void EigenFace::output_xgobi(char *basefile)
00506 {
00507 char filenames[200];
00508 vcl_sprintf(filenames, "%s.dat", basefile);
00509 vcl_ofstream datfile(filenames);
00510 vcl_sprintf(filenames, "%s.glyphs", basefile);
00511 vcl_ofstream glyphs(filenames);
00512 vcl_sprintf(filenames, "%s.row", basefile);
00513 vcl_ofstream rowfile(filenames);
00514 vcl_map<char*, int, ImageDatabase::ltstr> glyphmap;
00515 int glyphnum=1;
00516 for (int i=0; i<num_vectors(); i++)
00517 {
00518 datfile << *(encoded_training_images[i]) << vcl_endl;
00519
00520 if (glyphmap.find(training_labels[i])==glyphmap.end())
00521 {
00522 vcl_cout << "Adding training_label " << training_labels[i] << vcl_endl;
00523 glyphmap[training_labels[i]] = glyphnum;
00524 glyphnum += 3;
00525 }
00526 glyphs << glyphmap[training_labels[i]] << vcl_endl;
00527 rowfile << training_labels[i] << vcl_endl;
00528 }
00529 vcl_map<char *, int, ImageDatabase::ltstr>::iterator iter;
00530 for (iter=glyphmap.begin(); iter!=glyphmap.end(); iter++)
00531 vcl_cout << (*iter).first << vcl_endl;
00532 rowfile.close();
00533 glyphs.close();
00534 datfile.close();
00535 }