Repository navigation
Expand file tree
/
Copy pathcaptureface.cpp
More file actions
263 lines (218 loc) · 9.99 KB
/
Copy pathcaptureface.cpp
File metadata and controls
263 lines (218 loc) · 9.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#include "captureface.h"
#include "ui_captureface.h"
#include "common_cv.h"
using namespace std;
CaptureFace::CaptureFace(QWidget *parent) :
QDialog(parent),
ui(new Ui::CaptureFace)
{
ui->setupUi(this);
m_capture_done = true;
m_pthread = new QThread();
m_getcamframe = new getcamframe();
m_getcamframe->Dosetup(m_pthread);
MaximumFace2Becaptured = 10;
m_selectedPerson = 1;
connect(m_getcamframe,SIGNAL(imageQueued()),this,SLOT(captureface()));
}
CaptureFace::~CaptureFace()
{
delete ui;
}
void CaptureFace::closeEvent(QCloseEvent * )
{
emit captureface_closed();
}
void CaptureFace::on_pbtBack_clicked()
{
m_capture_done = false;
if (m_getcamframe->m_bStart) {
m_getcamframe->m_bStart = false;
qDebug() << "Done button clicked\n";
qDebug() << "MaximumFace2Becaptured =" << MaximumFace2Becaptured << endl;
if (! m_getcamframe->my_imgQueue.isEmpty()) {
m_getcamframe->my_imgQueue.clear();
} else {
qDebug() << "Image que is empty no need to clear it \n";
}
if (m_pthread != NULL) {
m_pthread->exit(0);
}
}
this->close();
}
// Get access to the webcam.
//void initWebcam(VideoCapture &videoCapture, int cameraNumber)
//{
// // Get access to the default camera.
// try { // Surround the OpenCV call by a try/catch block so we can give a useful error message!
// videoCapture.open(cameraNumber);
// } catch (cv::Exception &e) {}
// if ( !videoCapture.isOpened() ) {
// cerr << "ERROR: Could not access the camera!" << endl;
// exit(1);
// }
// cout << "Loaded camera " << cameraNumber << "." << endl;
//}
// Load the face and 1 or 2 eye detection XML classifiers.
void initDetectors(CascadeClassifier &faceCascade, CascadeClassifier &eyeCascade1, CascadeClassifier &eyeCascade2)
{
// Load the Face Detection cascade classifier xml file.
try { // Surround the OpenCV call by a try/catch block so we can give a useful error message!
faceCascade.load(faceCascadeFilename);
} catch (cv::Exception &e) {}
if ( faceCascade.empty() ) {
cerr << "ERROR: Could not load Face Detection cascade classifier [" << faceCascadeFilename << "]!" << endl;
cerr << "Copy the file from your OpenCV data folder (eg: 'C:\\OpenCV\\data\\lbpcascades') into this WebcamFaceRec folder." << endl;
exit(1);
}
cout << "Loaded the Face Detection cascade classifier [" << faceCascadeFilename << "]." << endl;
// Load the Eye Detection cascade classifier xml file.
try { // Surround the OpenCV call by a try/catch block so we can give a useful error message!
eyeCascade1.load(eyeCascadeFilename1);
} catch (cv::Exception &e) {}
if ( eyeCascade1.empty() ) {
cerr << "ERROR: Could not load 1st Eye Detection cascade classifier [" << eyeCascadeFilename1 << "]!" << endl;
cerr << "Copy the file from your OpenCV data folder (eg: 'C:\\OpenCV\\data\\haarcascades') into this WebcamFaceRec folder." << endl;
exit(1);
}
cout << "Loaded the 1st Eye Detection cascade classifier [" << eyeCascadeFilename1 << "]." << endl;
// Load the Eye Detection cascade classifier xml file.
try { // Surround the OpenCV call by a try/catch block so we can give a useful error message!
eyeCascade2.load(eyeCascadeFilename2);
} catch (cv::Exception &e) {}
if ( eyeCascade2.empty() ) {
cerr << "Could not load 2nd Eye Detection cascade classifier [" << eyeCascadeFilename2 << "]." << endl;
// Dont exit if the 2nd eye detector did not load, because we have the 1st eye detector at least.
//exit(1);
}
else
cout << "Loaded the 2nd Eye Detection cascade classifier [" << eyeCascadeFilename2 << "]." << endl;
}
// Compare two images by getting the L2 error (square-root of sum of squared error).
double getSimilarity(const Mat A, const Mat B)
{
if (A.rows > 0 && A.rows == B.rows && A.cols > 0 && A.cols == B.cols) {
// Calculate the L2 relative error between the 2 images.
double errorL2 = norm(A, B, CV_L2);
// Convert to a reasonable scale, since L2 error is summed across all pixels of the image.
double similarity = errorL2 / (double)(A.rows * A.cols);
return similarity;
}
else {
//cout << "WARNING: Images have a different size in 'getSimilarity()'." << endl;
return 100000000.0; // Return a bad value
}
}
void CaptureFace::captureface()
{
/*CascadeClassifier faceCascade;
CascadeClassifier eyeCascade1;
CascadeClassifier eyeCascade2;
*/
//VideoCapture videoCapture;
if (! m_getcamframe->my_imgQueue.isEmpty()) {
Mat img(m_getcamframe->my_imgQueue.dequeue());
//int cameraNumber = 0; // Change this if you want to use a different camera device.
// Get access to the webcam.
//initWebcam(videoCapture, cameraNumber);
// Try to set the camera resolution. Note that this only works for some cameras on
// some computers and only for some drivers, so don't rely on it to work!
//videoCapture.set(CV_CAP_PROP_FRAME_WIDTH, DESIRED_CAMERA_WIDTH);
//videoCapture.set(CV_CAP_PROP_FRAME_HEIGHT, DESIRED_CAMERA_HEIGHT);
// Find a face and preprocess it to have a standard size and contrast & brightness.
Rect faceRect; // Position of detected face.
Rect searchedLeftEye, searchedRightEye; // top-left and top-right regions of the face, where eyes were searched.
Point leftEye, rightEye; // Position of the detected eyes.
Mat preprocessedFace = getPreprocessedFace(img, faceWidth, faceCascade, eyeCascade1, eyeCascade2, preprocessLeftAndRightSeparately, &faceRect, &leftEye, &rightEye, &searchedLeftEye, &searchedRightEye);
Mat old_prepreprocessedFace;
double old_time = 0;
bool gotFaceAndEyes = false;
if (preprocessedFace.data)
gotFaceAndEyes = true;
// Draw an anti-aliased rectangle around the detected face.
if (faceRect.width > 0) {
rectangle(img, faceRect, CV_RGB(255, 255, 0), 2, CV_AA);
#ifdef DISPLAY_EYE
// Draw light-blue anti-aliased circles for the 2 eyes.
Scalar eyeColor = CV_RGB(0,255,255);
if (leftEye.x >= 0) { // Check if the eye was detected
circle(img, Point(faceRect.x + leftEye.x, faceRect.y + leftEye.y), 6, eyeColor, 1, CV_AA);
}
if (rightEye.x >= 0) { // Check if the eye was detected
circle(img, Point(faceRect.x + rightEye.x, faceRect.y + rightEye.y), 6, eyeColor, 1, CV_AA);
}
#endif
}
#if 1
if (gotFaceAndEyes) {
// Check if this face looks somewhat different from the previously collected face.
double imageDiff = 10000000000.0;
if (old_prepreprocessedFace.data) {
imageDiff = getSimilarity(preprocessedFace, old_prepreprocessedFace);
}
// Also record when it happened.
double current_time = (double)getTickCount();
double timeDiff_seconds = (current_time - old_time)/getTickFrequency();
// Only process the face if it is noticeably different from the previous frame and there has been noticeable time gap.
if ((imageDiff > CHANGE_IN_IMAGE_FOR_COLLECTION) && (timeDiff_seconds > CHANGE_IN_SECONDS_FOR_COLLECTION)) {
if (MaximumFace2Becaptured != 0) {
// Also add the mirror image to the training set, so we have more training data, as well as to deal with faces looking to the left or right.
Mat mirroredFace;
flip(preprocessedFace, mirroredFace, 1);
m_selectedPerson = m_selectedPerson + 1;
// Add the face images to the list of detected faces.
preprocessedFaces.push_back(preprocessedFace);
preprocessedFaces.push_back(mirroredFace);
faceLabels.push_back(m_selectedPerson);
faceLabels.push_back(m_selectedPerson);
facename.push_back(m_enteredName);
facename.push_back(m_enteredName);
// Make a white flash on the face, so the user knows a photo has been taken.
Mat displayedFaceRegion = img(faceRect);
displayedFaceRegion += CV_RGB(90,90,90);
// Keep a copy of the processed face, to compare on next iteration.
old_prepreprocessedFace = preprocessedFace;
old_time = current_time;
qDebug() << "InLoop =" << MaximumFace2Becaptured << endl;
MaximumFace2Becaptured = MaximumFace2Becaptured - 1;
}
}
}
#endif
QImage qimg = QImage((const unsigned char*) img.data,
img.cols, img.rows,
QImage::Format_RGB888); // convert to QImage
ui->lblCaptureImg->setPixmap(QPixmap::fromImage(qimg));
ui->lblCaptureImg->show();
}
}
void CaptureFace::on_pbtDone_clicked()
{
m_capture_done = false;
if (m_getcamframe->m_bStart) {
m_getcamframe->m_bStart = false;
qDebug() << "Done button clicked\n";
qDebug() << "MaximumFace2Becaptured =" << MaximumFace2Becaptured << endl;
if (! m_getcamframe->my_imgQueue.isEmpty()) {
m_getcamframe->my_imgQueue.clear();
} else {
qDebug() << "Image que is empty no need to clear it \n";
}
if (m_pthread != NULL) {
m_pthread->exit(0);
}
}
}
void CaptureFace::on_btnStartCapture_clicked()
{
if ( m_getcamframe->m_bStart == false) {
m_getcamframe->m_bStart = true;
// Load the face and 1 or 2 eye detection XML classifiers.
initDetectors(faceCascade, eyeCascade1, eyeCascade2);
m_getcamframe->moveToThread(m_pthread);
//Start the thread
m_pthread->start();
}
qDebug() << "Start capture button clicked\n";
}