mexopencv  3.4.1
MEX interface for OpenCV library
Facemark_.cpp
Go to the documentation of this file.
1 
8 #include "mexopencv.hpp"
9 #include "opencv2/face.hpp"
10 using namespace std;
11 using namespace cv;
12 using namespace cv::face;
13 
14 // Persistent objects
15 namespace {
17 int last_id = 0;
21 string func;
22 
29 bool matlab_face_detector(InputArray image_, OutputArray faces_, void *userData)
30 {
31  // create input to evaluate MATLAB function
32  mxArray *lhs, *rhs[2];
33  rhs[0] = MxArray(func);
34  rhs[1] = MxArray(image_.getMat());
35 
36  // evaluate specified function in MATLAB as:
37  // faces = feval("func", image)
38  bool success = (mexCallMATLAB(1, &lhs, 2, rhs, "feval") == 0);
39  if (success) {
40  vector<Rect> faces(MxArray(lhs).toVector<Rect>());
41  Mat(faces).copyTo(faces_);
42  }
43 
44  // cleanup
45  mxDestroyArray(lhs);
46  mxDestroyArray(rhs[0]);
47  mxDestroyArray(rhs[1]);
48 
49  // return success flag
50  return success;
51 }
52 
58 FacemarkAAM::Config MxArrayToConfig(const MxArray& arr, mwIndex idx = 0)
59 {
60  return FacemarkAAM::Config(
61  arr.isField("R") ? arr.at("R", idx).toMat(CV_32F) : Mat::eye(2,2,CV_32F),
62  arr.isField("t") ? arr.at("t", idx).toPoint2f() : Point2f(0,0),
63  arr.isField("scale") ? arr.at("scale", idx).toFloat() : 1.0f,
64  arr.isField("scaleIdx") ? arr.at("scaleIdx", idx).toInt() : 0
65  );
66 }
67 
73 {
74  const mwSize n = arr.numel();
76  configs.reserve(n);
77  if (arr.isCell())
78  for (mwIndex i = 0; i < n; ++i)
79  configs.push_back(MxArrayToConfig(arr.at<MxArray>(i)));
80  else if (arr.isStruct())
81  for (mwIndex i = 0; i < n; ++i)
82  configs.push_back(MxArrayToConfig(arr,i));
83  else
84  mexErrMsgIdAndTxt("mexopencv:error",
85  "MxArray unable to convert to std::vector<cv::face::FacemarkAAM::Config>");
86  return configs;
87 }
88 
97 {
98  ptrdiff_t len = std::distance(first, last);
99  nargchk((len%2)==0);
100  FacemarkLBF::Params parameters;
101  for (; first != last; first += 2) {
102  string key(first->toString());
103  const MxArray& val = *(first + 1);
104  if (key == "ShapeOffset")
105  parameters.shape_offset = val.toDouble();
106  else if (key == "CascadeFace")
107  parameters.cascade_face = val.toString();
108  else if (key == "Verbose")
109  parameters.verbose = val.toBool();
110  else if (key == "NLandmarks")
111  parameters.n_landmarks = val.toInt();
112  else if (key == "InitShapeN")
113  parameters.initShape_n = val.toInt();
114  else if (key == "StagesN")
115  parameters.stages_n = val.toInt();
116  else if (key == "TreeN")
117  parameters.tree_n = val.toInt();
118  else if (key == "TreeDepth")
119  parameters.tree_depth = val.toInt();
120  else if (key == "BaggingOverlap")
121  parameters.bagging_overlap = val.toDouble();
122  else if (key == "ModelFilename")
123  parameters.model_filename = val.toString();
124  else if (key == "SaveModel")
125  parameters.save_model = val.toBool();
126  else if (key == "Seed")
127  parameters.seed = static_cast<unsigned>(val.toInt());
128  else if (key == "FeatsM")
129  parameters.feats_m = val.toVector<int>();
130  else if (key == "RadiusM")
131  parameters.radius_m = val.toVector<double>();
132  else if (key == "Pupils") {
133  if (!val.isCell() || val.numel() != 2)
134  mexErrMsgIdAndTxt("mexopencv:error", "Invalid arguments");
135  vector<MxArray> arr(val.toVector<MxArray>());
136  parameters.pupils[0] = arr[0].toVector<int>();
137  parameters.pupils[1] = arr[1].toVector<int>();
138  }
139  else if (key == "DetectROI")
140  parameters.detectROI = val.toRect();
141  else
142  mexErrMsgIdAndTxt("mexopencv:error",
143  "Unrecognized option %s", key.c_str());
144  }
145  return FacemarkLBF::create(parameters);
146 }
147 
156 {
157  ptrdiff_t len = std::distance(first, last);
158  nargchk((len%2)==0);
159  FacemarkAAM::Params parameters;
160  for (; first != last; first += 2) {
161  string key(first->toString());
162  const MxArray& val = *(first + 1);
163  if (key == "ModelFilename")
164  parameters.model_filename = val.toString();
165  else if (key == "M")
166  parameters.m = val.toInt();
167  else if (key == "N")
168  parameters.n = val.toInt();
169  else if (key == "NIter")
170  parameters.n_iter = val.toInt();
171  else if (key == "Verbose")
172  parameters.verbose = val.toBool();
173  else if (key == "SaveModel")
174  parameters.save_model = val.toBool();
175  else if (key == "MaxM")
176  parameters.max_m = val.toInt();
177  else if (key == "MaxN")
178  parameters.max_n = val.toInt();
179  else if (key == "TextureMaxM")
180  parameters.texture_max_m = val.toInt();
181  else if (key == "Scales")
182  parameters.scales = val.toVector<float>();
183  else
184  mexErrMsgIdAndTxt("mexopencv:error",
185  "Unrecognized option %s", key.c_str());
186  }
187  return FacemarkAAM::create(parameters);
188 }
189 
199  const string& type,
202 {
203  Ptr<Facemark> p;
204  if (type == "LBF")
205  p = createFacemarkLBF(first, last);
206  else if (type == "AAM")
207  p = createFacemarkAAM(first, last);
208  else
209  mexErrMsgIdAndTxt("mexopencv:error",
210  "Unrecognized facemark %s", type.c_str());
211  if (p.empty())
212  mexErrMsgIdAndTxt("mexopencv:error", "Failed to create Facemark");
213  return p;
214 }
215 }
216 
224 void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
225 {
226  // Check the number of arguments
227  nargchk(nrhs>=3 && nlhs<=3);
228 
229  // Argument vector
230  vector<MxArray> rhs(prhs, prhs+nrhs);
231  int id = rhs[0].toInt();
232  func = rhs[1].toString();
233  string method(rhs[2].toString());
234 
235  // constructor call
236  if (method == "new") {
237  nargchk(nrhs>=4 && nlhs<=1);
239  rhs[3].toString(), rhs.begin() + 4, rhs.end());
240  plhs[0] = MxArray(last_id);
241  mexLock();
242  return;
243  }
244  // static method call
245  else if (method == "getFacesHAAR") {
246  nargchk(nrhs==5 && nlhs<=2);
247  Mat image(rhs[3].toMat(CV_8U));
248  string face_cascade_name(rhs[4].toString());
249  vector<Rect> faces;
250  bool b = cv::face::getFacesHAAR(image, faces, face_cascade_name);
251  plhs[0] = MxArray(faces);
252  if (nlhs > 1)
253  plhs[1] = MxArray(b);
254  return;
255  }
256  else if (method == "loadDatasetList") {
257  nargchk(nrhs==5 && nlhs<=3);
258  string imageList(rhs[3].toString());
259  string annotationList(rhs[4].toString());
260  vector<String> images, annotations;
261  bool b = cv::face::loadDatasetList(
262  imageList, annotationList, images, annotations);
263  plhs[0] = MxArray(images);
264  if (nlhs > 1)
265  plhs[1] = MxArray(annotations);
266  if (nlhs > 2)
267  plhs[2] = MxArray(b);
268  return;
269  }
270  else if (method == "loadTrainingData1") {
271  nargchk(nrhs>=5 && (nrhs%2)==1 && nlhs<=3);
272  float offset = 0.0f;
273  for (int i=5; i<nrhs; i+=2) {
274  string key(rhs[i].toString());
275  if (key == "Offset")
276  offset = rhs[i+1].toFloat();
277  else
278  mexErrMsgIdAndTxt("mexopencv:error",
279  "Unrecognized option %s", key.c_str());
280  }
281  string imageList(rhs[3].toString());
282  string groundTruth(rhs[4].toString());
283  vector<String> images;
284  vector<vector<Point2f> > facePoints;
286  imageList, groundTruth, images, facePoints, offset);
287  plhs[0] = MxArray(images);
288  if (nlhs > 1)
289  plhs[1] = MxArray(facePoints);
290  if (nlhs > 2)
291  plhs[2] = MxArray(b);
292  return;
293  }
294  else if (method == "loadTrainingData2") {
295  nargchk(nrhs>=4 && (nrhs%2)==0 && nlhs<=3);
296  char delim = ' ';
297  float offset = 0.0f;
298  for (int i=4; i<nrhs; i+=2) {
299  string key(rhs[i].toString());
300  if (key == "Delim")
301  delim = (!rhs[i+1].isEmpty()) ? rhs[i+1].toString()[0] : ' ';
302  else if (key == "Offset")
303  offset = rhs[i+1].toFloat();
304  else
305  mexErrMsgIdAndTxt("mexopencv:error",
306  "Unrecognized option %s", key.c_str());
307  }
308  string filename(rhs[3].toString());
309  vector<String> images;
310  vector<vector<Point2f> > facePoints;
312  filename, images, facePoints, delim, offset);
313  plhs[0] = MxArray(images);
314  if (nlhs > 1)
315  plhs[1] = MxArray(facePoints);
316  if (nlhs > 2)
317  plhs[2] = MxArray(b);
318  return;
319  }
320  else if (method == "loadTrainingData3") {
321  nargchk(nrhs==4 && nlhs<=3);
322  vector<string> filenames(rhs[3].toVector<string>());
323  vector<vector<Point2f> > trainlandmarks;
324  vector<String> trainimages;
326  vector<String>(filenames.begin(), filenames.end()),
327  trainlandmarks, trainimages);
328  plhs[0] = MxArray(trainlandmarks);
329  if (nlhs > 1)
330  plhs[1] = MxArray(trainimages);
331  if (nlhs > 2)
332  plhs[2] = MxArray(b);
333  return;
334  }
335  else if (method == "loadFacePoints") {
336  nargchk(nrhs>=4 && (nrhs%2)==0 && nlhs<=2);
337  float offset = 0.0f;
338  for (int i=4; i<nrhs; i+=2) {
339  string key(rhs[i].toString());
340  if (key == "Offset")
341  offset = rhs[i+1].toFloat();
342  else
343  mexErrMsgIdAndTxt("mexopencv:error",
344  "Unrecognized option %s", key.c_str());
345  }
346  string filename(rhs[3].toString());
347  vector<Point2f> points;
348  bool b = cv::face::loadFacePoints(filename, points, offset);
349  plhs[0] = MxArray(points);
350  if (nlhs > 1)
351  plhs[1] = MxArray(b);
352  return;
353  }
354  else if (method == "drawFacemarks") {
355  nargchk(nrhs>=5 && (nrhs%2)==1 && nlhs<=1);
356  Scalar color(255,0,0);
357  for (int i=5; i<nrhs; i+=2) {
358  string key(rhs[i].toString());
359  if (key == "Color")
360  color = rhs[i+1].toScalar();
361  else
362  mexErrMsgIdAndTxt("mexopencv:error",
363  "Unrecognized option %s", key.c_str());
364  }
365  Mat image(rhs[3].toMat(CV_8U));
366  vector<Point2f> points(rhs[4].toVector<Point2f>());
367  cv::face::drawFacemarks(image, points, color);
368  plhs[0] = MxArray(image);
369  return;
370  }
371 
372  // Big operation switch
373  Ptr<Facemark> obj = obj_[id];
374  if (obj.empty())
375  mexErrMsgIdAndTxt("mexopencv:error", "Object not found id=%d", id);
376  if (method == "delete") {
377  nargchk(nrhs==3 && nlhs==0);
378  obj_.erase(id);
379  mexUnlock();
380  }
381  else if (method == "clear") {
382  nargchk(nrhs==3 && nlhs==0);
383  obj->clear();
384  }
385  else if (method == "empty") {
386  nargchk(nrhs==3 && nlhs<=1);
387  plhs[0] = MxArray(obj->empty());
388  }
389  else if (method == "getDefaultName") {
390  nargchk(nrhs==3 && nlhs<=1);
391  plhs[0] = MxArray(obj->getDefaultName());
392  }
393  else if (method == "read") {
394  nargchk(nrhs>=4 && (nrhs%2)==0 && nlhs==0);
395  string objname;
396  bool loadFromString = false;
397  for (int i=4; i<nrhs; i+=2) {
398  string key(rhs[i].toString());
399  if (key == "ObjName")
400  objname = rhs[i+1].toString();
401  else if (key == "FromString")
402  loadFromString = rhs[i+1].toBool();
403  else
404  mexErrMsgIdAndTxt("mexopencv:error",
405  "Unrecognized option %s", key.c_str());
406  }
407  FileStorage fs(rhs[3].toString(), FileStorage::READ +
408  (loadFromString ? FileStorage::MEMORY : 0));
409  if (!fs.isOpened())
410  mexErrMsgIdAndTxt("mexopencv:error", "Failed to open file");
411  FileNode fn(objname.empty() ? fs.getFirstTopLevelNode() : fs[objname]);
412  if (fn.empty())
413  mexErrMsgIdAndTxt("mexopencv:error", "Failed to get node");
414  obj->read(fn);
415  }
416  else if (method == "write") {
417  nargchk(nrhs==4 && nlhs<=1);
418  FileStorage fs(rhs[3].toString(), FileStorage::WRITE +
419  ((nlhs > 0) ? FileStorage::MEMORY : 0));
420  if (!fs.isOpened())
421  mexErrMsgIdAndTxt("mexopencv:error", "Failed to open file");
422  fs << obj->getDefaultName() << "{";
423  obj->write(fs);
424  fs << "}";
425  if (nlhs > 0)
426  plhs[0] = MxArray(fs.releaseAndGetString());
427  }
428  else if (method == "addTrainingSample") {
429  nargchk(nrhs==5 && nlhs<=1);
430  Mat image(rhs[3].toMat(CV_8U));
431  vector<Point2f> landmarks(rhs[4].toVector<Point2f>());
432  bool b = obj->addTrainingSample(image, landmarks);
433  plhs[0] = MxArray(b);
434  }
435  else if (method == "training") {
436  nargchk(nrhs==3 && nlhs==0);
437  obj->training(NULL); //NOTE: null for unused input
438  }
439  else if (method == "loadModel") {
440  nargchk(nrhs==4 && nlhs==0);
441  string model(rhs[3].toString());
442  obj->loadModel(model);
443  }
444  else if (method == "fit") {
445  nargchk(nrhs>=5 && (nrhs%2)==1 && nlhs<=2);
447  for (int i=5; i<nrhs; i+=2) {
448  string key(rhs[i].toString());
449  if (key == "Configs")
450  configs = MxArrayToVectorConfig(rhs[i+1]);
451  else
452  mexErrMsgIdAndTxt("mexopencv:error",
453  "Unrecognized option %s", key.c_str());
454  }
455  Mat image(rhs[3].toMat(CV_8U));
456  vector<Rect> faces(rhs[4].toVector<Rect>());
457  vector<vector<Point2f> > landmarks;
458  bool b = obj->fit(image, faces, landmarks,
459  !configs.empty() ? &configs : NULL);
460  plhs[0] = MxArray(landmarks);
461  if (nlhs > 1)
462  plhs[1] = MxArray(b);
463  }
464  else if (method == "setFaceDetector") {
465  nargchk(nrhs==4 && nlhs<=1);
466  func = rhs[3].toString();
467  bool b = obj->setFaceDetector(matlab_face_detector, NULL);
468  plhs[0] = MxArray(b);
469  }
470  else if (method == "getFaces") {
471  nargchk(nrhs==4 && nlhs<=2);
472  Mat image(rhs[3].toMat(CV_8U));
473  vector<Rect> faces;
474  bool b = obj->getFaces(image, faces);
475  plhs[0] = MxArray(faces);
476  if (nlhs > 1)
477  plhs[1] = MxArray(b);
478  }
479  else if (method == "getData") {
480  nargchk(nrhs==3 && nlhs<=2);
481  bool b;
483  if (!p.empty()) {
484  // AAM
485  FacemarkAAM::Data items;
486  b = obj->getData(&items);
487  plhs[0] = MxArray(items.s0);
488  }
489  else {
490  // LBF
491  b = obj->getData(NULL); //NOTE: null for unused output
492  plhs[0] = MxArray(Mat());
493  }
494  if (nlhs > 1)
495  plhs[1] = MxArray(b);
496  }
497  else
498  mexErrMsgIdAndTxt("mexopencv:error",
499  "Unrecognized operation %s", method.c_str());
500 }
T empty(T... args)
T distance(T... args)
std::vector< int > feats_m
mwSize numel() const
Number of elements in an array.
Definition: MxArray.hpp:546
T at(mwIndex index) const
Template for numeric array element accessor.
Definition: MxArray.hpp:1250
virtual void training(void *parameters=0)=0
void copyTo(OutputArray m) const
LIBMWMEX_API_EXTERN_C void mexLock(void)
Lock a MEX-function so that it cannot be cleared from memory.
virtual bool getData(void *items=0)=0
#define CV_8U
bool loadTrainingData(String filename, std::vector< String > &images, OutputArray facePoints, char delim=' ', float offset=0.0f)
Ptr< FacemarkAAM > createFacemarkAAM(vector< MxArray >::const_iterator first, vector< MxArray >::const_iterator last)
Create an instance of FacemarkAAM using options in arguments.
Definition: Facemark_.cpp:153
int last_id
Last object id to allocate.
Definition: Facemark_.cpp:17
STL namespace.
LIBMMWMATRIX_PUBLISHED_API_EXTERN_C void mxDestroyArray(mxArray *pa)
mxArray destructor
T end(T... args)
virtual bool isOpened() const
Ptr< FacemarkLBF > createFacemarkLBF(vector< MxArray >::const_iterator first, vector< MxArray >::const_iterator last)
Create an instance of FacemarkLBF using options in arguments.
Definition: Facemark_.cpp:94
struct mxArray_tag mxArray
Forward declaration for mxArray.
Definition: matrix.h:259
vector< FacemarkAAM::Config > MxArrayToVectorConfig(const MxArray &arr)
Convert an MxArray to std::vector<cv::face::FacemarkAAM::Config>
Definition: Facemark_.cpp:72
STL class.
virtual bool fit(InputArray image, InputArray faces, InputOutputArray landmarks, void *config=0)=0
string func
name of MATLAB function to evaluate (custom face detector)
Definition: Facemark_.cpp:21
T push_back(T... args)
virtual void clear()
virtual String releaseAndGetString()
#define CV_32F
Ptr< Y > dynamicCast() const
Point_< float > Point2f
LIBMWMEX_API_EXTERN_C void mexErrMsgIdAndTxt(const char *identifier, const char *err_msg,...)
Issue formatted error message with corresponding error identifier and return to MATLAB prompt...
std::vector< int > pupils[2]
bool isCell() const
Determine whether input is cell array.
Definition: MxArray.hpp:610
LIBMWMEX_API_EXTERN_C void mexUnlock(void)
Unlock a locked MEX-function so that it can be cleared from memory.
bool getFacesHAAR(InputArray image, OutputArray faces, const String &face_cascade_name)
virtual bool setFaceDetector(FN_FaceDetector detector, void *userData=0)=0
bool loadDatasetList(String imageList, String annotationList, std::vector< String > &images, std::vector< String > &annotations)
bool isField(const std::string &fieldName) const
Determine whether a struct array has a specified field.
Definition: MxArray.hpp:743
mxArray object wrapper for data conversion and manipulation.
Definition: MxArray.hpp:123
void nargchk(bool cond)
Alias for input/output arguments number check.
Definition: mexopencv.hpp:181
CV__DEBUG_NS_END typedef const _InputArray & InputArray
bool matlab_face_detector(InputArray image_, OutputArray faces_, void *userData)
Custom face detector implemented as a MATLAB function.
Definition: Facemark_.cpp:29
FileNode getFirstTopLevelNode() const
bool isStruct() const
Determine whether input is structure array.
Definition: MxArray.hpp:708
map< int, Ptr< Facemark > > obj_
Object container.
Definition: Facemark_.cpp:19
STL class.
bool empty() const
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
Main entry called from Matlab.
Definition: Facemark_.cpp:224
FacemarkAAM::Config MxArrayToConfig(const MxArray &arr, mwIndex idx=0)
Convert an MxArray to cv::face::FacemarkAAM::Config.
Definition: Facemark_.cpp:58
virtual String getDefaultName() const
Global constant definitions.
T begin(T... args)
virtual void write(FileStorage &fs) const=0
T c_str(T... args)
virtual bool getFaces(InputArray image, OutputArray faces)=0
Ptr< Facemark > createFacemark(const string &type, vector< MxArray >::const_iterator first, vector< MxArray >::const_iterator last)
Create an instance of Facemark using options in arguments.
Definition: Facemark_.cpp:198
std::vector< float > scales
bool loadFacePoints(String filename, OutputArray points, float offset=0.0f)
virtual bool empty() const
virtual void loadModel(String model)=0
int type() const
void drawFacemarks(InputOutputArray image, InputArray points, Scalar color=Scalar(255, 0, 0))
std::vector< double > radius_m
LIBMWMEX_API_EXTERN_C int mexCallMATLAB(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[], const char *fcn_name)
call MATLAB function
void create(int arows, int acols, int atype, Target target=ARRAY_BUFFER, bool autoRelease=false)
cv::Mat toMat() const
virtual void read(const FileNode &fn)=0
virtual bool addTrainingSample(InputArray image, InputArray landmarks)=0
T reserve(T... args)