From 932f0fef834e27d5a9ff4d3edc4324b03b77ce3e Mon Sep 17 00:00:00 2001 From: Nicholas Charbonneau Date: Sun, 22 Apr 2018 21:16:21 -0400 Subject: [PATCH 1/7] Facemark API: Complex getters & setters macro --- cc/macros.h | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/cc/macros.h b/cc/macros.h index 65f1d2f5b..0c5b87b9f 100644 --- a/cc/macros.h +++ b/cc/macros.h @@ -9,6 +9,16 @@ #define FF_GETTER(clazz, name, prop) \ NAN_GETTER(name) { info.GetReturnValue().Set(Nan::ObjectWrap::Unwrap(info.This())->prop); } +#define FF_GETTER_SIMPLE(clazz, name, prop, converter) \ + NAN_GETTER(name) { \ + v8::Local jsValue = converter::wrap( \ + Nan::ObjectWrap::Unwrap(info.This())->prop \ + ); \ + info.GetReturnValue().Set(jsValue); \ + } + +#define FF_GETTER_COMPLEX(clazz, name, prop, converter) FF_GETTER_SIMPLE(clazz, name, prop, converter) + #define FF_GETTER_JSOBJ(clazz, name, value, unwrapper, ctor) \ NAN_GETTER(name) { \ v8::Local jsObj = FF_NEW_INSTANCE(ctor); \ @@ -129,6 +139,22 @@ static FF_FUNC_TYPE ff_func = FF_FUNC_TYPE(); #define FF_SETTER_NUMBER(clazz, name, prop) FF_SETTER(clazz, name, prop, ff_number) #define FF_SETTER_BOOL(clazz, name, prop) FF_SETTER(clazz, name, prop, ff_bool) +#define FF_SETTER_SIMPLE(clazz, name, prop, converter) \ + NAN_SETTER(name##Set) { \ + FF_METHOD_CONTEXT(#name); \ + Nan::ObjectWrap::Unwrap(info.This())->prop = converter::unwrap( \ + value \ + ); \ + } + +#define FF_SETTER_COMPLEX(clazz, name, prop, type, converter) \ + NAN_SETTER(name##Set) { \ + FF_METHOD_CONTEXT(#name); \ + type target; \ + converter::unwrap(&target, value); \ + Nan::ObjectWrap::Unwrap(info.This())->prop = target; \ + } + namespace FF { template static inline v8::Local stdVecToJSArray(std::vector vec) { @@ -140,4 +166,4 @@ namespace FF { } } -#endif \ No newline at end of file +#endif From 4ecb4e80579c2eba94c008583c49ebff4875f6ce Mon Sep 17 00:00:00 2001 From: Nicholas Charbonneau Date: Sun, 22 Apr 2018 21:20:11 -0400 Subject: [PATCH 2/7] Facemark API implementation --- binding.gyp | 5 + cc/modules/face/Facemark.cc | 269 ++++++++++++++++++ cc/modules/face/Facemark.h | 55 ++++ cc/modules/face/FacemarkAAM.cc | 39 +++ cc/modules/face/FacemarkAAM.h | 23 ++ cc/modules/face/FacemarkAAMData.cc | 29 ++ cc/modules/face/FacemarkAAMData.h | 32 +++ cc/modules/face/FacemarkAAMParams.cc | 38 +++ cc/modules/face/FacemarkAAMParams.h | 43 +++ cc/modules/face/FacemarkLBF.cc | 39 +++ cc/modules/face/FacemarkLBF.h | 23 ++ cc/modules/face/FacemarkLBFParams.cc | 44 +++ cc/modules/face/FacemarkLBFParams.h | 78 +++++ cc/modules/face/face.cc | 23 +- lib/typings/Facemark.d.ts | 19 ++ lib/typings/FacemarkAAMParams.d.ts | 13 + lib/typings/FacemarkLBF.d.ts | 3 + lib/typings/FacemarkLBFParams.d.ts | 21 ++ lib/typings/FacemarkrAAM.d.ts | 3 + test/tests/modules/face/face.test.js | 80 +++--- .../modules/face/facemarkStructsTests.js | 69 +++++ test/tests/modules/face/facemarkTests.js | 144 ++++++++++ 22 files changed, 1054 insertions(+), 38 deletions(-) create mode 100644 cc/modules/face/Facemark.cc create mode 100644 cc/modules/face/Facemark.h create mode 100644 cc/modules/face/FacemarkAAM.cc create mode 100644 cc/modules/face/FacemarkAAM.h create mode 100644 cc/modules/face/FacemarkAAMData.cc create mode 100644 cc/modules/face/FacemarkAAMData.h create mode 100644 cc/modules/face/FacemarkAAMParams.cc create mode 100644 cc/modules/face/FacemarkAAMParams.h create mode 100644 cc/modules/face/FacemarkLBF.cc create mode 100644 cc/modules/face/FacemarkLBF.h create mode 100644 cc/modules/face/FacemarkLBFParams.cc create mode 100644 cc/modules/face/FacemarkLBFParams.h create mode 100644 lib/typings/Facemark.d.ts create mode 100644 lib/typings/FacemarkAAMParams.d.ts create mode 100644 lib/typings/FacemarkLBF.d.ts create mode 100644 lib/typings/FacemarkLBFParams.d.ts create mode 100644 lib/typings/FacemarkrAAM.d.ts create mode 100644 test/tests/modules/face/facemarkStructsTests.js create mode 100644 test/tests/modules/face/facemarkTests.js diff --git a/binding.gyp b/binding.gyp index 868e31705..b3caf889b 100644 --- a/binding.gyp +++ b/binding.gyp @@ -65,6 +65,11 @@ "cc/modules/face/EigenFaceRecognizer.cc", "cc/modules/face/FisherFaceRecognizer.cc", "cc/modules/face/LBPHFaceRecognizer.cc", + "cc/modules/face/Facemark.cc", + "cc/modules/face/FacemarkAAM.cc", + "cc/modules/face/FacemarkAAMParams.cc", + "cc/modules/face/FacemarkLBF.cc", + "cc/modules/face/FacemarkLBFParams.cc", "cc/modules/text/text.cc", "cc/modules/text/OCRHMMClassifier.cc", "cc/modules/text/OCRHMMDecoder.cc", diff --git a/cc/modules/face/Facemark.cc b/cc/modules/face/Facemark.cc new file mode 100644 index 000000000..eda79ec2f --- /dev/null +++ b/cc/modules/face/Facemark.cc @@ -0,0 +1,269 @@ +#ifdef HAVE_FACE + +#include "Facemark.h" +#include "FacemarkAAMData.h" + +void Facemark::Init(v8::Local ctor) { + Nan::SetPrototypeMethod(ctor, "addTrainingSample", AddTrainingSample); + Nan::SetPrototypeMethod(ctor, "addTrainingSampleAsync", + AddTrainingSampleAsync); + Nan::SetPrototypeMethod(ctor, "loadModel", LoadModel); + Nan::SetPrototypeMethod(ctor, "loadModelAsync", LoadModelAsync); + Nan::SetPrototypeMethod(ctor, "getData", GetData); + Nan::SetPrototypeMethod(ctor, "getDataAsync", GetDataAsync); + Nan::SetPrototypeMethod(ctor, "getFaces", GetFaces); + Nan::SetPrototypeMethod(ctor, "getFacesAsync", GetFacesAsync); + Nan::SetPrototypeMethod(ctor, "setFaceDetector", SetFaceDetector); + Nan::SetPrototypeMethod(ctor, "training", Training); + Nan::SetPrototypeMethod(ctor, "trainingAsync", TrainingAsync); + Nan::SetPrototypeMethod(ctor, "fit", Fit); + Nan::SetPrototypeMethod(ctor, "fitAsync", FitAsync); + Nan::SetPrototypeMethod(ctor, "save", Save); + Nan::SetPrototypeMethod(ctor, "load", Load); +}; + +struct Facemark::AddTrainingSampleWorker : public SimpleWorker { +public: + cv::Ptr self; + AddTrainingSampleWorker(cv::Ptr self) { + this->self = self; + } + + bool results; + cv::Mat image; + std::vector landmarks; + + const char *execute() { + results = self->addTrainingSample(image, landmarks); + return ""; + } + + v8::Local getReturnValue() { + v8::Local ret = Nan::New(results); + return ret; + } + + bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { + return (Mat::Converter::arg(0, &image, info) || + ObjectArrayConverter::arg( + 1, &landmarks, info)); + } +}; + +NAN_METHOD(Facemark::AddTrainingSample) { + AddTrainingSampleWorker worker( + FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_SYNC("Facemark::AddTrainingSample", worker); + info.GetReturnValue().Set(worker.getReturnValue()); +} + +NAN_METHOD(Facemark::AddTrainingSampleAsync) { + AddTrainingSampleWorker worker( + FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_ASYNC("Facemark::AddTrainingSampleAsync", AddTrainingSampleWorker, + worker); +} + +struct Facemark::LoadModelWorker : public SimpleWorker { +public: + cv::Ptr self; + LoadModelWorker(cv::Ptr self) { this->self = self; } + + std::string model; + + const char *execute() { + self->loadModel(model); + return ""; + } + + bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { + return (StringConverter::arg(0, &model, info)); + } +}; + +NAN_METHOD(Facemark::LoadModel) { + LoadModelWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_SYNC("Facemark::LoadModel", worker); + info.GetReturnValue().Set(worker.getReturnValue()); +} + +NAN_METHOD(Facemark::LoadModelAsync) { + LoadModelWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_ASYNC("Facemark::LoadModelAsync", LoadModelWorker, worker); +} + +struct Facemark::GetDataWorker : public SimpleWorker { +public: + cv::Ptr self; + GetDataWorker(cv::Ptr self) { this->self = self; } + + cv::face::FacemarkAAM::Data data; + + const char *execute() { + self->getData(&data); + return ""; + } + + v8::Local getReturnValue() { + v8::Local ret = InstanceConverter::wrap(data); + return ret; + } +}; + +NAN_METHOD(Facemark::GetData) { + GetDataWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_SYNC("Facemark::GetData", worker); + info.GetReturnValue().Set(worker.getReturnValue()); +} + +NAN_METHOD(Facemark::GetDataAsync) { + GetDataWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_ASYNC("Facemark::GetDataAsync", GetDataWorker, worker); +} + +struct Facemark::GetFacesWorker : public SimpleWorker { +public: + cv::Ptr self; + GetFacesWorker(cv::Ptr self) { this->self = self; } + + cv::Mat image; + std::vector faces; + + const char *execute() { + self->getFaces(image, faces); + return ""; + } + + v8::Local getReturnValue() { + v8::Local ret = + ObjectArrayConverter::wrap(faces); + return ret; + } + + bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { + return (Mat::Converter::arg(0, &image, info)); + } +}; + +NAN_METHOD(Facemark::GetFaces) { + GetFacesWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_SYNC("Facemark::GetFaces", worker); + info.GetReturnValue().Set(worker.getReturnValue()); +} + +NAN_METHOD(Facemark::GetFacesAsync) { + GetFacesWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_ASYNC("Facemark::GetFacesAsync", GetFacesWorker, worker); +} + +bool Facemark::detector(cv::InputArray image, cv::OutputArray faces, + Nan::Callback *callback) { + Nan::HandleScope scope; + + cv::Mat frame = image.getMat().clone(); + v8::Local jsMat = Mat::Converter::wrap(frame); + + v8::Local argv[] = {jsMat}; + FF_OBJ jsObject = callback->Call(1, argv)->ToObject(); + + std::vector _faces; + ObjectArrayConverter::unwrap(&_faces, jsObject); + + cv::Mat(_faces).copyTo(faces); + + return true; +} + +NAN_METHOD(Facemark::SetFaceDetector) { + FF_METHOD_CONTEXT("SetFaceDetector"); + + if (!info[0]->IsFunction()) { + return Nan::ThrowError(Nan::New("Facemark::SetFaceDetector - Error: " + "expected argument 0 to be of type") + .ToLocalChecked()); + } + + FF_ARG_FUNC(0, v8::Local cbFunc); + + Nan::Callback *callback = new Nan::Callback(cbFunc); + + bool results = FF_UNWRAP(info.This(), Facemark) + ->getFacemark() + ->setFaceDetector((cv::face::FN_FaceDetector)detector, callback); + + info.GetReturnValue().Set(Nan::New(results)); +} + +struct Facemark::TrainingWorker : public SimpleWorker { +public: + cv::Ptr self; + TrainingWorker(cv::Ptr self) { this->self = self; } + + const char *execute() { + self->training(); + return ""; + } +}; + +NAN_METHOD(Facemark::Training) { + TrainingWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_SYNC("Facemark::Train", worker); + info.GetReturnValue().Set(worker.getReturnValue()); +} + +NAN_METHOD(Facemark::TrainingAsync) { + TrainingWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_ASYNC("Facemark::TrainAsync", TrainingWorker, worker); +} + +struct Facemark::FitWorker : public SimpleWorker { +public: + cv::Ptr self; + FitWorker(cv::Ptr self) { this->self = self; } + + cv::Mat image; + std::vector faces; + std::vector> landmarks; + + const char *execute() { + self->fit(image, faces, landmarks); + return ""; + } + + v8::Local getReturnValue() { + v8::Local ret = + ObjectArrayOfArraysConverter::wrap( + landmarks); + return ret; + } + + bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { + return (Mat::Converter::arg(0, &image, info) || + ObjectArrayConverter::arg(1, &faces, info)); + } +}; + +NAN_METHOD(Facemark::Fit) { + FitWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_SYNC("Facemark::Fit", worker); + info.GetReturnValue().Set(worker.getReturnValue()); +} + +NAN_METHOD(Facemark::FitAsync) { + FitWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); + FF_WORKER_ASYNC("Facemark::FitAsync", FitWorker, worker); +} + +NAN_METHOD(Facemark::Save) { + FF_METHOD_CONTEXT("Facemark::Save"); + FF_ARG_STRING(0, std::string path); + FF_UNWRAP(info.This(), Facemark)->save(path); +} + +NAN_METHOD(Facemark::Load) { + FF_METHOD_CONTEXT("Facemark::Load"); + FF_ARG_STRING(0, std::string path); + FF_UNWRAP(info.This(), Facemark)->load(path); +} + +#endif diff --git a/cc/modules/face/Facemark.h b/cc/modules/face/Facemark.h new file mode 100644 index 000000000..dab8f00c1 --- /dev/null +++ b/cc/modules/face/Facemark.h @@ -0,0 +1,55 @@ +#include "Converters.h" +#include "Mat.h" +#include "Point.h" +#include "Rect.h" +#include "Workers.h" +#include "macros.h" +#include +#include + +#ifndef __FF_FACEMARK_H__ +#define __FF_FACEMARK_H__ + +class Facemark : public Nan::ObjectWrap { +public: + virtual cv::Ptr getFacemark() = 0; + virtual void save(std::string) = 0; + virtual void load(std::string) = 0; + + static void Init(v8::Local); + + struct AddTrainingSampleWorker; + static NAN_METHOD(AddTrainingSample); + static NAN_METHOD(AddTrainingSampleAsync); + + struct LoadModelWorker; + static NAN_METHOD(LoadModel); + static NAN_METHOD(LoadModelAsync); + + struct GetDataWorker; + static NAN_METHOD(GetData); + static NAN_METHOD(GetDataAsync); + + struct GetFacesWorker; + static NAN_METHOD(GetFaces); + static NAN_METHOD(GetFacesAsync); + + static bool detector(cv::InputArray image, cv::OutputArray faces, + Nan::Callback *callback); + + struct SetFaceDetectorWorker; + static NAN_METHOD(SetFaceDetector); + + struct TrainingWorker; + static NAN_METHOD(Training); + static NAN_METHOD(TrainingAsync); + + struct FitWorker; + static NAN_METHOD(Fit); + static NAN_METHOD(FitAsync); + + static NAN_METHOD(Save); + static NAN_METHOD(Load); +}; + +#endif diff --git a/cc/modules/face/FacemarkAAM.cc b/cc/modules/face/FacemarkAAM.cc new file mode 100644 index 000000000..eeb1cac1b --- /dev/null +++ b/cc/modules/face/FacemarkAAM.cc @@ -0,0 +1,39 @@ +#ifdef HAVE_FACE + +#include "FacemarkAAM.h" +#include "FacemarkAAMParams.h" + +Nan::Persistent FacemarkAAM::constructor; + +NAN_MODULE_INIT(FacemarkAAM::Init) { + v8::Local ctor = + Nan::New(FacemarkAAM::New); + v8::Local instanceTemplate = ctor->InstanceTemplate(); + + Facemark::Init(ctor); + constructor.Reset(ctor); + ctor->SetClassName(Nan::New("FacemarkAAM").ToLocalChecked()); + instanceTemplate->SetInternalFieldCount(1); + + target->Set(Nan::New("FacemarkAAM").ToLocalChecked(), ctor->GetFunction()); +}; + +NAN_METHOD(FacemarkAAM::New) { + FF_METHOD_CONTEXT("FacemarkAAM::New"); + + FF_ARG_INSTANCE_IFDEF( + 0, + cv::face::FacemarkAAM::Params params, + FacemarkAAMParams::constructor, + FF_UNWRAP_FACEMARKAAMPARAMS_AND_GET, + cv::face::FacemarkAAM::Params() + ); + + FacemarkAAM *self = new FacemarkAAM(); + self->Wrap(info.Holder()); + self->facemark = cv::face::FacemarkAAM::create(params); + + FF_RETURN(info.Holder()); +}; + +#endif diff --git a/cc/modules/face/FacemarkAAM.h b/cc/modules/face/FacemarkAAM.h new file mode 100644 index 000000000..56677fd1e --- /dev/null +++ b/cc/modules/face/FacemarkAAM.h @@ -0,0 +1,23 @@ +#include "Facemark.h" + +#ifndef __FF_FACEMARKAAM_H__ +#define __FF_FACEMARKAAM_H__ + +class FacemarkAAM : public Facemark { +public: + cv::Ptr facemark; + + void save(std::string path) { facemark->save(path); } + + void load(std::string path) { + cv::Algorithm::load(path); + } + + static NAN_MODULE_INIT(Init); + static NAN_METHOD(New); + + static Nan::Persistent constructor; + cv::Ptr getFacemark() { return facemark; } +}; + +#endif diff --git a/cc/modules/face/FacemarkAAMData.cc b/cc/modules/face/FacemarkAAMData.cc new file mode 100644 index 000000000..efc3c3ee6 --- /dev/null +++ b/cc/modules/face/FacemarkAAMData.cc @@ -0,0 +1,29 @@ +#ifdef HAVE_FACE + +#include "FacemarkAAMData.h" + +Nan::Persistent FacemarkAAMData::constructor; + +NAN_MODULE_INIT(FacemarkAAMData::Init) { + v8::Local ctor = + Nan::New(FacemarkAAMData::New); + v8::Local instanceTemplate = ctor->InstanceTemplate(); + + constructor.Reset(ctor); + ctor->SetClassName(FF_NEW_STRING("FacemarkAAMData")); + instanceTemplate->SetInternalFieldCount(1); + + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("s0"), s0Get, s0Set); + + target->Set(FF_NEW_STRING("FacemarkAAMData"), ctor->GetFunction()); +}; + +NAN_METHOD(FacemarkAAMData::New) { + FF_METHOD_CONTEXT("FacemarkAAMData::New"); + FacemarkAAMData *self = new FacemarkAAMData(); + self->data = cv::face::FacemarkAAM::Data(); + self->Wrap(info.Holder()); + FF_RETURN(info.Holder()); +}; + +#endif diff --git a/cc/modules/face/FacemarkAAMData.h b/cc/modules/face/FacemarkAAMData.h new file mode 100644 index 000000000..35c478143 --- /dev/null +++ b/cc/modules/face/FacemarkAAMData.h @@ -0,0 +1,32 @@ +#include "macros.h" +#include "Converters.h" +#include "Point2.h" +#include +#include + +#ifndef __FF_FACEMARKAAMDATA_H__ +#define __FF_FACEMARKAAMDATA_H__ + +typedef ObjectArrayConverter s0_converter; + +class FacemarkAAMData : public Nan::ObjectWrap { +public: + cv::face::FacemarkAAM::Data data; + + static NAN_MODULE_INIT(Init); + static NAN_METHOD(New); + + static FF_GETTER_COMPLEX(FacemarkAAMData, s0Get, data.s0, s0_converter); + static FF_SETTER_COMPLEX(FacemarkAAMData, s0, data.s0, std::vector, s0_converter); + + static Nan::Persistent constructor; + + cv::face::FacemarkAAM::Data* getNativeObjectPtr() { return &data; } + cv::face::FacemarkAAM::Data getNativeObject() { return data; } +}; + +#define FF_UNWRAP_FACEMARKAAMDATA(obj) FF_UNWRAP(obj, FacemarkAAMData) +#define FF_UNWRAP_FACEMARKAAMDATA_AND_GET(obj) \ + FF_UNWRAP_FACEMARKAAMDATA(obj)->data + +#endif diff --git a/cc/modules/face/FacemarkAAMParams.cc b/cc/modules/face/FacemarkAAMParams.cc new file mode 100644 index 000000000..93b1f4c05 --- /dev/null +++ b/cc/modules/face/FacemarkAAMParams.cc @@ -0,0 +1,38 @@ +#ifdef HAVE_FACE + +#include "FacemarkAAMParams.h" + +Nan::Persistent FacemarkAAMParams::constructor; + +NAN_MODULE_INIT(FacemarkAAMParams::Init) { + v8::Local ctor = + Nan::New(FacemarkAAMParams::New); + v8::Local instanceTemplate = ctor->InstanceTemplate(); + + constructor.Reset(ctor); + ctor->SetClassName(FF_NEW_STRING("FacemarkAAMParams")); + instanceTemplate->SetInternalFieldCount(1); + + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("m"), mGet, mSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("maxM"), maxMGet, maxMSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("maxN"), maxNGet, maxNSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("modelFilename"), modelFilenameGet, modelFilenameSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("n"), nGet, nSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("nIter"), nIterGet, nIterSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("saveModel"), saveModelGet, saveModelSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("scales"), scalesGet, scalesSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("textureMaxM"), textureMaxMGet, textureMaxMSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("verbose"), verboseGet, verboseSet); + + target->Set(FF_NEW_STRING("FacemarkAAMParams"), ctor->GetFunction()); +}; + +NAN_METHOD(FacemarkAAMParams::New) { + FF_METHOD_CONTEXT("FacemarkAAMParams::New"); + FacemarkAAMParams *self = new FacemarkAAMParams(); + self->params = cv::face::FacemarkAAM::Params(); + self->Wrap(info.Holder()); + FF_RETURN(info.Holder()); +}; + +#endif diff --git a/cc/modules/face/FacemarkAAMParams.h b/cc/modules/face/FacemarkAAMParams.h new file mode 100644 index 000000000..f78ffba3d --- /dev/null +++ b/cc/modules/face/FacemarkAAMParams.h @@ -0,0 +1,43 @@ +#include "macros.h" +#include "Converters.h" +#include + +#ifndef __FF_FACEMARKAAMPARAMS_H__ +#define __FF_FACEMARKAAMPARAMS_H__ + +class FacemarkAAMParams : public Nan::ObjectWrap { +public: + cv::face::FacemarkAAM::Params params; + + static NAN_MODULE_INIT(Init); + static NAN_METHOD(New); + + static FF_GETTER(FacemarkAAMParams, mGet, params.m); + static FF_SETTER_INT(FacemarkAAMParams, m, params.m); + static FF_GETTER(FacemarkAAMParams, maxMGet, params.max_m); + static FF_SETTER_INT(FacemarkAAMParams, maxM, params.max_m); + static FF_GETTER(FacemarkAAMParams, maxNGet, params.max_n); + static FF_SETTER_INT(FacemarkAAMParams, maxN, params.max_n); + static FF_GETTER_SIMPLE(FacemarkAAMParams, modelFilenameGet, params.model_filename, StringConverter); + static FF_SETTER_SIMPLE(FacemarkAAMParams, modelFilename, params.model_filename, StringConverter); + static FF_GETTER(FacemarkAAMParams, nGet, params.n); + static FF_SETTER_INT(FacemarkAAMParams, n, params.n); + static FF_GETTER(FacemarkAAMParams, nIterGet, params.n_iter); + static FF_SETTER_INT(FacemarkAAMParams, nIter, params.n_iter); + static FF_GETTER(FacemarkAAMParams, saveModelGet, params.save_model); + static FF_SETTER_BOOL(FacemarkAAMParams, saveModel, params.save_model); + static FF_GETTER_COMPLEX(FacemarkAAMParams, scalesGet, params.scales, FloatArrayConverter); + static FF_SETTER_COMPLEX(FacemarkAAMParams, scales, params.scales, std::vector, FloatArrayConverter); + static FF_GETTER(FacemarkAAMParams, textureMaxMGet, params.texture_max_m); + static FF_SETTER_INT(FacemarkAAMParams, textureMaxM, params.texture_max_m); + static FF_GETTER(FacemarkAAMParams, verboseGet, params.verbose); + static FF_SETTER_BOOL(FacemarkAAMParams, verbose, params.verbose); + + static Nan::Persistent constructor; +}; + +#define FF_UNWRAP_FACEMARKAAMPARAMS(obj) FF_UNWRAP(obj, FacemarkAAMParams) +#define FF_UNWRAP_FACEMARKAAMPARAMS_AND_GET(obj) \ + FF_UNWRAP_FACEMARKAAMPARAMS(obj)->params + +#endif diff --git a/cc/modules/face/FacemarkLBF.cc b/cc/modules/face/FacemarkLBF.cc new file mode 100644 index 000000000..a7e736964 --- /dev/null +++ b/cc/modules/face/FacemarkLBF.cc @@ -0,0 +1,39 @@ +#ifdef HAVE_FACE + +#include "FacemarkLBF.h" +#include "FacemarkLBFParams.h" + +Nan::Persistent FacemarkLBF::constructor; + +NAN_MODULE_INIT(FacemarkLBF::Init) { + v8::Local ctor = + Nan::New(FacemarkLBF::New); + v8::Local instanceTemplate = ctor->InstanceTemplate(); + + Facemark::Init(ctor); + constructor.Reset(ctor); + ctor->SetClassName(Nan::New("FacemarkLBF").ToLocalChecked()); + instanceTemplate->SetInternalFieldCount(1); + + target->Set(Nan::New("FacemarkLBF").ToLocalChecked(), ctor->GetFunction()); +}; + +NAN_METHOD(FacemarkLBF::New) { + FF_METHOD_CONTEXT("FacemarkLBF::New"); + + FF_ARG_INSTANCE_IFDEF( + 0, + cv::face::FacemarkLBF::Params params, + FacemarkLBFParams::constructor, + FF_UNWRAP_FACEMARKLBFPARAMS_AND_GET, + cv::face::FacemarkLBF::Params() + ); + + FacemarkLBF *self = new FacemarkLBF(); + self->Wrap(info.Holder()); + self->facemark = cv::face::FacemarkLBF::create(params); + + FF_RETURN(info.Holder()); +}; + +#endif diff --git a/cc/modules/face/FacemarkLBF.h b/cc/modules/face/FacemarkLBF.h new file mode 100644 index 000000000..1de44fe4c --- /dev/null +++ b/cc/modules/face/FacemarkLBF.h @@ -0,0 +1,23 @@ +#include "Facemark.h" + +#ifndef __FF_FACEMARKLBF_H__ +#define __FF_FACEMARKLBF_H__ + +class FacemarkLBF : public Facemark { +public: + cv::Ptr facemark; + + void save(std::string path) { facemark->save(path); } + + void load(std::string path) { + cv::Algorithm::load(path); + } + + static NAN_MODULE_INIT(Init); + static NAN_METHOD(New); + + static Nan::Persistent constructor; + cv::Ptr getFacemark() { return facemark; } +}; + +#endif diff --git a/cc/modules/face/FacemarkLBFParams.cc b/cc/modules/face/FacemarkLBFParams.cc new file mode 100644 index 000000000..77f2cdf7c --- /dev/null +++ b/cc/modules/face/FacemarkLBFParams.cc @@ -0,0 +1,44 @@ +#ifdef HAVE_FACE + +#include "FacemarkLBFParams.h" + +Nan::Persistent FacemarkLBFParams::constructor; + +NAN_MODULE_INIT(FacemarkLBFParams::Init) { + v8::Local ctor = + Nan::New(FacemarkLBFParams::New); + v8::Local instanceTemplate = ctor->InstanceTemplate(); + + constructor.Reset(ctor); + ctor->SetClassName(FF_NEW_STRING("FacemarkLBFParams")); + instanceTemplate->SetInternalFieldCount(1); + + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("baggingOverlap"), baggingOverlapGet, baggingOverlapSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("cascadeFace"), cascadeFaceGet, cascadeFaceSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("detectROI"), detectROIGet, detectROISet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("featsM"), featsMGet, featsMSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("initShapeN"), initShapeNGet, initShapeNSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("modelFilename"), modelFilenameGet, modelFilenameSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("nLandmarks"), nLandmarksGet, nLandmarksSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("pupils"), pupilsGet, pupilsSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("radiusM"), radiusMGet, radiusMSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("saveModel"), saveModelGet, saveModelSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("seed"), seedGet, seedSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("shapeOffset"), shapeOffsetGet, shapeOffsetSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("stagesN"), stagesNGet, stagesNSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("treeDepth"), treeDepthGet, treeDepthSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("treeN"), treeNGet, treeNSet); + Nan::SetAccessor(instanceTemplate, FF_NEW_STRING("verbose"), verboseGet, verboseSet); + + target->Set(FF_NEW_STRING("FacemarkLBFParams"), ctor->GetFunction()); +}; + +NAN_METHOD(FacemarkLBFParams::New) { + FF_METHOD_CONTEXT("FacemarkLBFParams::New"); + FacemarkLBFParams *self = new FacemarkLBFParams(); + self->params = cv::face::FacemarkLBF::Params(); + self->Wrap(info.Holder()); + FF_RETURN(info.Holder()); +}; + +#endif diff --git a/cc/modules/face/FacemarkLBFParams.h b/cc/modules/face/FacemarkLBFParams.h new file mode 100644 index 000000000..517c169e7 --- /dev/null +++ b/cc/modules/face/FacemarkLBFParams.h @@ -0,0 +1,78 @@ +#include "macros.h" +#include "Converters.h" +#include "Rect.h" +#include + +#ifndef __FF_FACEMARKLBFPARAMS_H__ +#define __FF_FACEMARKLBFPARAMS_H__ + +class FacemarkLBFParams : public Nan::ObjectWrap { +public: + cv::face::FacemarkLBF::Params params; + + static NAN_MODULE_INIT(Init); + static NAN_METHOD(New); + + static FF_GETTER(FacemarkLBFParams, baggingOverlapGet, params.bagging_overlap); + static FF_SETTER_NUMBER(FacemarkLBFParams, baggingOverlap, params.bagging_overlap); + static FF_GETTER_SIMPLE(FacemarkLBFParams, cascadeFaceGet, params.cascade_face, StringConverter); + static FF_SETTER_SIMPLE(FacemarkLBFParams, cascadeFace, params.cascade_face, StringConverter); + static FF_GETTER_SIMPLE(FacemarkLBFParams, detectROIGet, params.detectROI, Rect::Converter); + static FF_SETTER_SIMPLE(FacemarkLBFParams, detectROI, params.detectROI, Rect::Converter); + static FF_GETTER_COMPLEX(FacemarkLBFParams, featsMGet, params.feats_m, IntArrayConverter); + static FF_SETTER_COMPLEX(FacemarkLBFParams, featsM, params.feats_m, std::vector, IntArrayConverter); + static FF_GETTER(FacemarkLBFParams, initShapeNGet, params.initShape_n); + static FF_SETTER_INT(FacemarkLBFParams, initShapeN, params.initShape_n); + static FF_GETTER_SIMPLE(FacemarkLBFParams, modelFilenameGet, params.model_filename, StringConverter); + static FF_SETTER_SIMPLE(FacemarkLBFParams, modelFilename, params.model_filename, StringConverter); + static FF_GETTER(FacemarkLBFParams, nLandmarksGet, params.n_landmarks); + static FF_SETTER_INT(FacemarkLBFParams, nLandmarks, params.n_landmarks); + + static NAN_GETTER(pupilsGet) { + v8::Local jsArr = Nan::New(2); + for (int i = 0; i < jsArr->Length(); i++) { + jsArr->Set(i, ArrayConverterType::wrap( + Nan::ObjectWrap::Unwrap(info.This())->params.pupils[i]) + ); + } + info.GetReturnValue().Set(jsArr); + } + + static NAN_SETTER(pupilsSet) { + FF_METHOD_CONTEXT("pupils"); + v8::Local jsArr = v8::Local::Cast(value); + for (int i = 0; i < jsArr->Length(); i++) { + std::vector vec; + Nan::TryCatch tryCatch; + if (ArrayConverterType::unwrap(&vec, jsArr->Get(i))) { + tryCatch.ReThrow(); + } + Nan::ObjectWrap::Unwrap(info.This())->params.pupils[i] = vec; + } + } + + static FF_GETTER_COMPLEX(FacemarkLBFParams, radiusMGet, params.radius_m, DoubleArrayConverter); + static FF_SETTER_COMPLEX(FacemarkLBFParams, radiusM, params.radius_m, std::vector, DoubleArrayConverter); + static FF_GETTER(FacemarkLBFParams, saveModelGet, params.save_model); + static FF_SETTER_BOOL(FacemarkLBFParams, saveModel, params.save_model); + static FF_GETTER(FacemarkLBFParams, seedGet, params.seed); + static FF_SETTER_UINT(FacemarkLBFParams, seed, params.seed); + static FF_GETTER(FacemarkLBFParams, shapeOffsetGet, params.shape_offset); + static FF_SETTER_NUMBER(FacemarkLBFParams, shapeOffset, params.shape_offset); + static FF_GETTER(FacemarkLBFParams, stagesNGet, params.stages_n); + static FF_SETTER_INT(FacemarkLBFParams, stagesN, params.stages_n); + static FF_GETTER(FacemarkLBFParams, treeDepthGet, params.tree_depth); + static FF_SETTER_INT(FacemarkLBFParams, treeDepth, params.tree_depth); + static FF_GETTER(FacemarkLBFParams, treeNGet, params.tree_n); + static FF_SETTER_INT(FacemarkLBFParams, treeN, params.tree_n); + static FF_GETTER(FacemarkLBFParams, verboseGet, params.verbose); + static FF_SETTER_BOOL(FacemarkLBFParams, verbose, params.verbose); + + static Nan::Persistent constructor; +}; + +#define FF_UNWRAP_FACEMARKLBFPARAMS(obj) FF_UNWRAP(obj, FacemarkLBFParams) +#define FF_UNWRAP_FACEMARKLBFPARAMS_AND_GET(obj) \ + FF_UNWRAP_FACEMARKLBFPARAMS(obj)->params + +#endif diff --git a/cc/modules/face/face.cc b/cc/modules/face/face.cc index 658f4cfc1..a388cfd79 100644 --- a/cc/modules/face/face.cc +++ b/cc/modules/face/face.cc @@ -5,10 +5,25 @@ #include "FisherFaceRecognizer.h" #include "LBPHFaceRecognizer.h" +#if CV_VERSION_MINOR >= 4 +#include "FacemarkAAM.h" +#include "FacemarkAAMData.h" +#include "FacemarkAAMParams.h" +#include "FacemarkLBF.h" +#include "FacemarkLBFParams.h" +#endif + NAN_MODULE_INIT(Face::Init) { - EigenFaceRecognizer::Init(target); - FisherFaceRecognizer::Init(target); - LBPHFaceRecognizer::Init(target); + EigenFaceRecognizer::Init(target); + FisherFaceRecognizer::Init(target); + LBPHFaceRecognizer::Init(target); +#if CV_VERSION_MINOR >= 4 + FacemarkAAM::Init(target); + FacemarkAAMData::Init(target); + FacemarkAAMParams::Init(target); + FacemarkLBF::Init(target); + FacemarkLBFParams::Init(target); +#endif }; -#endif \ No newline at end of file +#endif diff --git a/lib/typings/Facemark.d.ts b/lib/typings/Facemark.d.ts new file mode 100644 index 000000000..fce3c7930 --- /dev/null +++ b/lib/typings/Facemark.d.ts @@ -0,0 +1,19 @@ +import { Mat } from "./Mat.d"; +import { Rect } from "./Rect.d"; +import { Point2 } from "./Point2.d"; + +export class Facemark { + addTrainingSample(image: Mat, landmarks: number[][]): boolean; + addTrainingSampleAsync(image: Mat, landmarks: number[][]): Promise; + loadModel(model: string): void; + loadModelAsync(model: string): Promise; + getFaces(image: Mat): Rect[]; + getFacesAsync(image: Mat): Promise; + setFaceDetector(callback: Function): boolean; + training(): void; + trainingAsync(): Promise; + fit(image: Mat, faces: Rect[]): Point2[][]; + fitAsync(image: Mat, faces: Rect[]): Promise; + save(file: string): void; + load(file: string): void; +} diff --git a/lib/typings/FacemarkAAMParams.d.ts b/lib/typings/FacemarkAAMParams.d.ts new file mode 100644 index 000000000..af99fd30e --- /dev/null +++ b/lib/typings/FacemarkAAMParams.d.ts @@ -0,0 +1,13 @@ +export class FacemarkAAMParams { + readonly m: number; + readonly maxM: number; + readonly maxN: number; + readonly modelFilename: string; + readonly n: number; + readonly nIter: number; + readonly saveModel: boolean; + readonly scales: number[]; + readonly textureMaxM: number; + readonly verbose: boolean; + constructor(); +} diff --git a/lib/typings/FacemarkLBF.d.ts b/lib/typings/FacemarkLBF.d.ts new file mode 100644 index 000000000..adf6485ab --- /dev/null +++ b/lib/typings/FacemarkLBF.d.ts @@ -0,0 +1,3 @@ +import { Facemark } from "./Facemark"; + +export class FacemarkLBF extends Facemark {} diff --git a/lib/typings/FacemarkLBFParams.d.ts b/lib/typings/FacemarkLBFParams.d.ts new file mode 100644 index 000000000..95aef54bd --- /dev/null +++ b/lib/typings/FacemarkLBFParams.d.ts @@ -0,0 +1,21 @@ +import { Rect } from "./Rect.d"; + +export class FacemarkLBFParams { + readonly baggingOverlap: number; + readonly cascadeFace: string; + readonly detectROI: Rect; + readonly featsM: number[]; + readonly initShapeN: number; + readonly modelFilename: string; + readonly nLandmarks: number; + readonly pupils: number[]; + readonly radiusM: number[]; + readonly saveModel: boolean; + readonly seed: number; + readonly shapeOffset: number; + readonly stagesN: number; + readonly treeDepth: number; + readonly treeN: number; + readonly verbose: boolean; + constructor(); +} diff --git a/lib/typings/FacemarkrAAM.d.ts b/lib/typings/FacemarkrAAM.d.ts new file mode 100644 index 000000000..31b50b4ae --- /dev/null +++ b/lib/typings/FacemarkrAAM.d.ts @@ -0,0 +1,3 @@ +import { Facemark } from "./Facemark"; + +export class FacemarkAAM extends Facemark {} diff --git a/test/tests/modules/face/face.test.js b/test/tests/modules/face/face.test.js index 5c156568e..4cdcb5b0b 100644 --- a/test/tests/modules/face/face.test.js +++ b/test/tests/modules/face/face.test.js @@ -1,34 +1,46 @@ -const cv = global.dut; -const { readTestImage } = global.utils; -const recognizerTests = require('./recognizerTests'); - -describe('face', () => { - if (!cv.xmodules.face) { - it('compiled without face'); - return; - } - - let testImg; - - before(() => { - testImg = readTestImage().resizeToMax(250); - }); - - describe('EigenFaceRecognizer', () => { - const args = ['num_components', 'threshold']; - const values = [10, 0.8]; - recognizerTests(() => testImg, args, values, cv.EigenFaceRecognizer); - }); - - describe('FisherFaceRecognizer', () => { - const args = ['num_components', 'threshold']; - const values = [10, 0.8]; - recognizerTests(() => testImg, args, values, cv.FisherFaceRecognizer); - }); - - describe('LBPHFaceRecognizer', () => { - const args = ['radius', 'neighbors', 'grid_x', 'grid_y']; - const values = [2, 16, 16, 16]; - recognizerTests(() => testImg, args, values, cv.LBPHFaceRecognizer); - }); -}); +const cv = global.dut; +const { readTestImage } = global.utils; +const recognizerTests = require('./recognizerTests'); +const facemarkTests = require('./facemarkTests'); +const facemarkStructsTests = require('./facemarkStructsTests'); + +describe('face', () => { + if (!cv.xmodules.face) { + it('compiled without face'); + return; + } + + let testImg; + + before(() => { + testImg = readTestImage().resizeToMax(250); + }); + + describe('EigenFaceRecognizer', () => { + const args = ['num_components', 'threshold']; + const values = [10, 0.8]; + recognizerTests(() => testImg, args, values, cv.EigenFaceRecognizer); + }); + + describe('FisherFaceRecognizer', () => { + const args = ['num_components', 'threshold']; + const values = [10, 0.8]; + recognizerTests(() => testImg, args, values, cv.FisherFaceRecognizer); + }); + + describe('LBPHFaceRecognizer', () => { + const args = ['radius', 'neighbors', 'grid_x', 'grid_y']; + const values = [2, 16, 16, 16]; + recognizerTests(() => testImg, args, values, cv.LBPHFaceRecognizer); + }); + + facemarkStructsTests(); + + describe('FacemarkLBF', () => { + facemarkTests(() => testImg, cv.FacemarkLBF, cv.FacemarkLBFParams); + }); + + describe('FacemarkAAM', () => { + facemarkTests(() => testImg, cv.FacemarkAAM, cv.FacemarkAAMParams); + }); +}); diff --git a/test/tests/modules/face/facemarkStructsTests.js b/test/tests/modules/face/facemarkStructsTests.js new file mode 100644 index 000000000..3a7be48cb --- /dev/null +++ b/test/tests/modules/face/facemarkStructsTests.js @@ -0,0 +1,69 @@ +const cv = global.dut; +const { assertPropsWithValue } = global.utils; + +module.exports = () => { + describe('Facemark structures', () => { + it('FacemarkAAMData', () => { + const data = { + s0: [new cv.Point2(0, 0), new cv.Point2(0, 0)] + }; + + const facemarkData = new cv.FacemarkAAMData(); + Object.keys(data).forEach((item) => { + facemarkData[item] = data[item]; + }); + + assertPropsWithValue(facemarkData)(data); + }); + + it('FacemarkAAMParams', () => { + const params = { + m: 10, + n: 10, + maxM: 30, + maxN: 30, + modelFilename: 'filename.xml', + nIter: 4, + saveModel: true, + scales: [3.0, 2.0], + textureMaxM: 12, + verbose: true + }; + + const facemarkParams = new cv.FacemarkAAMParams(); + Object.keys(params).forEach((param) => { + facemarkParams[param] = params[param]; + }); + + assertPropsWithValue(facemarkParams)(params); + }); + + it('FacemarkLBFParams', () => { + const params = { + baggingOverlap: 2.5, + cascadeFile: 'cascadeFile.xml', + detectROI: new cv.Rect(0, 0, 10, 10), + featsM: [5, 4, 3, 2, 1], + initShapeN: 32, + modelFilename: 'modelFilename.xml', + nLandmarks: 68, + pupils: [[1, 2, 3, 4], [4, 3, 2, 1]], + radiusM: [2.5, 5.5], + saveModel: true, + seed: 1000, + shapeOffset: 5.4, + stagesN: 4, + treeDepth: 3, + treeN: 2, + verbose: true + }; + + const facemarkParams = new cv.FacemarkLBFParams(); + Object.keys(params).forEach((param) => { + facemarkParams[param] = params[param]; + }); + + assertPropsWithValue(facemarkParams)(params); + }); + }); +}; diff --git a/test/tests/modules/face/facemarkTests.js b/test/tests/modules/face/facemarkTests.js new file mode 100644 index 000000000..1df5e054a --- /dev/null +++ b/test/tests/modules/face/facemarkTests.js @@ -0,0 +1,144 @@ +const cv = global.dut; +const { generateAPITests, clearTmpData, getTmpDataFilePath } = global.utils; +const { expect } = require('chai'); + +module.exports = (getTestImg, Facemark, FacemarkParams) => { + let testImg; + + before(() => { + testImg = getTestImg().bgrToGray(); + }); + + describe('constructor', () => { + it('is constructable without args', () => { + expect(() => new Facemark()).to.not.throw(); + }); + + it('is constructable from args', () => { + const params = new FacemarkParams(); + expect(() => new Facemark(params).to.not.throw()); + }); + }); + + describe('face detection tests', () => { + let facemark; + before(() => { + facemark = new Facemark(); + }); + + describe('setFaceDetector', () => { + const expectOutput = () => {}; + const callback = () => {}; + + generateAPITests({ + getDut: () => facemark, + methodName: 'setFaceDetector', + methodNameSpace: 'Facemark', + getRequiredArgs: () => [callback], + hasAsync: false, + expectOutput + }); + }); + + describe('getData', () => { + const expectOutput = () => {}; + + generateAPITests({ + getDut: () => facemark, + methodName: 'getData', + methodNameSpace: 'Facemark', + hasAsync: true, + expectOutput + }); + }); + + describe('getFaces', () => { + const expectOutput = () => {}; + + it('setFaceDetector', () => { + facemark.setFaceDetector(() => []); + }); + + generateAPITests({ + getDut: () => facemark, + methodName: 'getFaces', + methodNameSpace: 'Facemark', + getRequiredArgs: () => [testImg], + hasAsync: false, + expectOutput + }); + }); + }); + + describe('train', () => { + let facemark; + + const landmarks = []; + for (let i = 0; i < 68; i++) { + landmarks[i] = new cv.Point2(Math.random() * 250, Math.random() * 250); + } + + before(() => { + const params = new FacemarkParams(); + params.cascadeFace = '../lib/haarcascades/haarcascade_frontalcatface.xml'; + params.modelFilename = 'modelFilename.model'; + params.nLandmarks = 68; + params.initShapeN = 10; + params.stagesN = 5; + params.treeN = 6; + params.treeDepth = 5; + + facemark = new Facemark(params); + }); + + describe('addTrainingSample', () => { + generateAPITests({ + getDut: () => facemark, + methodName: 'addTrainingSample', + methodNameSpace: 'Facemark', + getRequiredArgs: () => [testImg, landmarks], + expectOutput: () => {} + }); + }); + }); + + describe('trained model tests', () => { + let facemark; + + before(() => { + facemark = new Facemark(); + }); + + describe('fit', () => { + const expectOutput = (res) => { + expect(res).to.be.an('array'); + }; + + const faces = []; + + generateAPITests({ + getDut: () => facemark, + methodName: 'fit', + methodNameSpace: 'Facemark', + getRequiredArgs: () => [testImg, faces], + expectOutput + }); + }); + + describe('save and load', () => { + beforeEach(() => { + clearTmpData(); + }); + afterEach(() => { + clearTmpData(); + }); + + it('should save and load from xml', () => { + const file = getTmpDataFilePath('testFacemark.xml'); + facemark.save(file); + const facemarkNew = new Facemark(); + facemarkNew.load(file); + }); + }); + }); +}; From 113a006615ee9c48d48c115f558c555a49589412 Mon Sep 17 00:00:00 2001 From: Nicholas Charbonneau Date: Mon, 23 Apr 2018 10:28:15 -0400 Subject: [PATCH 3/7] Updated Facemark API to match newer node utils --- binding.gyp | 1 + cc/modules/face/Facemark.cc | 275 +++++++++------------------- cc/modules/face/Facemark.h | 25 +-- cc/modules/face/FacemarkAAMData.h | 2 +- cc/modules/face/FacemarkAAMParams.h | 2 +- cc/modules/face/FacemarkBindings.h | 133 ++++++++++++++ cc/modules/face/FacemarkLBFParams.h | 3 +- 7 files changed, 231 insertions(+), 210 deletions(-) create mode 100644 cc/modules/face/FacemarkBindings.h diff --git a/binding.gyp b/binding.gyp index bff0d63f1..af9c0e399 100644 --- a/binding.gyp +++ b/binding.gyp @@ -68,6 +68,7 @@ "cc/modules/face/LBPHFaceRecognizer.cc", "cc/modules/face/Facemark.cc", "cc/modules/face/FacemarkAAM.cc", + "cc/modules/face/FacemarkAAMData.cc", "cc/modules/face/FacemarkAAMParams.cc", "cc/modules/face/FacemarkLBF.cc", "cc/modules/face/FacemarkLBFParams.cc", diff --git a/cc/modules/face/Facemark.cc b/cc/modules/face/Facemark.cc index eda79ec2f..277403e0a 100644 --- a/cc/modules/face/Facemark.cc +++ b/cc/modules/face/Facemark.cc @@ -1,7 +1,19 @@ #ifdef HAVE_FACE #include "Facemark.h" -#include "FacemarkAAMData.h" +#include "FacemarkBindings.h" + +NAN_METHOD(Facemark::Save) { + FF_METHOD_CONTEXT("Facemark::Save"); + FF_ARG_STRING(0, std::string path); + FF_UNWRAP(info.This(), Facemark)->save(path); +} + +NAN_METHOD(Facemark::Load) { + FF_METHOD_CONTEXT("Facemark::Load"); + FF_ARG_STRING(0, std::string path); + FF_UNWRAP(info.This(), Facemark)->load(path); +} void Facemark::Init(v8::Local ctor) { Nan::SetPrototypeMethod(ctor, "addTrainingSample", AddTrainingSample); @@ -22,156 +34,68 @@ void Facemark::Init(v8::Local ctor) { Nan::SetPrototypeMethod(ctor, "load", Load); }; -struct Facemark::AddTrainingSampleWorker : public SimpleWorker { -public: - cv::Ptr self; - AddTrainingSampleWorker(cv::Ptr self) { - this->self = self; - } - - bool results; - cv::Mat image; - std::vector landmarks; - - const char *execute() { - results = self->addTrainingSample(image, landmarks); - return ""; - } - - v8::Local getReturnValue() { - v8::Local ret = Nan::New(results); - return ret; - } - - bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { - return (Mat::Converter::arg(0, &image, info) || - ObjectArrayConverter::arg( - 1, &landmarks, info)); - } -}; - NAN_METHOD(Facemark::AddTrainingSample) { - AddTrainingSampleWorker worker( - FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_SYNC("Facemark::AddTrainingSample", worker); - info.GetReturnValue().Set(worker.getReturnValue()); + FF::SyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::AddTrainingSample", + info + ); } NAN_METHOD(Facemark::AddTrainingSampleAsync) { - AddTrainingSampleWorker worker( - FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_ASYNC("Facemark::AddTrainingSampleAsync", AddTrainingSampleWorker, - worker); + FF::AsyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::AddTrainingSampleAsync", + info + ); } -struct Facemark::LoadModelWorker : public SimpleWorker { -public: - cv::Ptr self; - LoadModelWorker(cv::Ptr self) { this->self = self; } - - std::string model; - - const char *execute() { - self->loadModel(model); - return ""; - } - - bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { - return (StringConverter::arg(0, &model, info)); - } -}; - NAN_METHOD(Facemark::LoadModel) { - LoadModelWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_SYNC("Facemark::LoadModel", worker); - info.GetReturnValue().Set(worker.getReturnValue()); + FF::SyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::LoadModel", + info + ); } NAN_METHOD(Facemark::LoadModelAsync) { - LoadModelWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_ASYNC("Facemark::LoadModelAsync", LoadModelWorker, worker); + FF::AsyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::LoadModelAsync", + info + ); } -struct Facemark::GetDataWorker : public SimpleWorker { -public: - cv::Ptr self; - GetDataWorker(cv::Ptr self) { this->self = self; } - - cv::face::FacemarkAAM::Data data; - - const char *execute() { - self->getData(&data); - return ""; - } - - v8::Local getReturnValue() { - v8::Local ret = InstanceConverter::wrap(data); - return ret; - } -}; - NAN_METHOD(Facemark::GetData) { - GetDataWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_SYNC("Facemark::GetData", worker); - info.GetReturnValue().Set(worker.getReturnValue()); + FF::SyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::GetData", + info + ); } NAN_METHOD(Facemark::GetDataAsync) { - GetDataWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_ASYNC("Facemark::GetDataAsync", GetDataWorker, worker); + FF::AsyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::GetDataAsync", + info + ); } -struct Facemark::GetFacesWorker : public SimpleWorker { -public: - cv::Ptr self; - GetFacesWorker(cv::Ptr self) { this->self = self; } - - cv::Mat image; - std::vector faces; - - const char *execute() { - self->getFaces(image, faces); - return ""; - } - - v8::Local getReturnValue() { - v8::Local ret = - ObjectArrayConverter::wrap(faces); - return ret; - } - - bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { - return (Mat::Converter::arg(0, &image, info)); - } -}; - NAN_METHOD(Facemark::GetFaces) { - GetFacesWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_SYNC("Facemark::GetFaces", worker); - info.GetReturnValue().Set(worker.getReturnValue()); + FF::SyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::GetFaces", + info + ); } NAN_METHOD(Facemark::GetFacesAsync) { - GetFacesWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_ASYNC("Facemark::GetFacesAsync", GetFacesWorker, worker); -} - -bool Facemark::detector(cv::InputArray image, cv::OutputArray faces, - Nan::Callback *callback) { - Nan::HandleScope scope; - - cv::Mat frame = image.getMat().clone(); - v8::Local jsMat = Mat::Converter::wrap(frame); - - v8::Local argv[] = {jsMat}; - FF_OBJ jsObject = callback->Call(1, argv)->ToObject(); - - std::vector _faces; - ObjectArrayConverter::unwrap(&_faces, jsObject); - - cv::Mat(_faces).copyTo(faces); - - return true; + FF::AsyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::GetFacesAsync", + info + ); } NAN_METHOD(Facemark::SetFaceDetector) { @@ -184,7 +108,6 @@ NAN_METHOD(Facemark::SetFaceDetector) { } FF_ARG_FUNC(0, v8::Local cbFunc); - Nan::Callback *callback = new Nan::Callback(cbFunc); bool results = FF_UNWRAP(info.This(), Facemark) @@ -194,76 +117,54 @@ NAN_METHOD(Facemark::SetFaceDetector) { info.GetReturnValue().Set(Nan::New(results)); } -struct Facemark::TrainingWorker : public SimpleWorker { -public: - cv::Ptr self; - TrainingWorker(cv::Ptr self) { this->self = self; } - - const char *execute() { - self->training(); - return ""; - } -}; - NAN_METHOD(Facemark::Training) { - TrainingWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_SYNC("Facemark::Train", worker); - info.GetReturnValue().Set(worker.getReturnValue()); + FF::SyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::Train", + info + ); } NAN_METHOD(Facemark::TrainingAsync) { - TrainingWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_ASYNC("Facemark::TrainAsync", TrainingWorker, worker); + FF::AsyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::TrainAsync", + info + ); } -struct Facemark::FitWorker : public SimpleWorker { -public: - cv::Ptr self; - FitWorker(cv::Ptr self) { this->self = self; } - - cv::Mat image; - std::vector faces; - std::vector> landmarks; - - const char *execute() { - self->fit(image, faces, landmarks); - return ""; - } - - v8::Local getReturnValue() { - v8::Local ret = - ObjectArrayOfArraysConverter::wrap( - landmarks); - return ret; - } - - bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { - return (Mat::Converter::arg(0, &image, info) || - ObjectArrayConverter::arg(1, &faces, info)); - } -}; - NAN_METHOD(Facemark::Fit) { - FitWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_SYNC("Facemark::Fit", worker); - info.GetReturnValue().Set(worker.getReturnValue()); + FF::SyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::Fit", + info + ); } NAN_METHOD(Facemark::FitAsync) { - FitWorker worker(FF_UNWRAP(info.This(), Facemark)->getFacemark()); - FF_WORKER_ASYNC("Facemark::FitAsync", FitWorker, worker); + FF::AsyncBinding( + std::make_shared(FF_UNWRAP(info.This(), Facemark)->getFacemark()), + "Facemark::FitAsync", + info + ); } -NAN_METHOD(Facemark::Save) { - FF_METHOD_CONTEXT("Facemark::Save"); - FF_ARG_STRING(0, std::string path); - FF_UNWRAP(info.This(), Facemark)->save(path); -} +bool Facemark::detector(cv::InputArray image, cv::OutputArray faces, + Nan::Callback *callback) { + Nan::HandleScope scope; -NAN_METHOD(Facemark::Load) { - FF_METHOD_CONTEXT("Facemark::Load"); - FF_ARG_STRING(0, std::string path); - FF_UNWRAP(info.This(), Facemark)->load(path); + cv::Mat frame = image.getMat().clone(); + v8::Local jsMat = Mat::Converter::wrap(frame); + + v8::Local argv[] = {jsMat}; + FF_OBJ jsObject = callback->Call(1, argv)->ToObject(); + + std::vector _faces; + ObjectArrayConverter::unwrap(&_faces, jsObject); + + cv::Mat(_faces).copyTo(faces); + + return true; } #endif diff --git a/cc/modules/face/Facemark.h b/cc/modules/face/Facemark.h index dab8f00c1..b6b536fe3 100644 --- a/cc/modules/face/Facemark.h +++ b/cc/modules/face/Facemark.h @@ -1,8 +1,7 @@ -#include "Converters.h" +#include "NativeNodeUtils.h" #include "Mat.h" #include "Point.h" #include "Rect.h" -#include "Workers.h" #include "macros.h" #include #include @@ -17,39 +16,25 @@ class Facemark : public Nan::ObjectWrap { virtual void load(std::string) = 0; static void Init(v8::Local); - - struct AddTrainingSampleWorker; + static NAN_METHOD(AddTrainingSample); static NAN_METHOD(AddTrainingSampleAsync); - - struct LoadModelWorker; static NAN_METHOD(LoadModel); static NAN_METHOD(LoadModelAsync); - - struct GetDataWorker; static NAN_METHOD(GetData); static NAN_METHOD(GetDataAsync); - - struct GetFacesWorker; static NAN_METHOD(GetFaces); static NAN_METHOD(GetFacesAsync); - - static bool detector(cv::InputArray image, cv::OutputArray faces, - Nan::Callback *callback); - - struct SetFaceDetectorWorker; static NAN_METHOD(SetFaceDetector); - - struct TrainingWorker; static NAN_METHOD(Training); static NAN_METHOD(TrainingAsync); - - struct FitWorker; static NAN_METHOD(Fit); static NAN_METHOD(FitAsync); - static NAN_METHOD(Save); static NAN_METHOD(Load); + + static bool detector(cv::InputArray image, cv::OutputArray faces, + Nan::Callback *callback); }; #endif diff --git a/cc/modules/face/FacemarkAAMData.h b/cc/modules/face/FacemarkAAMData.h index 35c478143..56bfa6716 100644 --- a/cc/modules/face/FacemarkAAMData.h +++ b/cc/modules/face/FacemarkAAMData.h @@ -1,5 +1,5 @@ #include "macros.h" -#include "Converters.h" +#include "ArrayConverters.h" #include "Point2.h" #include #include diff --git a/cc/modules/face/FacemarkAAMParams.h b/cc/modules/face/FacemarkAAMParams.h index f78ffba3d..9c43ce0db 100644 --- a/cc/modules/face/FacemarkAAMParams.h +++ b/cc/modules/face/FacemarkAAMParams.h @@ -1,5 +1,5 @@ #include "macros.h" -#include "Converters.h" +#include "TypeConverters.h" #include #ifndef __FF_FACEMARKAAMPARAMS_H__ diff --git a/cc/modules/face/FacemarkBindings.h b/cc/modules/face/FacemarkBindings.h new file mode 100644 index 000000000..b6f53a9e0 --- /dev/null +++ b/cc/modules/face/FacemarkBindings.h @@ -0,0 +1,133 @@ +#include "Facemark.h" +#include "FacemarkAAMData.h" + +#ifndef __FF_FACEMARKBINDINGS_H_ +#define __FF_FACEMARKBINDINGS_H_ + +namespace FacemarkBindings { + struct AddTrainingSampleWorker : public CatchCvExceptionWorker { + public: + cv::Ptr self; + AddTrainingSampleWorker(cv::Ptr self) { + this->self = self; + } + + bool results; + cv::Mat image; + std::vector landmarks; + + std::string executeCatchCvExceptionWorker() { + results = self->addTrainingSample(image, landmarks); + return ""; + } + + v8::Local getReturnValue() { + v8::Local ret = Nan::New(results); + return ret; + } + + bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { + return (Mat::Converter::arg(0, &image, info) || + ObjectArrayConverter::arg( + 1, &landmarks, info)); + } + }; + + struct LoadModelWorker : public CatchCvExceptionWorker { + public: + cv::Ptr self; + LoadModelWorker(cv::Ptr self) { this->self = self; } + + std::string model; + + std::string executeCatchCvExceptionWorker() { + self->loadModel(model); + return ""; + } + + bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { + return (StringConverter::arg(0, &model, info)); + } + }; + + struct GetDataWorker : public CatchCvExceptionWorker { + public: + cv::Ptr self; + GetDataWorker(cv::Ptr self) { this->self = self; } + + cv::face::FacemarkAAM::Data data; + + std::string executeCatchCvExceptionWorker() { + self->getData(&data); + return ""; + } + + v8::Local getReturnValue() { + v8::Local ret = InstanceConverter::wrap(data); + return ret; + } + }; + + struct GetFacesWorker : public CatchCvExceptionWorker { + public: + cv::Ptr self; + GetFacesWorker(cv::Ptr self) { this->self = self; } + + cv::Mat image; + std::vector faces; + + std::string executeCatchCvExceptionWorker() { + self->getFaces(image, faces); + return ""; + } + + v8::Local getReturnValue() { + v8::Local ret = + ObjectArrayConverter::wrap(faces); + return ret; + } + + bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { + return (Mat::Converter::arg(0, &image, info)); + } + }; + + struct TrainingWorker : public CatchCvExceptionWorker { + public: + cv::Ptr self; + TrainingWorker(cv::Ptr self) { this->self = self; } + + std::string executeCatchCvExceptionWorker() { + self->training(); + return ""; + } + }; + + struct FitWorker : public CatchCvExceptionWorker { + public: + cv::Ptr self; + FitWorker(cv::Ptr self) { this->self = self; } + + cv::Mat image; + std::vector faces; + std::vector> landmarks; + + std::string executeCatchCvExceptionWorker() { + self->fit(image, faces, landmarks); + return ""; + } + + v8::Local getReturnValue() { + v8::Local ret = + ObjectArrayOfArraysConverter::wrap( + landmarks); + return ret; + } + + bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) { + return (Mat::Converter::arg(0, &image, info) || + ObjectArrayConverter::arg(1, &faces, info)); + } + }; +} +#endif diff --git a/cc/modules/face/FacemarkLBFParams.h b/cc/modules/face/FacemarkLBFParams.h index 517c169e7..2a25fb85b 100644 --- a/cc/modules/face/FacemarkLBFParams.h +++ b/cc/modules/face/FacemarkLBFParams.h @@ -1,5 +1,6 @@ #include "macros.h" -#include "Converters.h" +#include "TypeConverters.h" +#include "ArrayConverters.h" #include "Rect.h" #include From ed1859b67a4cb2fae61ce1607b9cc35583e87011 Mon Sep 17 00:00:00 2001 From: Nicholas Charbonneau Date: Mon, 23 Apr 2018 10:31:34 -0400 Subject: [PATCH 4/7] makeCompareValues now compares objects --- test/utils/testUtils.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/utils/testUtils.js b/test/utils/testUtils.js index c068047fe..b38d06385 100644 --- a/test/utils/testUtils.js +++ b/test/utils/testUtils.js @@ -34,7 +34,10 @@ exports.assertError = assertError; const makeCompareValues = floatSafe => (val1, val2) => { if (floatSafe && typeof val1 === 'number' && typeof val2 === 'number') { return Math.abs(val1 - val2) < 0.001; - } + } else if (typeof val1 === 'object' && typeof val2 === 'object') { + return JSON.stringify(val1) === JSON.stringify(val2); + } + return val1 === val2; }; From bed0691b38aa2fc868cc3e719de8b6c32847e70d Mon Sep 17 00:00:00 2001 From: Nicholas Charbonneau Date: Tue, 24 Apr 2018 13:21:02 -0400 Subject: [PATCH 5/7] Facemark API example --- examples/facemark.js | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 examples/facemark.js diff --git a/examples/facemark.js b/examples/facemark.js new file mode 100644 index 000000000..db4d36c51 --- /dev/null +++ b/examples/facemark.js @@ -0,0 +1,47 @@ +const cv = require("../"); +const fs = require("fs"); +const path = require("path"); + +if (!cv.xmodules.face) { + throw new Error("exiting: opencv4nodejs compiled without face module"); +} + +const facemarkModelPath = "../data/face/"; +const modelFile = path.resolve(facemarkModelPath, "lbfmodel.yaml"); + +if (!fs.existsSync(modelFile)) { + console.log("could not find landmarks model"); + console.log( + "download the model from: https://raw.githubusercontent.com/kurnianggoro/GSOC2017/master/data/lbfmodel.yaml" + ); + throw new Error("exiting: could not find landmarks model"); +} + +const classifier = new cv.CascadeClassifier(cv.HAAR_FRONTALFACE_ALT2); + +// create the facemark object with the landmarks model +const facemark = new cv.FacemarkLBF(); +facemark.loadModel(modelFile); + +// give the facemark object it's face detection callback +facemark.setFaceDetector(frame => { + const { objects } = classifier.detectMultiScale(frame, 1.12); + return objects; +}); + +// retrieve faces using the facemark face detector callback +const image = cv.imread("../data/got.jpg"); +const gray = image.bgrToGray(); +const faces = facemark.getFaces(gray); + +// use the detected faces to detect the landmarks +const faceLandmarks = facemark.fit(gray, faces); + +for (let i = 0; i < faceLandmarks.length; i++) { + const landmarks = faceLandmarks[i]; + for (let x = 0; x < landmarks.length; x++) { + image.drawCircle(landmarks[x], 1, new cv.Vec(0, 255, 0), 1, cv.LINE_8); + } +} + +cv.imshowWait("VideoCapture", image); From 8d042295203f5cc2fdc0f36946b9d789d7313953 Mon Sep 17 00:00:00 2001 From: Nicholas Charbonneau Date: Tue, 24 Apr 2018 14:08:51 -0400 Subject: [PATCH 6/7] Facemark API fix build for older contrib versions --- cc/modules/face/Facemark.cc | 4 ++++ cc/modules/face/Facemark.h | 6 +++++- cc/modules/face/FacemarkAAM.cc | 4 ++++ cc/modules/face/FacemarkAAM.h | 4 ++++ cc/modules/face/FacemarkAAMData.cc | 4 ++++ cc/modules/face/FacemarkAAMData.h | 4 ++++ cc/modules/face/FacemarkAAMParams.cc | 4 ++++ cc/modules/face/FacemarkAAMParams.h | 4 ++++ cc/modules/face/FacemarkBindings.h | 5 +++++ cc/modules/face/FacemarkLBF.cc | 4 ++++ cc/modules/face/FacemarkLBF.h | 4 ++++ cc/modules/face/FacemarkLBFParams.cc | 4 ++++ cc/modules/face/FacemarkLBFParams.h | 4 ++++ 13 files changed, 54 insertions(+), 1 deletion(-) diff --git a/cc/modules/face/Facemark.cc b/cc/modules/face/Facemark.cc index 277403e0a..70d478fd7 100644 --- a/cc/modules/face/Facemark.cc +++ b/cc/modules/face/Facemark.cc @@ -3,6 +3,8 @@ #include "Facemark.h" #include "FacemarkBindings.h" +#if CV_VERSION_MINOR >= 4 + NAN_METHOD(Facemark::Save) { FF_METHOD_CONTEXT("Facemark::Save"); FF_ARG_STRING(0, std::string path); @@ -168,3 +170,5 @@ bool Facemark::detector(cv::InputArray image, cv::OutputArray faces, } #endif + +#endif diff --git a/cc/modules/face/Facemark.h b/cc/modules/face/Facemark.h index b6b536fe3..43de3cd27 100644 --- a/cc/modules/face/Facemark.h +++ b/cc/modules/face/Facemark.h @@ -6,6 +6,8 @@ #include #include +#if CV_VERSION_MINOR >= 4 + #ifndef __FF_FACEMARK_H__ #define __FF_FACEMARK_H__ @@ -16,7 +18,7 @@ class Facemark : public Nan::ObjectWrap { virtual void load(std::string) = 0; static void Init(v8::Local); - + static NAN_METHOD(AddTrainingSample); static NAN_METHOD(AddTrainingSampleAsync); static NAN_METHOD(LoadModel); @@ -38,3 +40,5 @@ class Facemark : public Nan::ObjectWrap { }; #endif + +#endif diff --git a/cc/modules/face/FacemarkAAM.cc b/cc/modules/face/FacemarkAAM.cc index eeb1cac1b..ef0085694 100644 --- a/cc/modules/face/FacemarkAAM.cc +++ b/cc/modules/face/FacemarkAAM.cc @@ -3,6 +3,8 @@ #include "FacemarkAAM.h" #include "FacemarkAAMParams.h" +#if CV_VERSION_MINOR >= 4 + Nan::Persistent FacemarkAAM::constructor; NAN_MODULE_INIT(FacemarkAAM::Init) { @@ -37,3 +39,5 @@ NAN_METHOD(FacemarkAAM::New) { }; #endif + +#endif diff --git a/cc/modules/face/FacemarkAAM.h b/cc/modules/face/FacemarkAAM.h index 56677fd1e..61351e25e 100644 --- a/cc/modules/face/FacemarkAAM.h +++ b/cc/modules/face/FacemarkAAM.h @@ -1,5 +1,7 @@ #include "Facemark.h" +#if CV_VERSION_MINOR >= 4 + #ifndef __FF_FACEMARKAAM_H__ #define __FF_FACEMARKAAM_H__ @@ -21,3 +23,5 @@ class FacemarkAAM : public Facemark { }; #endif + +#endif diff --git a/cc/modules/face/FacemarkAAMData.cc b/cc/modules/face/FacemarkAAMData.cc index efc3c3ee6..213296156 100644 --- a/cc/modules/face/FacemarkAAMData.cc +++ b/cc/modules/face/FacemarkAAMData.cc @@ -2,6 +2,8 @@ #include "FacemarkAAMData.h" +#if CV_VERSION_MINOR >= 4 + Nan::Persistent FacemarkAAMData::constructor; NAN_MODULE_INIT(FacemarkAAMData::Init) { @@ -27,3 +29,5 @@ NAN_METHOD(FacemarkAAMData::New) { }; #endif + +#endif diff --git a/cc/modules/face/FacemarkAAMData.h b/cc/modules/face/FacemarkAAMData.h index 56bfa6716..4d8b59465 100644 --- a/cc/modules/face/FacemarkAAMData.h +++ b/cc/modules/face/FacemarkAAMData.h @@ -4,6 +4,8 @@ #include #include +#if CV_VERSION_MINOR >= 4 + #ifndef __FF_FACEMARKAAMDATA_H__ #define __FF_FACEMARKAAMDATA_H__ @@ -30,3 +32,5 @@ class FacemarkAAMData : public Nan::ObjectWrap { FF_UNWRAP_FACEMARKAAMDATA(obj)->data #endif + +#endif diff --git a/cc/modules/face/FacemarkAAMParams.cc b/cc/modules/face/FacemarkAAMParams.cc index 93b1f4c05..9a30c0d98 100644 --- a/cc/modules/face/FacemarkAAMParams.cc +++ b/cc/modules/face/FacemarkAAMParams.cc @@ -2,6 +2,8 @@ #include "FacemarkAAMParams.h" +#if CV_VERSION_MINOR >= 4 + Nan::Persistent FacemarkAAMParams::constructor; NAN_MODULE_INIT(FacemarkAAMParams::Init) { @@ -36,3 +38,5 @@ NAN_METHOD(FacemarkAAMParams::New) { }; #endif + +#endif diff --git a/cc/modules/face/FacemarkAAMParams.h b/cc/modules/face/FacemarkAAMParams.h index 9c43ce0db..01282c60b 100644 --- a/cc/modules/face/FacemarkAAMParams.h +++ b/cc/modules/face/FacemarkAAMParams.h @@ -2,6 +2,8 @@ #include "TypeConverters.h" #include +#if CV_VERSION_MINOR >= 4 + #ifndef __FF_FACEMARKAAMPARAMS_H__ #define __FF_FACEMARKAAMPARAMS_H__ @@ -41,3 +43,5 @@ class FacemarkAAMParams : public Nan::ObjectWrap { FF_UNWRAP_FACEMARKAAMPARAMS(obj)->params #endif + +#endif diff --git a/cc/modules/face/FacemarkBindings.h b/cc/modules/face/FacemarkBindings.h index b6f53a9e0..57656b9d3 100644 --- a/cc/modules/face/FacemarkBindings.h +++ b/cc/modules/face/FacemarkBindings.h @@ -1,6 +1,8 @@ #include "Facemark.h" #include "FacemarkAAMData.h" +#if CV_VERSION_MINOR >= 4 + #ifndef __FF_FACEMARKBINDINGS_H_ #define __FF_FACEMARKBINDINGS_H_ @@ -130,4 +132,7 @@ namespace FacemarkBindings { } }; } + +#endif + #endif diff --git a/cc/modules/face/FacemarkLBF.cc b/cc/modules/face/FacemarkLBF.cc index a7e736964..2ba5fcd3b 100644 --- a/cc/modules/face/FacemarkLBF.cc +++ b/cc/modules/face/FacemarkLBF.cc @@ -3,6 +3,8 @@ #include "FacemarkLBF.h" #include "FacemarkLBFParams.h" +#if CV_VERSION_MINOR >= 4 + Nan::Persistent FacemarkLBF::constructor; NAN_MODULE_INIT(FacemarkLBF::Init) { @@ -37,3 +39,5 @@ NAN_METHOD(FacemarkLBF::New) { }; #endif + +#endif diff --git a/cc/modules/face/FacemarkLBF.h b/cc/modules/face/FacemarkLBF.h index 1de44fe4c..ab621ecd9 100644 --- a/cc/modules/face/FacemarkLBF.h +++ b/cc/modules/face/FacemarkLBF.h @@ -1,5 +1,7 @@ #include "Facemark.h" +#if CV_VERSION_MINOR >= 4 + #ifndef __FF_FACEMARKLBF_H__ #define __FF_FACEMARKLBF_H__ @@ -21,3 +23,5 @@ class FacemarkLBF : public Facemark { }; #endif + +#endif diff --git a/cc/modules/face/FacemarkLBFParams.cc b/cc/modules/face/FacemarkLBFParams.cc index 77f2cdf7c..1dc97ada5 100644 --- a/cc/modules/face/FacemarkLBFParams.cc +++ b/cc/modules/face/FacemarkLBFParams.cc @@ -2,6 +2,8 @@ #include "FacemarkLBFParams.h" +#if CV_VERSION_MINOR >= 4 + Nan::Persistent FacemarkLBFParams::constructor; NAN_MODULE_INIT(FacemarkLBFParams::Init) { @@ -42,3 +44,5 @@ NAN_METHOD(FacemarkLBFParams::New) { }; #endif + +#endif diff --git a/cc/modules/face/FacemarkLBFParams.h b/cc/modules/face/FacemarkLBFParams.h index 2a25fb85b..bb3cd86f1 100644 --- a/cc/modules/face/FacemarkLBFParams.h +++ b/cc/modules/face/FacemarkLBFParams.h @@ -4,6 +4,8 @@ #include "Rect.h" #include +#if CV_VERSION_MINOR >= 4 + #ifndef __FF_FACEMARKLBFPARAMS_H__ #define __FF_FACEMARKLBFPARAMS_H__ @@ -77,3 +79,5 @@ class FacemarkLBFParams : public Nan::ObjectWrap { FF_UNWRAP_FACEMARKLBFPARAMS(obj)->params #endif + +#endif From d7f444476ac9f06529a79b99f1e4e6608a94a98f Mon Sep 17 00:00:00 2001 From: Nicholas Charbonneau Date: Tue, 24 Apr 2018 14:41:48 -0400 Subject: [PATCH 7/7] Stripped old artifacts from previous merge --- cc/macros.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/cc/macros.h b/cc/macros.h index 28bfc6704..e7a542614 100644 --- a/cc/macros.h +++ b/cc/macros.h @@ -122,15 +122,4 @@ static FF_FUNC_TYPE ff_func = FF_FUNC_TYPE(); Nan::ObjectWrap::Unwrap(info.This())->prop = target; \ } -namespace FF { - template - static inline v8::Local stdVecToJSArray(std::vector vec) { - v8::Local jsArray = Nan::New(vec.size()); - for (int i = 0; i < jsArray->Length(); i++) { - jsArray->Set(i, Nan::New((toType)vec.at(i))); - } - return jsArray; - } -} - #endif