#include "FaceRecognizer.h" #include "OpenCV.h" #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4 #include "Matrix.h" #include #define EIGEN 0 #define LBPH 1 #define FISHER 2 // Todo, move somewhere useful cv::Mat fromMatrixOrFilename(Local v){ cv::Mat im; if (v->IsString()){ std::string filename = std::string(*NanAsciiString(v->ToString())); im = cv::imread(filename); //std::cout<< im.size(); } else { Matrix *img = ObjectWrap::Unwrap(v->ToObject()); im = img->mat; } return im; } void AsyncPredict(uv_work_t *req); void AfterAsyncPredict(uv_work_t *req); Persistent FaceRecognizerWrap::constructor; void FaceRecognizerWrap::Init(Handle target) { NanScope(); // Constructor Local ctor = NanNew(FaceRecognizerWrap::New); NanAssignPersistent(constructor, ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); ctor->SetClassName(NanNew("FaceRecognizer")); NODE_SET_METHOD(ctor, "createLBPHFaceRecognizer", CreateLBPH); NODE_SET_METHOD(ctor, "createEigenFaceRecognizer", CreateEigen); NODE_SET_METHOD(ctor, "createFisherFaceRecognizer", CreateFisher); NODE_SET_PROTOTYPE_METHOD(ctor, "trainSync", TrainSync); NODE_SET_PROTOTYPE_METHOD(ctor, "updateSync", UpdateSync); NODE_SET_PROTOTYPE_METHOD(ctor, "predictSync", PredictSync); NODE_SET_PROTOTYPE_METHOD(ctor, "saveSync", SaveSync); NODE_SET_PROTOTYPE_METHOD(ctor, "loadSync", LoadSync); NODE_SET_PROTOTYPE_METHOD(ctor, "getMat", GetMat); target->Set(NanNew("FaceRecognizer"), ctor->GetFunction()); }; NAN_METHOD(FaceRecognizerWrap::New) { NanScope(); if (args.This()->InternalFieldCount() == 0) JSTHROW_TYPE("Cannot Instantiate without new") // By default initialize LBPH cv::Ptr f = cv::createLBPHFaceRecognizer(1, 8, 8, 8, 80.0); FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, LBPH); pt->Wrap(args.This()); NanReturnValue(args.This()); } NAN_METHOD(FaceRecognizerWrap::CreateLBPH) { NanScope(); int radius = 1; int neighbors = 8; int grid_x = 8; int grid_y = 8; double threshold = 80; INT_FROM_ARGS(radius, 0) INT_FROM_ARGS(neighbors, 1) INT_FROM_ARGS(grid_x, 2) INT_FROM_ARGS(grid_y, 3) DOUBLE_FROM_ARGS(threshold, 4) Local n = NanNew(FaceRecognizerWrap::constructor)->GetFunction()->NewInstance(); cv::Ptr f = cv::createLBPHFaceRecognizer( radius, neighbors, grid_x, grid_y, threshold ); FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, LBPH); pt->Wrap(n); NanReturnValue( n ); } NAN_METHOD(FaceRecognizerWrap::CreateEigen) { NanScope(); int components = 0; double threshold = DBL_MAX; INT_FROM_ARGS(components, 0) DOUBLE_FROM_ARGS(threshold, 1) Local n = NanNew(FaceRecognizerWrap::constructor)->GetFunction()->NewInstance(); cv::Ptr f = cv::createEigenFaceRecognizer( components, threshold ); FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, EIGEN); pt->Wrap(n); NanReturnValue( n ); } NAN_METHOD(FaceRecognizerWrap::CreateFisher) { NanScope(); int components = 0; double threshold = DBL_MAX; INT_FROM_ARGS(components, 0) DOUBLE_FROM_ARGS(threshold, 1) Local n = NanNew(FaceRecognizerWrap::constructor)->GetFunction()->NewInstance(); cv::Ptr f = cv::createFisherFaceRecognizer( components, threshold ); FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, FISHER); pt->Wrap(n); NanReturnValue( n ); } FaceRecognizerWrap::FaceRecognizerWrap(cv::Ptr f, int type){ rec = f; typ = type; } Handle UnwrapTrainingData(_NAN_METHOD_ARGS_TYPE args, cv::vector* images, cv::vector* labels){ if (args.Length() < 1 || !args[0]->IsArray()){ JSTHROW("FaceRecognizer.train takes a list of [ label, image] tuples") } // Iterate through [[label, image], ...] etc, and add matrix / label to vectors //const //Local tuples = v8::Array::Cast(*args[0]); const Local tuples = Local::Cast(args[0]); const uint32_t length = tuples->Length(); for (uint32_t i=0 ; i val = tuples->Get(i); if (!val->IsArray()){ JSTHROW("train takes a list of [label, image] tuples") } Local valarr = Local::Cast(val); if (valarr->Length() != 2 || !valarr->Get(0)->IsInt32()){ JSTHROW("train takes a list of [label, image] tuples") } int label = valarr->Get(0)->Uint32Value(); cv::Mat im = fromMatrixOrFilename(valarr->Get(1)); im = im.clone(); cv::cvtColor(im, im, CV_RGB2GRAY); labels->push_back(label); images->push_back(im); } return NanUndefined(); } NAN_METHOD(FaceRecognizerWrap::TrainSync){ SETUP_FUNCTION(FaceRecognizerWrap) cv::vector images; cv::vector labels; Handle exception = UnwrapTrainingData(args, &images, &labels); if (!exception->IsUndefined()){ NanReturnValue(exception);//FIXME: not too sure about returning exceptions like this } self->rec->train(images, labels); NanReturnUndefined(); } NAN_METHOD(FaceRecognizerWrap::UpdateSync){ SETUP_FUNCTION(FaceRecognizerWrap) if (self->typ == EIGEN){ JSTHROW("Eigen Recognizer does not support update") } if (self->typ == FISHER){ JSTHROW("Fisher Recognizer does not support update") } cv::vector images; cv::vector labels; Handle exception = UnwrapTrainingData(args, &images, &labels); if (!exception->IsUndefined()){ JSTHROW( exception ); } self->rec->update(images, labels); NanReturnUndefined(); } NAN_METHOD(FaceRecognizerWrap::PredictSync){ SETUP_FUNCTION(FaceRecognizerWrap) cv::Mat im = fromMatrixOrFilename(args[0]);//TODO CHECK! 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); v8::Local res = NanNew(); res->Set(NanNew("id"), NanNew(predictedLabel)); res->Set(NanNew("confidence"), NanNew(confidence)); NanReturnValue(res); } NAN_METHOD(FaceRecognizerWrap::SaveSync){ SETUP_FUNCTION(FaceRecognizerWrap) if (!args[0]->IsString()){ JSTHROW("Save takes a filename") } std::string filename = std::string(*NanAsciiString(args[0]->ToString())); self->rec->save(filename); NanReturnUndefined(); } NAN_METHOD(FaceRecognizerWrap::LoadSync){ SETUP_FUNCTION(FaceRecognizerWrap) if (!args[0]->IsString()){ JSTHROW("Load takes a filename") } std::string filename = std::string(*NanAsciiString(args[0]->ToString())); self->rec->load(filename); NanReturnUndefined(); } NAN_METHOD(FaceRecognizerWrap::GetMat){ SETUP_FUNCTION(FaceRecognizerWrap) if (!args[0]->IsString()){ JSTHROW("getMat takes a key") } std::string key = std::string(*NanAsciiString(args[0]->ToString())); cv::Mat m = self->rec->getMat(key); Local im = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); Matrix *img = ObjectWrap::Unwrap(im); img->mat = m; NanReturnValue( im ); } #endif // End version > 2.4