diff --git a/src/FaceRecognizer.cc b/src/FaceRecognizer.cc index 8de89c8..238a6af 100644 --- a/src/FaceRecognizer.cc +++ b/src/FaceRecognizer.cc @@ -24,9 +24,6 @@ cv::Mat fromMatrixOrFilename(Local v) { return im; } -void AsyncPredict(uv_work_t *req); -void AfterAsyncPredict(uv_work_t *req); - Nan::Persistent FaceRecognizerWrap::constructor; void FaceRecognizerWrap::Init(Local target) { @@ -43,8 +40,10 @@ void FaceRecognizerWrap::Init(Local target) { Nan::SetMethod(ctor, "createFisherFaceRecognizer", CreateFisher); Nan::SetPrototypeMethod(ctor, "trainSync", TrainSync); + Nan::SetPrototypeMethod(ctor, "train", Train); Nan::SetPrototypeMethod(ctor, "updateSync", UpdateSync); Nan::SetPrototypeMethod(ctor, "predictSync", PredictSync); + Nan::SetPrototypeMethod(ctor, "predict", Predict); Nan::SetPrototypeMethod(ctor, "saveSync", SaveSync); Nan::SetPrototypeMethod(ctor, "loadSync", LoadSync); @@ -147,7 +146,7 @@ Local UnwrapTrainingData(Nan::NAN_METHOD_ARGS_TYPE info, const Local tuples = Local::Cast(info[0]); const uint32_t length = tuples->Length(); - for (uint32_t i=0; i val = tuples->Get(i); if (!val->IsArray()) { @@ -178,7 +177,8 @@ NAN_METHOD(FaceRecognizerWrap::TrainSync) { Local exception = UnwrapTrainingData(info, &images, &labels); if (!exception->IsUndefined()) { - info.GetReturnValue().Set(exception); // FIXME: not too sure about returning exceptions like this + // FIXME: not too sure about returning exceptions like this + info.GetReturnValue().Set(exception); } self->rec->train(images, labels); @@ -186,6 +186,53 @@ NAN_METHOD(FaceRecognizerWrap::TrainSync) { return; } +class TrainASyncWorker: public Nan::AsyncWorker { +public: + TrainASyncWorker(Nan::Callback *callback, cv::Ptr rec, + cv::vector images, cv::vector labels) : + Nan::AsyncWorker(callback), + rec(rec), + images(images), + labels(labels) { + } + + ~TrainASyncWorker() { + } + + void Execute() { + this->rec->train(this->images, this->labels); + } + +private: + cv::Ptr rec; + cv::vector images; + cv::vector labels; +}; + +NAN_METHOD(FaceRecognizerWrap::Train) { + SETUP_FUNCTION(FaceRecognizerWrap) + + if (info.Length() < 2 || !(info[1]->IsFunction())) { + Nan::ThrowTypeError("Invalid number of arguments or invalid callback"); + } + + cv::vector images; + cv::vector labels; + + REQ_FUN_ARG(1, cb); + + Local exception = UnwrapTrainingData(info, &images, &labels); + if (!exception->IsUndefined()) { + // FIXME: not too sure about returning exceptions like this + info.GetReturnValue().Set(exception); + } + + Nan::Callback *callback = new Nan::Callback(cb.As()); + Nan::AsyncQueueWorker(new TrainASyncWorker(callback, self->rec, images, labels)); + + return; +} + NAN_METHOD(FaceRecognizerWrap::UpdateSync) { SETUP_FUNCTION(FaceRecognizerWrap) @@ -212,13 +259,15 @@ NAN_METHOD(FaceRecognizerWrap::UpdateSync) { NAN_METHOD(FaceRecognizerWrap::PredictSync) { SETUP_FUNCTION(FaceRecognizerWrap) + if (info.Length() < 1) { + Nan::ThrowTypeError("Invalid number of arguments"); + } + cv::Mat im = fromMatrixOrFilename(info[0]); // TODO CHECK! if (im.channels() == 3) { cv::cvtColor(im, im, CV_RGB2GRAY); } - // int predictedLabel = self->rec->predict(im); - int predictedLabel = -1; double confidence = 0.0; self->rec->predict(im, predictedLabel, confidence); @@ -230,6 +279,68 @@ NAN_METHOD(FaceRecognizerWrap::PredictSync) { info.GetReturnValue().Set(res); } +class PredictASyncWorker: public Nan::AsyncWorker { +public: + PredictASyncWorker(Nan::Callback *callback, cv::Ptr rec, cv::Mat im) : + Nan::AsyncWorker(callback), + rec(rec), + im(im) { + predictedLabel = -1; + confidence = 0.0; + } + + ~PredictASyncWorker() { + } + + void Execute() { + this->rec->predict(this->im, this->predictedLabel, this->confidence); + } + + void HandleOKCallback() { + Nan::HandleScope scope; + + v8::Local res = Nan::New(); + res->Set(Nan::New("id").ToLocalChecked(), Nan::New(predictedLabel)); + res->Set(Nan::New("confidence").ToLocalChecked(), Nan::New(confidence)); + + Local argv[] = { + res + }; + + Nan::TryCatch try_catch; + callback->Call(1, argv); + if (try_catch.HasCaught()) { + Nan::FatalException(try_catch); + } + } + +private: + cv::Ptr rec; + cv::Mat im; + int predictedLabel; + double confidence; +}; + +NAN_METHOD(FaceRecognizerWrap::Predict) { + SETUP_FUNCTION(FaceRecognizerWrap) + + if (info.Length() < 2 || !(info[1]->IsFunction())) { + Nan::ThrowTypeError("Invalid number of arguments or invalid callback"); + } + + REQ_FUN_ARG(1, cb); + + cv::Mat im = fromMatrixOrFilename(info[0]); + if (im.channels() == 3) { + cv::cvtColor(im, im, CV_RGB2GRAY); + } + + Nan::Callback *callback = new Nan::Callback(cb.As()); + Nan::AsyncQueueWorker(new PredictASyncWorker(callback, self->rec, im)); + + return; +} + NAN_METHOD(FaceRecognizerWrap::SaveSync) { SETUP_FUNCTION(FaceRecognizerWrap) if (!info[0]->IsString()) { diff --git a/src/FaceRecognizer.h b/src/FaceRecognizer.h index e4db0df..3afbf76 100644 --- a/src/FaceRecognizer.h +++ b/src/FaceRecognizer.h @@ -20,12 +20,12 @@ public: JSFUNC(CreateFisher) JSFUNC(TrainSync) - //JSFUNC(Train) + JSFUNC(Train) JSFUNC(UpdateSync) //JSFUNC(Update) JSFUNC(PredictSync) - // JSFUNC(Predict) + JSFUNC(Predict) //static void EIO_Predict(eio_req *req); //static int EIO_AfterPredict(eio_req *req);