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