EigenFace.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include <iostream>
  2. #include <fstream>
  3. #include <sstream>
  4. #include <opencv2/core/core.hpp>
  5. #include "opencv2/imgcodecs.hpp"
  6. #include <opencv2/highgui/highgui.hpp>
  7. #include <opencv2/opencv.hpp>
  8. #include <dirent.h>
  9. #include <stdlib.h>
  10. #include <time.h>
  11. using namespace cv;
  12. using namespace std;
  13. #define MAX_SLIDER_VALUE 255
  14. #define NUM_EIGEN_FACES 10
  15. // Weights for the different eigenvectors
  16. int sliderValues[NUM_EIGEN_FACES];
  17. // Matrices for average (mean) and eigenvectors
  18. Mat averageFace;
  19. vector<Mat> eigenFaces;
  20. // Read jpg files from the directory
  21. void readImages(string dirName, vector<Mat> &images)
  22. {
  23. cout << "Reading images from " << dirName;
  24. // Add slash to directory name if missing
  25. if (!dirName.empty() && dirName.back() != '/')
  26. dirName += '/';
  27. DIR *dir;
  28. struct dirent *ent;
  29. int count = 0;
  30. //image extensions
  31. string imgExt = "jpg";
  32. vector<string> files;
  33. if ((dir = opendir (dirName.c_str())) != NULL)
  34. {
  35. /* print all the files and directories within directory */
  36. while ((ent = readdir (dir)) != NULL)
  37. {
  38. if(strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0 )
  39. {
  40. continue;
  41. }
  42. string fname = ent->d_name;
  43. if (fname.find(imgExt, (fname.length() - imgExt.length())) != std::string::npos)
  44. {
  45. string path = dirName + fname;
  46. Mat img = imread(path);
  47. if(!img.data)
  48. {
  49. cout << "image " << path << " not read properly" << endl;
  50. }
  51. else
  52. {
  53. // Convert images to floating point type
  54. img.convertTo(img, CV_32FC3, 1/255.0);
  55. images.push_back(img);
  56. // A vertically flipped image is also a valid face image.
  57. // So lets use them as well.
  58. Mat imgFlip;
  59. flip(img, imgFlip, 1);
  60. images.push_back(imgFlip);
  61. }
  62. }
  63. }
  64. closedir (dir);
  65. }
  66. // Exit program if no images are found
  67. if(images.empty())exit(EXIT_FAILURE);
  68. cout << "... " << images.size() / 2 << " files read"<< endl;
  69. }
  70. // Create data matrix from a vector of images
  71. static Mat createDataMatrix(const vector<Mat> &images)
  72. {
  73. cout << "Creating data matrix from images ...";
  74. // Allocate space for all images in one data matrix.
  75. // The size of the data matrix is
  76. //
  77. // ( w * h * 3, numImages )
  78. //
  79. // where,
  80. //
  81. // w = width of an image in the dataset.
  82. // h = height of an image in the dataset.
  83. // 3 is for the 3 color channels.
  84. Mat data(static_cast<int>(images.size()), images[0].rows * images[0].cols * 3, CV_32F);
  85. // Turn an image into one row vector in the data matrix
  86. for(unsigned int i = 0; i < images.size(); i++)
  87. {
  88. // Extract image as one long vector of size w x h x 3
  89. Mat image = images[i].reshape(1,1);
  90. // Copy the long vector into one row of the destm
  91. image.copyTo(data.row(i));
  92. }
  93. cout << " DONE" << endl;
  94. return data;
  95. }
  96. // Calculate final image by adding weighted
  97. // EigenFaces to the average face.
  98. void createNewFace(int ,void *)
  99. {
  100. // Start with the mean image
  101. Mat output = averageFace.clone();
  102. // Add the eigen faces with the weights
  103. for(int i = 0; i < NUM_EIGEN_FACES; i++)
  104. {
  105. // OpenCV does not allow slider values to be negative.
  106. // So we use weight = sliderValue - MAX_SLIDER_VALUE / 2
  107. double weight = sliderValues[i] - MAX_SLIDER_VALUE/2;
  108. output = output + eigenFaces[i] * weight;
  109. }
  110. resize(output, output, Size(), 2, 2);
  111. imshow("Result", output);
  112. }
  113. // Reset slider values
  114. void resetSliderValues(int event, int x, int y, int flags, void* userdata)
  115. {
  116. if (event == EVENT_LBUTTONDOWN)
  117. {
  118. for(int i = 0; i < NUM_EIGEN_FACES; i++)
  119. {
  120. sliderValues[i] = 128;
  121. setTrackbarPos("Weight" + to_string(i), "Trackbars", MAX_SLIDER_VALUE/2);
  122. }
  123. createNewFace(0,0);
  124. }
  125. }
  126. int main(int argc, char **argv)
  127. {
  128. // Directory containing images
  129. string dirName = "images/";
  130. // Read images in the directory
  131. vector<Mat> images;
  132. readImages(dirName, images);
  133. // Size of images. All images should be the same size.
  134. Size sz = images[0].size();
  135. // Create data matrix for PCA.
  136. Mat data = createDataMatrix(images);
  137. // Calculate PCA of the data matrix
  138. cout << "Calculating PCA ...";
  139. PCA pca(data, Mat(), PCA::DATA_AS_ROW, NUM_EIGEN_FACES);
  140. cout << " DONE"<< endl;
  141. // Extract mean vector and reshape it to obtain average face
  142. averageFace = pca.mean.reshape(3,sz.height);
  143. // Find eigen vectors.
  144. Mat eigenVectors = pca.eigenvectors;
  145. // Reshape Eigenvectors to obtain EigenFaces
  146. for(int i = 0; i < NUM_EIGEN_FACES; i++)
  147. {
  148. Mat eigenFace = eigenVectors.row(i).reshape(3,sz.height);
  149. eigenFaces.push_back(eigenFace);
  150. }
  151. // Show mean face image at 2x the original size
  152. Mat output;
  153. resize(averageFace, output, Size(), 2, 2);
  154. namedWindow("Result", cv::WINDOW_AUTOSIZE);
  155. imshow("Result", output);
  156. // Create trackbars
  157. namedWindow("Trackbars", cv::WINDOW_AUTOSIZE);
  158. for(int i = 0; i < NUM_EIGEN_FACES; i++)
  159. {
  160. sliderValues[i] = MAX_SLIDER_VALUE/2;
  161. createTrackbar( "Weight" + to_string(i), "Trackbars", &sliderValues[i], MAX_SLIDER_VALUE, createNewFace);
  162. }
  163. // You can reset the sliders by clicking on the mean image.
  164. setMouseCallback("Result", resetSliderValues);
  165. cout << "Usage:" << endl
  166. << "\tChange the weights using the sliders" << endl
  167. << "\tClick on the result window to reset sliders" << endl
  168. << "\tHit ESC to terminate program." << endl;
  169. waitKey(0);
  170. destroyAllWindows();
  171. }