/* This file was part of GSoC Project: Facemark API for OpenCV Final report: https://gist.github.com/kurnianggoro/74de9121e122ad0bd825176751d47ecc Student: Laksono Kurnianggoro Mentor: Delia Passalacqua */ /*---------------------------------------------- * Usage: * facemark_demo_lbf <face_cascade_model> <saved_model_filename> <training_images> <annotation_files> [test_files] * * Example: * facemark_demo_lbf ../face_cascade.xml ../LBF.model ../images_train.txt ../points_train.txt ../test.txt * * Notes: * the user should provides the list of training images_train * accompanied by their corresponding landmarks location in separated files. * example of contents for images_train.txt: * ../trainset/image_0001.png * ../trainset/image_0002.png * example of contents for points_train.txt: * ../trainset/image_0001.pts * ../trainset/image_0002.pts * where the image_xxxx.pts contains the position of each face landmark. * example of the contents: * version: 1 * n_points: 68 * { * 115.167660 220.807529 * 116.164839 245.721357 * 120.208690 270.389841 * ... * } * example of the dataset is available at https://ibug.doc.ic.ac.uk/download/annotations/ibug.zip *--------------------------------------------------*/ #include <stdio.h> #include <fstream> #include <sstream> #include <iostream> #include "opencv2/core.hpp" #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/face.hpp" using namespace std; using namespace cv; using namespace cv::face; static bool myDetector( InputArray image, OutputArray roi, CascadeClassifier *face_detector); static bool parseArguments(int argc, char** argv, CommandLineParser & , String & cascade, String & model, String & images, String & annotations, String & testImages ); int main(int argc, char** argv) { CommandLineParser parser(argc, argv,""); String cascade_path,model_path,images_path, annotations_path, test_images_path; if(!parseArguments(argc, argv, parser,cascade_path,model_path,images_path, annotations_path, test_images_path)) return -1; /*create the facemark instance*/ FacemarkLBF::Params params; params.model_filename = model_path; params.cascade_face = cascade_path; Ptr<FacemarkLBF> facemark = FacemarkLBF::create(params); CascadeClassifier face_cascade; face_cascade.load(params.cascade_face.c_str()); facemark->setFaceDetector((FN_FaceDetector)myDetector, &face_cascade); /*Loads the dataset*/ std::vector<String> images_train; std::vector<String> landmarks_train; loadDatasetList(images_path,annotations_path,images_train,landmarks_train); Mat image; std::vector<Point2f> facial_points; for(size_t i=0;i<images_train.size();i++){ printf("%i/%i :: %s\n", (int)(i+1), (int)images_train.size(),images_train[i].c_str()); image = imread(images_train[i].c_str()); loadFacePoints(landmarks_train[i],facial_points); facemark->addTrainingSample(image, facial_points); } /*train the Algorithm*/ facemark->training(); /*test using some images*/ String testFiles(images_path), testPts(annotations_path); if(!test_images_path.empty()){ testFiles = test_images_path; testPts = test_images_path; //unused } std::vector<String> images; std::vector<String> facePoints; loadDatasetList(testFiles, testPts, images, facePoints); std::vector<Rect> rects; CascadeClassifier cc(params.cascade_face.c_str()); for(size_t i=0;i<images.size();i++){ std::vector<std::vector<Point2f> > landmarks; cout<<images[i]; Mat img = imread(images[i]); facemark->getFaces(img, rects); facemark->fit(img, rects, landmarks); for(size_t j=0;j<rects.size();j++){ drawFacemarks(img, landmarks[j], Scalar(0,0,255)); rectangle(img, rects[j], Scalar(255,0,255)); } if(rects.size()>0){ cout<<endl; imshow("result", img); waitKey(0); }else{ cout<<"face not found"<<endl; } } } bool myDetector(InputArray image, OutputArray faces, CascadeClassifier *face_cascade) { Mat gray; if (image.channels() > 1) cvtColor(image, gray, COLOR_BGR2GRAY); else gray = image.getMat().clone(); equalizeHist(gray, gray); std::vector<Rect> faces_; face_cascade->detectMultiScale(gray, faces_, 1.4, 2, CASCADE_SCALE_IMAGE, Size(30, 30)); Mat(faces_).copyTo(faces); return true; } bool parseArguments(int argc, char** argv, CommandLineParser & parser, String & cascade, String & model, String & images, String & annotations, String & test_images ){ const String keys = "{ @c cascade | | (required) path to the face cascade xml file fo the face detector }" "{ @i images | | (required) path of a text file contains the list of paths to all training images}" "{ @a annotations | | (required) Path of a text file contains the list of paths to all annotations files}" "{ @m model | | (required) path to save the trained model }" "{ t test-images | | Path of a text file contains the list of paths to the test images}" "{ help h usage ? | | facemark_demo_lbf -cascade -images -annotations -model [-t] \n" " example: facemark_demo_lbf ../face_cascade.xml ../images_train.txt ../points_train.txt ../lbf.model}" ; parser = CommandLineParser(argc, argv,keys); parser.about("hello"); if (parser.has("help")){ parser.printMessage(); return false; } cascade = String(parser.get<String>("cascade")); model = String(parser.get<string>("model")); images = String(parser.get<string>("images")); annotations = String(parser.get<string>("annotations")); test_images = String(parser.get<string>("t")); cout<<"cascade : "<<cascade.c_str()<<endl; cout<<"model : "<<model.c_str()<<endl; cout<<"images : "<<images.c_str()<<endl; cout<<"annotations : "<<annotations.c_str()<<endl; if(cascade.empty() || model.empty() || images.empty() || annotations.empty()){ std::cerr << "one or more required arguments are not found" << '\n'; parser.printMessage(); return false; } return true; }