-
Notifications
You must be signed in to change notification settings - Fork 0
/
LearnNRecognize.cpp
222 lines (193 loc) · 7.9 KB
/
LearnNRecognize.cpp
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
//
// main.cpp
// learn-n-recognize
//
// Created by Samuel Prevost on 11/11/2016.
// Copyright © 2016 Samuel Prevost. All rights reserved.
//
#include <iostream>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
#include "Database.hpp"
#include "Message.hpp"
#include "ArgumentManager.hpp"
#include "HaarCascade.hpp"
#include "LBPRecognizer.hpp"
// Set default mode to scan
#define DEFAULT_MODE SCAN
// Set the number of frame before learning the stack
#define FRAMES_BEFORE_LEARNING 30
// Used namespaces
using cv::VideoCapture;
using cv::waitKey;
void SaveAndExit(LBPRecognizer* rec);
/** Global variables **/
/* Modes:
* - SCAN : Scanning mode, detect faces and write their name
* - LEARN : Learning mode, learn new faces by associating them with their name
*/
enum Mode { SCAN, LEARN };
// The selected mode
Mode currentMode = DEFAULT_MODE;
int main(int argc, const char * argv[]){
// Clear the console
ClearMessage();
// Display credits
CreditsMessage();
// Display current OpenCV version
// (3.1.0-dev for now)
VersionMessage(CV_VERSION);
// Arguments handler, check if every args are provided
ArgumentManager* am = new ArgumentManager(argc, argv);
// Database containing subject's name and id
Database* db;
if(am->database_path != "")
db = new Database(am->database_path);
else
db = new Database();
// Haar Cascade detect human faces and get us their positions
HaarCascade* hc = new HaarCascade(am->face_cascade_path);
// LBPR recognize and identify the faces, it gives us their id
LBPRecognizer* rec;
if(am->recognizer_path.size() > 1)
rec = new LBPRecognizer(am->recognizer_path);
else
rec = new LBPRecognizer();
// Open camera image stream
VideoCapture cap(am->cameraID);
// If we failed, exit program
if(!cap.isOpened()) {
ErrorOpeningCameraMessage();
exit(EXIT_FAILURE);
}
// This will contain the position of every faces
vector<Rect> faces;
// This will contain the current frame we will work with
Mat currentFrame;
// This will contain the name of the subject we are learning the face
string subject_name;
// This will contain the id of the subject we are learning the face
int subject_id = NULL;
// This will contain some of the last frames to update/train the recognizer later with it
vector<Mat> framesToLearn;
while (true) {
switch (currentMode) {
// Scanning mode
case SCAN:
ScanningModeMessage();
Countdown(3);
while (true){
// Save the current frame
cap >> currentFrame;
// Detect every faces on it
faces = hc->detectFaces(¤tFrame);
for(int i = 0; i < faces.size(); i++){
// if we've initialized our LBPR
if(!rec->isEmpty()){
// id of the detected face
int id = -1;
// confidence of the detection
double confidence = 0.0;
// currentFrame(faces[i]) crop workingFrame to the Rect faces[i]
// Get subject's id from image using LBPH
rec->recognize(currentFrame(faces[i]), &id, &confidence);
// Draw detected name and confidence on the current frame
rec->drawNameAndConf(¤tFrame, faces[i], db->getSubjectName(id), to_string(confidence));
}else{
// otherwise, we can't recognize the faces
rec->drawNameAndConf(¤tFrame, faces[i], " ? ", "-");
}
}
// Draw rectangle around every faces
hc->drawRect(¤tFrame, faces);
// Display the frame
imshow("Learn'n'Recognize", currentFrame);
// Wait 1ms for key
char key = (char)waitKey(1);
// Save and exit if we pressed 'q'
if( key == 'q' ) { SaveAndExit(rec);}
// If we pressed 'l'
if( key == 'l' ) {
// Go to learning
currentMode = LEARN;
break;
}
}
break;
// Learning mode
case LEARN:
// Ask user if the subject exist in the database
if (DoesSubjectExist()){
/* Subject already exist in database */
// Get his name and id
AskSubjectNameAndID(&subject_name, &subject_id, db);
}else{
/* New subject */
subject_name = AskNewSubjectName(db);
// Insert subject into db and get his new id
subject_id = db->insertSubject(subject_name);
// Exit learning mode if we failed to insert the subject into db
if(subject_id == -1){
currentMode = SCAN;
break;
}
}
// Tell the user what is happening
LearningModeMessage();
// Wait 7 sec
Countdown(7);
while (true){
// Save the current frame
cap >> currentFrame;
// Detect every faces on it
faces = hc->detectFaces(¤tFrame);
// Theoretically faces.size() = 1 , but meh
for (int i = 0; i < faces.size(); i++) {
// Here, we add the faces to a stack to learn them when they'll be
// a bunch of them
framesToLearn.push_back(currentFrame(faces[i]));
}
// If we've got enough frames
if(framesToLearn.size() > FRAMES_BEFORE_LEARNING){
vector<int> labels(framesToLearn.size());
for (int i = 0; i < framesToLearn.size(); i++) {
labels[i] = subject_id;
}
if(rec->isEmpty())
rec->train(framesToLearn, labels);
else
rec->update(framesToLearn, labels);
// Since we don't want to re-learn the same frame, clear the stack
framesToLearn.clear();
}
// Draw rectangles around faces
hc->drawRect(¤tFrame, faces);
// Display the frame
imshow("Learn'n'Recognize", currentFrame);
// Wait 1ms for key
char key = (char)waitKey(1);
// Save and exit if we pressed 'q'
if( key == 'q' ) { SaveAndExit(rec);}
// If we pressed 's' or spacebar
if( key == 's' || key == ' ') {
// Reset name and id
subject_id = NULL;
subject_name = "";
// Go to scanning mode
currentMode = SCAN;
break;
}
}
break;
}
}
return 0;
}
void SaveAndExit(LBPRecognizer* rec){
// Save our recognizer
rec->save(AskWhereToSaveRecognizer() + "/LBPH_recognizer.xml");
// Say goodbye
ExitMessage();
exit(EXIT_SUCCESS);
return;
}