PageRenderTime 53ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/visual-control/visual-control/cognition/recognizer/eigenfacerecognizer.cpp

https://gitlab.com/CarlosRA97/visual-control
C++ | 224 lines | 136 code | 59 blank | 29 comment | 16 complexity | 4f3dc99c4ebcc7a63aa8309f5d97cb52 MD5 | raw file
  1. #include "eigenfacerecognizer.h"
  2. #include <highgui.h>
  3. #include <cvaux.h>
  4. #include <limits>
  5. namespace cognition
  6. {
  7. EigenfaceRecognizer::EigenfaceRecognizer(void)
  8. :images(0),
  9. numTrainedImages(0),
  10. numEigenvalues(0),
  11. eigenVectors(0),
  12. averageImage(0),
  13. eigenvalues(0),
  14. projectedTrainImage(0)
  15. {
  16. }
  17. EigenfaceRecognizer::~EigenfaceRecognizer(void)
  18. {
  19. }
  20. bool EigenfaceRecognizer::addTrainingImage(const std::string &filename, const std::string &name)
  21. {
  22. trainingImages[filename] = name;
  23. return true;
  24. }
  25. void EigenfaceRecognizer::freeMemory(int fromIndex)
  26. {
  27. for(; fromIndex >= 0; fromIndex--)
  28. cvFree(&images[fromIndex]);
  29. numTrainedImages = 0;
  30. cvFree(images);
  31. }
  32. bool EigenfaceRecognizer::train()
  33. {
  34. isTrained = false;
  35. if(!loadTrainingImages())
  36. return false;
  37. //do principal component analysis
  38. doPCA();
  39. // project the training images onto the PCA subspace
  40. projectedTrainImage = cvCreateMat( numTrainedImages, numEigenvalues, CV_32FC1 );
  41. int offset = projectedTrainImage->step / sizeof(float);
  42. for(int i = 0; i < numTrainedImages; i++)
  43. {
  44. //int offset = i * nEigens;
  45. cvEigenDecomposite(
  46. images[i],
  47. numEigenvalues,
  48. eigenVectors,
  49. 0, 0,
  50. averageImage,
  51. //projectedTrainFaceMat->data.fl + i*nEigens);
  52. projectedTrainImage->data.fl + i*offset);
  53. }
  54. isTrained = true;
  55. return isTrained;
  56. }
  57. bool EigenfaceRecognizer::loadTrainingImages()
  58. {
  59. if(trainingImages.size() < 2)
  60. return false;
  61. if(images && numTrainedImages > 0)
  62. freeMemory(numTrainedImages-1);//cvFree(images); //deletes images and sets images to 0
  63. //remove all the index to filename, name mappings
  64. recognitionDescriptor.clear();
  65. //number of images we are going to use for training
  66. numTrainedImages = trainingImages.size();
  67. //allocate space for an IplImage array
  68. images = (IplImage **) cvAlloc(sizeof(IplImage *) * numTrainedImages);
  69. int currentImage = 0;
  70. for(StringMap::iterator current = trainingImages.begin(); current != trainingImages.end(); ++current)
  71. {
  72. images[currentImage] = cvLoadImage(current->first.c_str(), CV_LOAD_IMAGE_GRAYSCALE);
  73. if(images[currentImage] == NULL) break;
  74. //add checks for size!
  75. //add filename and name as the descriptors images[current], used after recognition
  76. recognitionDescriptor.push_back(*current);
  77. currentImage++;
  78. }
  79. //not all images loaded
  80. if(currentImage != numTrainedImages)
  81. {
  82. freeMemory(currentImage);
  83. return false;
  84. }
  85. return true;
  86. }
  87. void EigenfaceRecognizer::doPCA()
  88. {
  89. // set the number of eigenvalues to use
  90. numEigenvalues = numTrainedImages-1;
  91. //the number of face images
  92. CvSize faceImgSize;
  93. // allocate the eigenvector images
  94. faceImgSize.width = images[0]->width;
  95. faceImgSize.height = images[0]->height;
  96. eigenVectors = (IplImage**)cvAlloc(sizeof(IplImage*) * numEigenvalues);
  97. for(int i = 0; i < numEigenvalues; i++)
  98. eigenVectors[i] = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);
  99. // allocate the eigenvalue array
  100. eigenvalues = cvCreateMat( 1, numEigenvalues, CV_32FC1 );
  101. // allocate the averaged image
  102. averageImage = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);
  103. // set the PCA termination criterion
  104. CvTermCriteria calcLimit = cvTermCriteria( CV_TERMCRIT_ITER, numEigenvalues, 1);
  105. // compute average image, eigenvalues, and eigenvectors
  106. // the new C++ api has a cv::PCA object for this, upgrade this in the future!
  107. cvCalcEigenObjects(
  108. numTrainedImages,
  109. (void*)images,
  110. (void*)eigenVectors,
  111. CV_EIGOBJ_NO_CALLBACK,
  112. 0,
  113. 0,
  114. &calcLimit,
  115. averageImage,
  116. eigenvalues->data.fl);
  117. cvNormalize(eigenvalues, eigenvalues, 1, 0, CV_L1, 0);
  118. }
  119. std::string EigenfaceRecognizer::recognize(cv::Mat &face)
  120. {
  121. //int i, nTestFaces = 0; // the number of test images
  122. //CvMat * trainPersonNumMat = 0; // the person numbers during training
  123. //float * projectedTestFace = 0;
  124. IplImage faceToRecognize = (IplImage) face;
  125. //IplImage *faceToRecognize = cvLoadImage("s1/1.pgm", CV_LOAD_IMAGE_GRAYSCALE);
  126. float *projectedTestImage = (float *)cvAlloc(sizeof(float) * numEigenvalues);
  127. //project the test image onto the PCA subspace
  128. cvEigenDecomposite(
  129. &faceToRecognize,
  130. numEigenvalues,
  131. eigenVectors,
  132. 0, 0,
  133. averageImage,
  134. projectedTestImage);
  135. int nearest = findNearestNeighbor(projectedTestImage);
  136. //take threshold into account, mark as not recognized if not found!
  137. return recognitionDescriptor[nearest].second;
  138. }
  139. int EigenfaceRecognizer::findNearestNeighbor(float *projectedTestImage)
  140. {
  141. //set the least distance to the maximum double value
  142. double leastDistanceSquare = std::numeric_limits<double>::max();
  143. //the index of the nearest element
  144. int nearestImage = 0;
  145. //calculate distance between each training image and the projected test face
  146. for(int current = 0; current < numTrainedImages; current++)
  147. {
  148. double distanceSquare = 0;
  149. for(int eigen = 0; eigen < numEigenvalues; eigen++)
  150. {
  151. //calculate the distance in for the current eigen
  152. float distance = projectedTestImage[eigen] -
  153. projectedTrainImage->data.fl[current * numEigenvalues + eigen];
  154. //square the distance and add it to the total value
  155. distanceSquare += distance * distance;
  156. }
  157. if(distanceSquare < leastDistanceSquare)
  158. {
  159. leastDistanceSquare = distanceSquare;
  160. nearestImage = current;
  161. }
  162. }
  163. return nearestImage;
  164. }
  165. }