You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
4.3 KiB
137 lines
4.3 KiB
// This file is part of the OpenCV project. |
|
// It is subject to the license terms in the LICENSE file found in the top-level directory |
|
// of this distribution and at http://opencv.org/license.html. |
|
|
|
#include "opencv2/videoio.hpp" |
|
#include "opencv2/highgui.hpp" |
|
#include "opencv2/imgproc.hpp" |
|
#include "opencv2/objdetect.hpp" |
|
#include "opencv2/face/mace.hpp" |
|
#include <iostream> |
|
using namespace cv; |
|
using namespace cv::face; |
|
using namespace std; |
|
|
|
|
|
enum STATE { |
|
NEUTRAL, |
|
RECORD, |
|
PREDICT |
|
}; |
|
|
|
const char *help = |
|
"press 'r' to record images. once N trainimages were recorded, train the mace filter\n" |
|
"press 'p' to predict (twofactor mode will switch back to neutral after each prediction attempt)\n" |
|
"press 's' to save a trained model\n" |
|
"press 'esc' to return\n" |
|
"any other key will reset to neutral state\n"; |
|
|
|
int main(int argc, char **argv) { |
|
CommandLineParser parser(argc, argv, |
|
"{ help h usage ? || show this help message }" |
|
"{ cascade c || (required) path to a cascade file for face detection }" |
|
"{ pre p || load a pretrained mace filter file, saved from previous session (e.g. my.xml.gz) }" |
|
"{ num n |50| num train images }" |
|
"{ size s |64| image size }" |
|
"{ twofactor t || pass phrase(text) for 2 factor authentification.\n" |
|
" (random convolute images seeded with the crc of this)\n" |
|
" users will get prompted to guess the secrect, additional to the image. }" |
|
); |
|
String cascade = parser.get<String>("cascade"); |
|
if (parser.has("help") || cascade.empty()) { |
|
parser.printMessage(); |
|
return 1; |
|
} else { |
|
cout << help << endl; |
|
} |
|
String defname = "mace.xml.gz"; |
|
String pre = parser.get<String>("pre"); |
|
String two = parser.get<String>("twofactor"); |
|
int N = parser.get<int>("num"); |
|
int Z = parser.get<int>("size"); |
|
int state = NEUTRAL; |
|
|
|
Ptr<MACE> mace; |
|
if (! pre.empty()) { // load pretrained model, if available |
|
mace = MACE::load(pre); |
|
if (mace->empty()) { |
|
cerr << "loading the MACE failed !" << endl; |
|
return -1; |
|
} |
|
state = PREDICT; |
|
} else { |
|
mace = MACE::create(Z); |
|
if (! two.empty()) { |
|
cout << "'" << two << "' initial passphrase" << endl; |
|
mace->salt(two); |
|
} |
|
} |
|
|
|
|
|
CascadeClassifier head(cascade); |
|
if (head.empty()) { |
|
cerr << "loading the cascade failed !" << endl; |
|
return -2; |
|
} |
|
|
|
VideoCapture cap(0); |
|
if (! cap.isOpened()) { |
|
cerr << "VideoCapture could not be opened !" << endl; |
|
return -3; |
|
} |
|
|
|
vector<Mat> train_img; |
|
while(1) { |
|
Mat frame; |
|
cap >> frame; |
|
|
|
vector<Rect> rects; |
|
head.detectMultiScale(frame,rects); |
|
if (rects.size()>0) { |
|
Scalar col = Scalar(0,120,0); |
|
|
|
if (state == RECORD) { |
|
if (train_img.size() >= size_t(N)) { |
|
mace->train(train_img); |
|
train_img.clear(); |
|
state = PREDICT; |
|
} else { |
|
train_img.push_back(frame(rects[0]).clone()); |
|
} |
|
col = Scalar(200,0,0); |
|
} |
|
|
|
if (state == PREDICT) { |
|
if (! two.empty()) { // prompt for secret on console |
|
cout << "enter passphrase: "; |
|
string pass; |
|
getline(cin, pass); |
|
mace->salt(pass); |
|
state = NEUTRAL; |
|
cout << "'" << pass << "' : "; |
|
} |
|
bool same = mace->same(frame(rects[0])); |
|
if (same) col = Scalar(0,220,220); |
|
else col = Scalar(60,60,60); |
|
if (! two.empty()) { |
|
cout << (same ? "accepted." : "denied.") << endl; |
|
} |
|
} |
|
|
|
rectangle(frame, rects[0], col, 2); |
|
} |
|
|
|
imshow("MACE",frame); |
|
int k = waitKey(10); |
|
switch (k) { |
|
case -1 : break; |
|
case 27 : return 0; |
|
default : state = NEUTRAL; break; |
|
case 'r': state = RECORD; break; |
|
case 'p': state = PREDICT; break; |
|
case 's': mace->save(defname); break; |
|
} |
|
} |
|
|
|
return 0; |
|
}
|
|
|