From cbbbcbf87f5da7728dbb6891c0239df67c13b878 Mon Sep 17 00:00:00 2001 From: Jorge Lahoz Date: Mon, 1 Sep 2014 20:39:20 +0200 Subject: [PATCH 1/4] Extend binding functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added objects bindings from https://bitbucket.org/Lior/node-opencv like Algorithm, KeyPoint or Feature2D - Added new objects bindings like DMatch, DescriptorMatcher, … - Extend functions bindings of Matrix like convertHSVscale, boxFilter, type, equalizeHist, … - Added Node.js objects descriptions (prototype.inspect) for Keypoint and DMatch --- binding.gyp | 9 +- lib/opencv.js | 42 ++++ src/Algorithm.cc | 170 +++++++++++++ src/Algorithm.h | 19 ++ src/Contours.cc | 2 +- src/DMatch.cc | 94 +++++++ src/DMatch.h | 19 ++ src/DescriptorExtractor.cc | 65 +++++ src/DescriptorExtractor.h | 14 ++ src/DescriptorMatcher.cc | 184 ++++++++++++++ src/DescriptorMatcher.h | 16 ++ src/Feature2D.cc | 90 +++++++ src/Feature2D.h | 15 ++ src/FeatureDetector.cc | 70 ++++++ src/FeatureDetector.h | 14 ++ src/KeyPoint.cc | 124 +++++++++ src/KeyPoint.h | 22 ++ src/Matrix.cc | 502 ++++++++++--------------------------- src/Matrix.h | 37 +-- src/VideoCaptureWrap.cc | 54 ---- src/VideoCaptureWrap.h | 7 - src/init.cc | 16 +- 22 files changed, 1128 insertions(+), 457 deletions(-) create mode 100755 src/Algorithm.cc create mode 100755 src/Algorithm.h create mode 100755 src/DMatch.cc create mode 100755 src/DMatch.h create mode 100755 src/DescriptorExtractor.cc create mode 100755 src/DescriptorExtractor.h create mode 100755 src/DescriptorMatcher.cc create mode 100755 src/DescriptorMatcher.h create mode 100755 src/Feature2D.cc create mode 100755 src/Feature2D.h create mode 100755 src/FeatureDetector.cc create mode 100755 src/FeatureDetector.h create mode 100755 src/KeyPoint.cc create mode 100755 src/KeyPoint.h diff --git a/binding.gyp b/binding.gyp index 72df9f37..7dc739b3 100755 --- a/binding.gyp +++ b/binding.gyp @@ -12,7 +12,14 @@ , "src/CamShift.cc" , "src/HighGUI.cc" , "src/FaceRecognizer.cc" - , "src/BackgroundSubtractor.cc" + , "src/Algorithm.cc" + , "src/KeyPoint.cc" + , "src/DMatch.cc" + , "src/DescriptorExtractor.cc" + , "src/DescriptorMatcher.cc" + , "src/FeatureDetector.cc" + , "src/Feature2D.cc" + ] , 'libraries': [ ' Algorithm::constructor; + +void +Algorithm::Init(Handle target) { + HandleScope scope; + + // Constructor + constructor = Persistent::New(FunctionTemplate::New(Algorithm::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("Algorithm")); + + NODE_SET_PROTOTYPE_METHOD(constructor, "get", Get); + NODE_SET_PROTOTYPE_METHOD(constructor, "set", Set); + + target->Set(String::NewSymbol("Algorithm"), constructor->GetFunction()); +}; + +Handle +Algorithm::New(const Arguments &args) { + HandleScope scope; + + if (args.This()->InternalFieldCount() == 0) + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new"))); + + Algorithm *algorithm; + + if (args[0]->IsString()){ + algorithm = new Algorithm(std::string(*v8::String::AsciiValue(args[0]->ToString()))); + } else { + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("New gets one string parameter"))); + } + + algorithm->Wrap(args.This()); + + return args.This(); +} + +Local +Algorithm::NewInstance(){ + HandleScope scope; + + Local args[] = {}; + Local instance = constructor->GetFunction()->NewInstance(0, args); + return scope.Close(instance); +} + + +Algorithm::Algorithm(){ +} + +Algorithm::Algorithm(const std::string& type) { + HandleScope scope; + _algorithm = cv::Algorithm::create(type); +} + +Handle +Algorithm::Get(const Arguments &args) { + HandleScope scope; + + if (args.Length() != 1){ + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("You must provide a param name."))); + } + + Local paramName = args[0]; + std::string name = std::string(*v8::String::AsciiValue(paramName->ToString())); + Algorithm *self = ObjectWrap::Unwrap(args.This()); + + int paramType = self->_algorithm->paramType(name); + switch(paramType){ + case cv::Param::INT: + return scope.Close(Number::New(self->_algorithm->getInt(name))); + + case cv::Param::BOOLEAN: + return scope.Close(Boolean::New(self->_algorithm->getBool(name))); + + case cv::Param::REAL: + return scope.Close(Number::New(self->_algorithm->getDouble(name))); + + case cv::Param::STRING: + return scope.Close(String::New(self->_algorithm->getString(name).c_str())); + + case cv::Param::MAT: { + Local matrixObject = Matrix::constructor->GetFunction()->NewInstance(); + Matrix *matrix = ObjectWrap::Unwrap(matrixObject); + matrix->mat = self->_algorithm->getMat(name); + return scope.Close(matrixObject); + } + + case cv::Param::MAT_VECTOR: { + cv::vector mats = self->_algorithm->getMatVector(name); + Local array = Array::New(mats.size()); + for (unsigned long i=0; i matrixItemObject = Matrix::constructor->GetFunction()->NewInstance(); + Matrix *matrixItem = ObjectWrap::Unwrap(matrixItemObject); + matrixItem->mat = mat; + array->Set(i, matrixItemObject); + } + return scope.Close(array); + } + + case cv::Param::ALGORITHM: { + Local algorithmObject = Algorithm::NewInstance(); + Algorithm *algorithm = ObjectWrap::Unwrap(algorithmObject); + algorithm->_algorithm = self->_algorithm->getAlgorithm(name); + return scope.Close(algorithmObject); + } + } + + return scope.Close(v8::Null()); +} + +Handle +Algorithm::Set(const Arguments &args) { + HandleScope scope; + + if (args.Length() != 2){ + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Only 2 parameters are supported param name and param value."))); + } + + Local paramName = args[0]; + Local paramValue = args[1]; + + if (!paramName->IsString()){ + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("The param name must be stringand param value."))); + } + + std::string name = std::string(*v8::String::AsciiValue(paramName->ToString())); + Algorithm *self = ObjectWrap::Unwrap(args.This()); + + if (paramValue->IsInt32()){ + self->_algorithm->setInt(name, paramValue->IntegerValue()); + } else if (paramValue->IsNumber()){ + self->_algorithm->setDouble(name, paramValue->NumberValue()); + } else if (paramValue->IsBoolean()){ + self->_algorithm->setBool(name, paramValue->BooleanValue()); + } else if (paramValue->IsString()){ + self->_algorithm->setString(name, std::string(*v8::String::AsciiValue(paramValue->ToString()))); + } else if (paramValue->IsObject()){ + Matrix *matrix = ObjectWrap::Unwrap(paramValue->ToObject()); + Algorithm *algorithm = ObjectWrap::Unwrap(paramValue->ToObject()); + Array *array = ObjectWrap::Unwrap(paramValue->ToObject()); + if (matrix != NULL) { + self->_algorithm->setMat(name, matrix->mat); + } else if (algorithm != NULL) { + self->_algorithm->setAlgorithm(name, algorithm->_algorithm); + } else if (array != NULL){ + unsigned int length = array->Get(v8::String::New("length"))->ToObject()->Uint32Value(); + cv::vector mats; + for (unsigned int i=0; i(array->Get(i)->ToObject()); + if (item == NULL){ + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Unsupported param type, only Matrix is a supported item in array."))); + } + mats.push_back(item->mat); + } + self->_algorithm->setMatVector(name, mats); + } else { + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Unsupported param type"))); + } + } else { + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Unsupported param type"))); + } + + return scope.Close(v8::Null()); +} diff --git a/src/Algorithm.h b/src/Algorithm.h new file mode 100755 index 00000000..643072b9 --- /dev/null +++ b/src/Algorithm.h @@ -0,0 +1,19 @@ +#include "OpenCV.h" + +class Algorithm: public node::ObjectWrap { + public: + cv::Ptr _algorithm; + + static Persistent constructor; + static void Init(Handle target); + static Handle New(const Arguments &args); + static Local NewInstance(); + + Algorithm(const std::string& type); + + JSFUNC(Set) + JSFUNC(Get) + + protected: + Algorithm(); +}; \ No newline at end of file diff --git a/src/Contours.cc b/src/Contours.cc index b2f8d04e..2193c235 100755 --- a/src/Contours.cc +++ b/src/Contours.cc @@ -31,7 +31,7 @@ Contour::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "approxPolyDP", ApproxPolyDP); NODE_SET_PROTOTYPE_METHOD(constructor, "convexHull", ConvexHull); NODE_SET_PROTOTYPE_METHOD(constructor, "boundingRect", BoundingRect); - NODE_SET_PROTOTYPE_METHOD(constructor, "minAreaRect", MinAreaRect); + NODE_SET_PROTOTYPE_METHOD(constructor, "minAreaRect", BoundingRect); NODE_SET_PROTOTYPE_METHOD(constructor, "isConvex", IsConvex); NODE_SET_PROTOTYPE_METHOD(constructor, "moments", Moments); target->Set(String::NewSymbol("Contours"), m->GetFunction()); diff --git a/src/DMatch.cc b/src/DMatch.cc new file mode 100755 index 00000000..6a006870 --- /dev/null +++ b/src/DMatch.cc @@ -0,0 +1,94 @@ +#include "DMatch.h" + +v8::Persistent DMatch::constructor; + +void +DMatch::Init(Handle target) { + HandleScope scope; + + // Constructor + constructor = Persistent::New(FunctionTemplate::New(DMatch::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("DMatch")); + + // Prototype + Local proto = constructor->PrototypeTemplate(); + proto->SetAccessor(String::NewSymbol("queryIdx"), GetQueryIdx, RaiseImmutable); + proto->SetAccessor(String::NewSymbol("trainIdx"), GetTrainIdx, RaiseImmutable); + proto->SetAccessor(String::NewSymbol("imgIdx"), GetImgIdx, RaiseImmutable); + proto->SetAccessor(String::NewSymbol("distance"), GetDistance, RaiseImmutable); + + target->Set(String::NewSymbol("DMatch"), constructor->GetFunction()); +}; + +Handle +DMatch::New(const Arguments &args) { + HandleScope scope; + + if (args.This()->InternalFieldCount() == 0) + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new"))); + + int queryIdx = -1, trainIdx = -1, imgIdx = -1; + double distance = -1; + if (args[0]->IsNumber()) queryIdx = args[0]->NumberValue(); + if (args[1]->IsNumber()) trainIdx = args[1]->NumberValue(); + if (args[2]->IsNumber()) imgIdx = args[2]->NumberValue(); + if (args[3]->IsNumber()) distance = args[3]->NumberValue(); + + DMatch *dMatch = new DMatch(queryIdx, trainIdx, imgIdx, distance); + dMatch->Wrap(args.This()); + return args.This(); +} + +Local +DMatch::NewInstance(int queryIdx, int trainIdx, int imgIdx, float distance){ + HandleScope scope; + + Local args[4] = { + Number::New(queryIdx), + Number::New(trainIdx), + Number::New(imgIdx), + Number::New(distance) + }; + + Local instance = constructor->GetFunction()->NewInstance(4, args); + return scope.Close(instance); +} + +Handle +DMatch::GetQueryIdx(Local prop, const AccessorInfo &info) { + HandleScope scope; + DMatch *dMatch = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(dMatch->_dMatch.queryIdx)); +} + +Handle +DMatch::GetTrainIdx(Local prop, const AccessorInfo &info) { + HandleScope scope; + DMatch *dMatch = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(dMatch->_dMatch.trainIdx)); +} + +Handle +DMatch::GetImgIdx(Local prop, const AccessorInfo &info) { + HandleScope scope; + DMatch *dMatch = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(dMatch->_dMatch.imgIdx)); +} + +Handle +DMatch::GetDistance(Local prop, const AccessorInfo &info) { + HandleScope scope; + DMatch *dMatch = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(dMatch->_dMatch.distance)); +} + +void +DMatch::RaiseImmutable(Local property, Local value, const AccessorInfo& info) { + v8::ThrowException(v8::Exception::TypeError(v8::String::New("DMatch is immutable"))); +} + +DMatch::DMatch(int queryIdx, int trainIdx, int imgIdx, float distance): ObjectWrap() { + _dMatch = cv::DMatch(queryIdx, trainIdx, imgIdx, distance); +} + diff --git a/src/DMatch.h b/src/DMatch.h new file mode 100755 index 00000000..885c6537 --- /dev/null +++ b/src/DMatch.h @@ -0,0 +1,19 @@ +#include "OpenCV.h" + +class DMatch: public node::ObjectWrap { + public: + cv::DMatch _dMatch; + + static Persistent constructor; + static void Init(Handle target); + static Handle New(const Arguments &args); + static Local NewInstance(int queryIdx, int trainIdx, int imgIdx, float distance); + DMatch(int queryIdx, int trainIdx, int imgIdx, float distance); + + static Handle GetQueryIdx(Local prop, const AccessorInfo &info); + static Handle GetTrainIdx(Local prop, const AccessorInfo &info); + static Handle GetImgIdx(Local prop, const AccessorInfo &info); + static Handle GetDistance(Local prop, const AccessorInfo &info); + static void RaiseImmutable(Local property, Local value, const AccessorInfo& info); + +}; \ No newline at end of file diff --git a/src/DescriptorExtractor.cc b/src/DescriptorExtractor.cc new file mode 100755 index 00000000..1f36292a --- /dev/null +++ b/src/DescriptorExtractor.cc @@ -0,0 +1,65 @@ +#include "DescriptorExtractor.h" +#include "Matrix.h" +#include "KeyPoint.h" + +v8::Persistent DescriptorExtractor::constructor; + +void +DescriptorExtractor::Init(Handle target) { + HandleScope scope; + + // Constructor + constructor = Persistent::New(FunctionTemplate::New(DescriptorExtractor::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("DescriptorExtractor")); + + NODE_SET_PROTOTYPE_METHOD(constructor, "compute", Compute); + + target->Set(String::NewSymbol("DescriptorExtractor"), constructor->GetFunction()); +}; + +Handle +DescriptorExtractor::New(const Arguments &args) { + HandleScope scope; + + if (args.This()->InternalFieldCount() == 0) + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new"))); + + DescriptorExtractor *de; + + if (args[0]->IsString()){ + de = new DescriptorExtractor(std::string(*v8::String::AsciiValue(args[0]->ToString()))); + } else { + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("New gets one string parameter"))); + } + + de->Wrap(args.This()); + + return args.This(); +} + +DescriptorExtractor::DescriptorExtractor(const std::string& detectorType){ + HandleScope scope; + _de = cv::DescriptorExtractor::create(detectorType); +} + +Handle +DescriptorExtractor::Compute(const Arguments &args) { + HandleScope scope; + DescriptorExtractor *de = ObjectWrap::Unwrap(args.This()); + Matrix *image = ObjectWrap::Unwrap(args[0]->ToObject()); + Local keypointsArray = args[1]->ToObject(); + unsigned int length = keypointsArray->Get(v8::String::New("length"))->ToObject()->Uint32Value(); + cv::vector keypoints; + for (unsigned int i=0; i(keypointsArray->Get(i)->ToObject()); + keypoints.push_back(keypoint->_keyPoint); + } + + Local descriptorsMatrixObject = Matrix::constructor->GetFunction()->NewInstance(); + Matrix *descriptorsMatrix = ObjectWrap::Unwrap(descriptorsMatrixObject); + + de->_de->compute(image->mat, keypoints, descriptorsMatrix->mat); + + return scope.Close(descriptorsMatrixObject); +} diff --git a/src/DescriptorExtractor.h b/src/DescriptorExtractor.h new file mode 100755 index 00000000..9baff202 --- /dev/null +++ b/src/DescriptorExtractor.h @@ -0,0 +1,14 @@ +#include "OpenCV.h" + +class DescriptorExtractor: public node::ObjectWrap { + public: + cv::Ptr _de; + + static Persistent constructor; + static void Init(Handle target); + static Handle New(const Arguments &args); + + DescriptorExtractor(const std::string& detectorType); + + JSFUNC(Compute) +}; \ No newline at end of file diff --git a/src/DescriptorMatcher.cc b/src/DescriptorMatcher.cc new file mode 100755 index 00000000..3e84c7fe --- /dev/null +++ b/src/DescriptorMatcher.cc @@ -0,0 +1,184 @@ +#include "DescriptorMatcher.h" +#include "Matrix.h" +#include "KeyPoint.h" +#include "DMatch.h" + +v8::Persistent DescriptorMatcher::constructor; + +void +DescriptorMatcher::Init(Handle target) { + HandleScope scope; + + // Constructor + constructor = Persistent::New(FunctionTemplate::New(DescriptorMatcher::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("DescriptorMatcher")); + + NODE_SET_PROTOTYPE_METHOD(constructor, "match", Match); + NODE_SET_PROTOTYPE_METHOD(constructor, "knnMatch", KnnMatch); + NODE_SET_PROTOTYPE_METHOD(constructor, "radiusMatch", RadiusMatch); + + target->Set(String::NewSymbol("DescriptorMatcher"), constructor->GetFunction()); +}; + +Handle +DescriptorMatcher::New(const Arguments &args) { + HandleScope scope; + + if (args.This()->InternalFieldCount() == 0) + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new"))); + + DescriptorMatcher *dm; + + if (args[0]->IsString()){ + dm = new DescriptorMatcher(std::string(*v8::String::AsciiValue(args[0]->ToString()))); + } else { + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("New gets one string parameter"))); + } + + dm->Wrap(args.This()); + + return args.This(); +} + +DescriptorMatcher::DescriptorMatcher(const std::string& descriptorMatcherType){ + HandleScope scope; + _dm = cv::DescriptorMatcher::create(descriptorMatcherType); +} + + +/* + * match + * http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_descriptor_matchers.html?highlight=descriptormatcher#descriptormatcher-match + */ +Handle +DescriptorMatcher::Match(const Arguments &args) { + HandleScope scope; + DescriptorMatcher *dm = ObjectWrap::Unwrap(args.This()); + + Matrix *queryDescriptors = ObjectWrap::Unwrap(args[0]->ToObject()); + Matrix *trainDescriptors = ObjectWrap::Unwrap(args[1]->ToObject()); + Matrix *descriptorsMask = NULL; + if (args.Length()>2 && !(args[2]->IsNull()) && args[2]->IsObject()){ + descriptorsMask = ObjectWrap::Unwrap(args[2]->ToObject()); + } + cv::Mat descriptorsMaskMat = descriptorsMask != NULL ? descriptorsMask->mat : cv::Mat(); + + cv::vector descriptorMatches; + dm->_dm->match(queryDescriptors->mat, trainDescriptors->mat, descriptorMatches, descriptorsMaskMat); + + Local array = Array::New(descriptorMatches.size()); + for (unsigned long i=0; i dMatchWrap = DMatch::NewInstance( + dMatch.queryIdx, + dMatch.trainIdx, + dMatch.imgIdx, + dMatch.distance); + array->Set(i, dMatchWrap); + } + + return scope.Close(array); +} + + +/* + * knnMatch + * http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_descriptor_matchers.html?highlight=descriptormatcher#descriptormatcher-knnmatch + */ +Handle +DescriptorMatcher::KnnMatch(const Arguments &args) { + HandleScope scope; + DescriptorMatcher *dm = ObjectWrap::Unwrap(args.This()); + + Matrix *queryDescriptors = ObjectWrap::Unwrap(args[0]->ToObject()); + Matrix *trainDescriptors = ObjectWrap::Unwrap(args[1]->ToObject()); + int k = args[2]->IntegerValue(); + Matrix *descriptorsMask = NULL; + bool compactResult = false; + if (args.Length()>3 && !(args[3]->IsNull()) && args[3]->IsObject()){ + descriptorsMask = ObjectWrap::Unwrap(args[3]->ToObject()); + if (args.Length()>4) { + compactResult = (bool)args[4]->IntegerValue(); + } + } + cv::Mat descriptorsMaskMat = descriptorsMask != NULL ? descriptorsMask->mat : cv::Mat(); + + cv::vector< cv::vector > descriptorMatches; + if (descriptorsMask!=NULL) { + dm->_dm->knnMatch(queryDescriptors->mat, trainDescriptors->mat, descriptorMatches, k, descriptorsMaskMat, compactResult); + }else{ + dm->_dm->knnMatch(queryDescriptors->mat, trainDescriptors->mat, descriptorMatches, k, descriptorsMaskMat); + } + + Local array = Array::New(descriptorMatches.size()); + for (unsigned long i=0; i subarray = Array::New(descriptorMatches[i].size()); + for (unsigned long j=0; j dMatchWrap = DMatch::NewInstance( + dMatch.queryIdx, + dMatch.trainIdx, + dMatch.imgIdx, + dMatch.distance); + subarray->Set(j, dMatchWrap); + } + array->Set(i, subarray); + } + + return scope.Close(array); +} + + +/* + * radiusMatch + * http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_descriptor_matchers.html?highlight=descriptormatcher#descriptormatcher-radiusmatch + */ +Handle +DescriptorMatcher::RadiusMatch(const Arguments &args) { + HandleScope scope; + DescriptorMatcher *dm = ObjectWrap::Unwrap(args.This()); + + Matrix *queryDescriptors = ObjectWrap::Unwrap(args[0]->ToObject()); + Matrix *trainDescriptors = ObjectWrap::Unwrap(args[1]->ToObject()); + float maxDistance = args[2]->NumberValue(); + Matrix *descriptorsMask = NULL; + bool compactResult = false; + if (args.Length()>3 && !(args[3]->IsNull()) && args[3]->IsObject()){ + descriptorsMask = ObjectWrap::Unwrap(args[3]->ToObject()); + if (args.Length()>4) { + compactResult = (bool)args[4]->IntegerValue(); + } + } + cv::Mat descriptorsMaskMat = descriptorsMask != NULL ? descriptorsMask->mat : cv::Mat(); + + cv::vector< cv::vector > descriptorMatches; + if (descriptorsMask!=NULL) { + dm->_dm->radiusMatch(queryDescriptors->mat, trainDescriptors->mat, descriptorMatches, maxDistance, descriptorsMaskMat, compactResult); + }else{ + dm->_dm->radiusMatch(queryDescriptors->mat, trainDescriptors->mat, descriptorMatches, maxDistance, descriptorsMaskMat); + } + + Local array = Array::New(descriptorMatches.size()); + for (unsigned long i=0; i subarray = Array::New(descriptorMatches[i].size()); + for (unsigned long j=0; j dMatchWrap = DMatch::NewInstance( + dMatch.queryIdx, + dMatch.trainIdx, + dMatch.imgIdx, + dMatch.distance); + subarray->Set(j, dMatchWrap); + } + array->Set(i, subarray); + } + + return scope.Close(array); +} + diff --git a/src/DescriptorMatcher.h b/src/DescriptorMatcher.h new file mode 100755 index 00000000..b3bdb409 --- /dev/null +++ b/src/DescriptorMatcher.h @@ -0,0 +1,16 @@ +#include "OpenCV.h" + +class DescriptorMatcher: public node::ObjectWrap { + public: + cv::Ptr _dm; + + static Persistent constructor; + static void Init(Handle target); + static Handle New(const Arguments &args); + + DescriptorMatcher(const std::string& descriptorMatcherType); + + JSFUNC(Match) + JSFUNC(KnnMatch) + JSFUNC(RadiusMatch) +}; \ No newline at end of file diff --git a/src/Feature2D.cc b/src/Feature2D.cc new file mode 100755 index 00000000..4d50909a --- /dev/null +++ b/src/Feature2D.cc @@ -0,0 +1,90 @@ +#include "Feature2D.h" +#include "Matrix.h" +#include "KeyPoint.h" + +v8::Persistent Feature2D::constructor; + +void +Feature2D::Init(Handle target) { + HandleScope scope; + + // Constructor + constructor = Persistent::New(FunctionTemplate::New(Feature2D::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("Feature2D")); + + NODE_SET_PROTOTYPE_METHOD(constructor, "get", Algorithm::Get); + NODE_SET_PROTOTYPE_METHOD(constructor, "set", Algorithm::Set); + + NODE_SET_PROTOTYPE_METHOD(constructor, "detectAndCompute", DetectAndCompute); + + target->Set(String::NewSymbol("Feature2D"), constructor->GetFunction()); +}; + +Handle +Feature2D::New(const Arguments &args) { + HandleScope scope; + + if (args.This()->InternalFieldCount() == 0) + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new"))); + + Feature2D *f2d; + + if (args[0]->IsString()){ + f2d = new Feature2D(std::string(*v8::String::AsciiValue(args[0]->ToString()))); + } else { + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("New gets one string parameter"))); + } + + f2d->Wrap(args.This()); + + return args.This(); +} + +Feature2D::Feature2D(const std::string& detectorType) : Algorithm(){ + HandleScope scope; + _algorithm = cv::Feature2D::create(detectorType); +} + +Handle +Feature2D::DetectAndCompute(const Arguments &args) { + HandleScope scope; + Feature2D *f2d = ObjectWrap::Unwrap(args.This()); + if (args.Length() == 0){ + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("image parameter is missing"))); + } + Matrix *image = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::InputArray imageArray(image->mat); + + Matrix *imageMask = NULL; + if (args.Length() > 1 && !(args[1]->IsNull()) && args[1]->IsObject()){ + imageMask = ObjectWrap::Unwrap(args[1]->ToObject()); + } + cv::InputArray imageMaskArray = imageMask != NULL ? cv::InputArray(imageMask->mat) : cv::noArray(); + + cv::vector keypoints; + if (args.Length() > 2 && !(args[2]->IsNull()) && args[2]->IsObject()){ + Local keypointsArray = args[2]->ToObject(); + unsigned int length = keypointsArray->Get(v8::String::New("length"))->ToObject()->Uint32Value(); + for (unsigned int i=0; i(keypointsArray->Get(i)->ToObject()); + keypoints.push_back(keypoint->_keyPoint); + } + } + + Local descriptorsMatrixObject = Matrix::constructor->GetFunction()->NewInstance(); + Matrix *descriptorsMatrix = ObjectWrap::Unwrap(descriptorsMatrixObject); + cv::OutputArray descriptors(descriptorsMatrix->mat); + + f2d->GetFeature2D()->operator()(imageArray, + imageMaskArray, + keypoints, + descriptors, + keypoints.size() > 0); + + return scope.Close(descriptorsMatrixObject); +} + +cv::Ptr Feature2D::GetFeature2D(){ + return (cv::Ptr)_algorithm; +} diff --git a/src/Feature2D.h b/src/Feature2D.h new file mode 100755 index 00000000..9754dc00 --- /dev/null +++ b/src/Feature2D.h @@ -0,0 +1,15 @@ +#include "OpenCV.h" +#include "Algorithm.h" + +class Feature2D: public Algorithm{ + public: + cv::Ptr GetFeature2D(); + + static Persistent constructor; + static void Init(Handle target); + static Handle New(const Arguments &args); + + Feature2D(const std::string& detectorType); + + JSFUNC(DetectAndCompute) +}; \ No newline at end of file diff --git a/src/FeatureDetector.cc b/src/FeatureDetector.cc new file mode 100755 index 00000000..c34aa3e8 --- /dev/null +++ b/src/FeatureDetector.cc @@ -0,0 +1,70 @@ +#include "FeatureDetector.h" +#include "Matrix.h" +#include "KeyPoint.h" + +v8::Persistent FeatureDetector::constructor; + +void +FeatureDetector::Init(Handle target) { + HandleScope scope; + + // Constructor + constructor = Persistent::New(FunctionTemplate::New(FeatureDetector::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("FeatureDetector")); + + NODE_SET_PROTOTYPE_METHOD(constructor, "detect", Detect); + + target->Set(String::NewSymbol("FeatureDetector"), constructor->GetFunction()); +}; + +Handle +FeatureDetector::New(const Arguments &args) { + HandleScope scope; + + if (args.This()->InternalFieldCount() == 0) + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new"))); + + FeatureDetector *fd; + + if (args[0]->IsString()){ + fd = new FeatureDetector(std::string(*v8::String::AsciiValue(args[0]->ToString()))); + } else { + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("New gets one string parameter"))); + } + + fd->Wrap(args.This()); + + return args.This(); +} + +FeatureDetector::FeatureDetector(const std::string& detectorType){ + HandleScope scope; + _fd = cv::FeatureDetector::create(detectorType); +} + +Handle +FeatureDetector::Detect(const Arguments &args) { + HandleScope scope; + FeatureDetector *fd = ObjectWrap::Unwrap(args.This()); + Matrix *image = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::vector keypoints; + fd->_fd->detect(image->mat, keypoints); + + Local array = Array::New(keypoints.size()); + for (unsigned long i=0; i keyPointWrap = KeyPoint::NewInstance( + keyPoint.pt.x, + keyPoint.pt.y, + keyPoint.size, + keyPoint.angle, + keyPoint.response, + keyPoint.octave, + keyPoint.class_id); + array->Set(i, keyPointWrap); + } + + return scope.Close(array); +} diff --git a/src/FeatureDetector.h b/src/FeatureDetector.h new file mode 100755 index 00000000..2e60c05f --- /dev/null +++ b/src/FeatureDetector.h @@ -0,0 +1,14 @@ +#include "OpenCV.h" + +class FeatureDetector: public node::ObjectWrap { + public: + cv::Ptr _fd; + + static Persistent constructor; + static void Init(Handle target); + static Handle New(const Arguments &args); + + FeatureDetector(const std::string& detectorType); + + JSFUNC(Detect) +}; \ No newline at end of file diff --git a/src/KeyPoint.cc b/src/KeyPoint.cc new file mode 100755 index 00000000..6d42d5cd --- /dev/null +++ b/src/KeyPoint.cc @@ -0,0 +1,124 @@ +#include "KeyPoint.h" + +v8::Persistent KeyPoint::constructor; + +void +KeyPoint::Init(Handle target) { + HandleScope scope; + + // Constructor + constructor = Persistent::New(FunctionTemplate::New(KeyPoint::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("KeyPoint")); + + // Prototype + Local proto = constructor->PrototypeTemplate(); + proto->SetAccessor(String::NewSymbol("x"), GetX, RaiseImmutable); + proto->SetAccessor(String::NewSymbol("y"), GetY, RaiseImmutable); + proto->SetAccessor(String::NewSymbol("size"), GetY, RaiseImmutable); + proto->SetAccessor(String::NewSymbol("angle"), GetY, RaiseImmutable); + proto->SetAccessor(String::NewSymbol("response"), GetY, RaiseImmutable); + proto->SetAccessor(String::NewSymbol("octave"), GetY, RaiseImmutable); + proto->SetAccessor(String::NewSymbol("classId"), GetY, RaiseImmutable); + + target->Set(String::NewSymbol("KeyPoint"), constructor->GetFunction()); +}; + +Handle +KeyPoint::New(const Arguments &args) { + HandleScope scope; + + if (args.This()->InternalFieldCount() == 0) + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new"))); + + double x = 0, y = 0, size = 0, angle =-2, response = 0; + int octave = 0, classId = -1; + if (args[0]->IsNumber()) x = args[0]->NumberValue(); + if (args[1]->IsNumber()) y = args[1]->NumberValue(); + if (args[2]->IsNumber()) size = args[2]->NumberValue(); + if (args[3]->IsNumber()) angle = args[3]->NumberValue(); + if (args[4]->IsNumber()) response = args[4]->NumberValue(); + if (args[5]->IsNumber()) octave = (int)args[5]->NumberValue(); + if (args[6]->IsNumber()) classId = (int)args[6]->NumberValue(); + + KeyPoint *keyPoint = new KeyPoint(x, y, size, angle, response, octave, classId); + keyPoint->Wrap(args.This()); + return args.This(); +} + +Local +KeyPoint::NewInstance(float x, float y, float size, float angle, float response, int octave, int class_id){ + HandleScope scope; + + Local args[7] = { + Number::New(x), + Number::New(y), + Number::New(size), + Number::New(angle), + Number::New(response), + Number::New(octave), + Number::New(class_id) + }; + + Local instance = constructor->GetFunction()->NewInstance(7, args); + return scope.Close(instance); +} + +Handle +KeyPoint::GetX(Local prop, const AccessorInfo &info) { + HandleScope scope; + KeyPoint *keyPoint = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(keyPoint->_keyPoint.pt.x)); +} + +Handle +KeyPoint::GetY(Local prop, const AccessorInfo &info) { + HandleScope scope; + KeyPoint *keyPoint = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(keyPoint->_keyPoint.pt.y)); +} + +Handle +KeyPoint::GetSize(Local prop, const AccessorInfo &info) { + HandleScope scope; + KeyPoint *keyPoint = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(keyPoint->_keyPoint.size)); +} + +Handle +KeyPoint::GetAngle(Local prop, const AccessorInfo &info) { + HandleScope scope; + KeyPoint *keyPoint = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(keyPoint->_keyPoint.angle)); +} + +Handle +KeyPoint::GetResponse(Local prop, const AccessorInfo &info) { + HandleScope scope; + KeyPoint *keyPoint = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(keyPoint->_keyPoint.response)); +} + +Handle +KeyPoint::GetOctave(Local prop, const AccessorInfo &info) { + HandleScope scope; + KeyPoint *keyPoint = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(keyPoint->_keyPoint.octave)); +} + +Handle +KeyPoint::GetClassId(Local prop, const AccessorInfo &info) { + HandleScope scope; + KeyPoint *keyPoint = ObjectWrap::Unwrap(info.This()); + return scope.Close(Number::New(keyPoint->_keyPoint.class_id)); +} + +void +KeyPoint::RaiseImmutable(Local property, Local value, const AccessorInfo& info) { + v8::ThrowException(v8::Exception::TypeError(v8::String::New("KeyPoint is immutable"))); +} + +KeyPoint::KeyPoint(float x, float y, float size, float angle, float response, int octave, int class_id): ObjectWrap() { + _keyPoint = cv::KeyPoint(x, y, size, angle, response, octave, class_id); +} + diff --git a/src/KeyPoint.h b/src/KeyPoint.h new file mode 100755 index 00000000..26d25171 --- /dev/null +++ b/src/KeyPoint.h @@ -0,0 +1,22 @@ +#include "OpenCV.h" + +class KeyPoint: public node::ObjectWrap { + public: + cv::KeyPoint _keyPoint; + + static Persistent constructor; + static void Init(Handle target); + static Handle New(const Arguments &args); + static Local NewInstance(float x, float y, float size, float angle=-1, float response=0, int octave=0, int class_id=-1); + KeyPoint(float x, float y, float size, float angle=-1, float response=0, int octave=0, int class_id=-1); + + static Handle GetX(Local prop, const AccessorInfo &info); + static Handle GetY(Local prop, const AccessorInfo &info); + static Handle GetSize(Local prop, const AccessorInfo &info); + static Handle GetAngle(Local prop, const AccessorInfo &info); + static Handle GetResponse(Local prop, const AccessorInfo &info); + static Handle GetOctave(Local prop, const AccessorInfo &info); + static Handle GetClassId(Local prop, const AccessorInfo &info); + static void RaiseImmutable(Local property, Local value, const AccessorInfo& info); + +}; \ No newline at end of file diff --git a/src/Matrix.cc b/src/Matrix.cc index c94064f3..ca2d2333 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -51,15 +51,16 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "resize", Resize); NODE_SET_PROTOTYPE_METHOD(constructor, "rotate", Rotate); NODE_SET_PROTOTYPE_METHOD(constructor, "copyTo", CopyTo); + NODE_SET_PROTOTYPE_METHOD(constructor, "convertTo", ConvertTo); NODE_SET_PROTOTYPE_METHOD(constructor, "pyrDown", PyrDown); NODE_SET_PROTOTYPE_METHOD(constructor, "pyrUp", PyrUp); NODE_SET_PROTOTYPE_METHOD(constructor, "channels", Channels); + NODE_SET_PROTOTYPE_METHOD(constructor, "type", Type); NODE_SET_PROTOTYPE_METHOD(constructor, "convertGrayscale", ConvertGrayscale); - NODE_SET_PROTOTYPE_METHOD(constructor, "convertHSVscale", ConvertHSVscale); + NODE_SET_PROTOTYPE_METHOD(constructor, "convertHSVscale", ConvertHSVscale); NODE_SET_PROTOTYPE_METHOD(constructor, "gaussianBlur", GaussianBlur); - NODE_SET_PROTOTYPE_METHOD(constructor, "medianBlur", MedianBlur); - NODE_SET_PROTOTYPE_METHOD(constructor, "bilateralFilter", BilateralFilter); + NODE_SET_PROTOTYPE_METHOD(constructor, "boxFilter", BoxFilter); NODE_SET_PROTOTYPE_METHOD(constructor, "copy", Copy); NODE_SET_PROTOTYPE_METHOD(constructor, "flip", Flip); NODE_SET_PROTOTYPE_METHOD(constructor, "roi", ROI); @@ -67,19 +68,18 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "absDiff", AbsDiff); NODE_SET_PROTOTYPE_METHOD(constructor, "addWeighted", AddWeighted); NODE_SET_PROTOTYPE_METHOD(constructor, "bitwiseXor", BitwiseXor); - NODE_SET_PROTOTYPE_METHOD(constructor, "bitwiseNot", BitwiseNot); - NODE_SET_PROTOTYPE_METHOD(constructor, "bitwiseAnd", BitwiseAnd); NODE_SET_PROTOTYPE_METHOD(constructor, "countNonZero", CountNonZero); + //NODE_SET_PROTOTYPE_METHOD(constructor, "split", Split); NODE_SET_PROTOTYPE_METHOD(constructor, "canny", Canny); - NODE_SET_PROTOTYPE_METHOD(constructor, "dilate", Dilate); + NODE_SET_PROTOTYPE_METHOD(constructor, "dilate", Dilate); NODE_SET_PROTOTYPE_METHOD(constructor, "erode", Erode); NODE_SET_PROTOTYPE_METHOD(constructor, "findContours", FindContours); NODE_SET_PROTOTYPE_METHOD(constructor, "drawContour", DrawContour); NODE_SET_PROTOTYPE_METHOD(constructor, "drawAllContours", DrawAllContours); - NODE_SET_PROTOTYPE_METHOD(constructor, "goodFeaturesToTrack", GoodFeaturesToTrack); - NODE_SET_PROTOTYPE_METHOD(constructor, "houghLinesP", HoughLinesP); + NODE_SET_PROTOTYPE_METHOD(constructor, "goodFeaturesToTrack", GoodFeaturesToTrack); + NODE_SET_PROTOTYPE_METHOD(constructor, "houghLinesP", HoughLinesP); NODE_SET_PROTOTYPE_METHOD(constructor, "inRange", inRange); NODE_SET_PROTOTYPE_METHOD(constructor, "adjustROI", AdjustROI); @@ -88,31 +88,19 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "threshold", Threshold); NODE_SET_PROTOTYPE_METHOD(constructor, "adaptiveThreshold", AdaptiveThreshold); NODE_SET_PROTOTYPE_METHOD(constructor, "meanStdDev", MeanStdDev); - - NODE_SET_PROTOTYPE_METHOD(constructor, "cvtColor", CvtColor); - NODE_SET_PROTOTYPE_METHOD(constructor, "split", Split); - NODE_SET_PROTOTYPE_METHOD(constructor, "merge", Merge); - NODE_SET_PROTOTYPE_METHOD(constructor, "equalizeHist", EqualizeHist); + + NODE_SET_PROTOTYPE_METHOD(constructor, "cvtColor", CvtColor); + NODE_SET_PROTOTYPE_METHOD(constructor, "split", Split); + NODE_SET_PROTOTYPE_METHOD(constructor, "merge", Merge); + NODE_SET_PROTOTYPE_METHOD(constructor, "equalizeHist", EqualizeHist); NODE_SET_PROTOTYPE_METHOD(constructor, "floodFill", FloodFill); - NODE_SET_PROTOTYPE_METHOD(constructor, "matchTemplate", MatchTemplate); - NODE_SET_PROTOTYPE_METHOD(constructor, "minMaxLoc", MinMaxLoc); - - NODE_SET_PROTOTYPE_METHOD(constructor, "pushBack", PushBack); - - NODE_SET_PROTOTYPE_METHOD(constructor, "putText", PutText); - - NODE_SET_PROTOTYPE_METHOD(constructor, "getPerspectiveTransform", GetPerspectiveTransform); - NODE_SET_PROTOTYPE_METHOD(constructor, "warpPerspective", WarpPerspective); + NODE_SET_PROTOTYPE_METHOD(constructor, "matchTemplate", MatchTemplate); + NODE_SET_PROTOTYPE_METHOD(constructor, "minMaxLoc", MinMaxLoc); NODE_SET_METHOD(constructor, "Eye", Eye); - NODE_SET_PROTOTYPE_METHOD(constructor, "copyWithMask", CopyWithMask); - NODE_SET_PROTOTYPE_METHOD(constructor, "setWithMask", SetWithMask); - NODE_SET_PROTOTYPE_METHOD(constructor, "meanWithMask", MeanWithMask); - NODE_SET_PROTOTYPE_METHOD(constructor, "shift", Shift); - target->Set(String::NewSymbol("Matrix"), m->GetFunction()); }; @@ -397,6 +385,12 @@ Matrix::Channels(const Arguments& args){ return scope.Close(Number::New(self->mat.channels())); } +Handle +Matrix::Type(const Arguments& args){ + SETUP_FUNCTION(Matrix) + + return scope.Close(Number::New(self->mat.type())); +} Handle Matrix::ToBuffer(const v8::Arguments& args){ @@ -566,73 +560,27 @@ void AfterAsyncToBufferAsync(uv_work_t *req) { Handle Matrix::Ellipse(const v8::Arguments& args){ - SETUP_FUNCTION(Matrix) + SETUP_FUNCTION(Matrix) - int x = 0; - int y = 0; - int width = 0; - int height = 0; - cv::Scalar color(0, 0, 255); - int thickness = 1; - double angle = 0; - double startAngle = 0; - double endAngle = 360; - int lineType = 8; - int shift = 0; - - if(args[0]->IsObject()) { - v8::Handle options = v8::Handle::Cast(args[0]); - if (options->Has(v8::String::New("center"))) { - Local center = options->Get(v8::String::NewSymbol("center"))->ToObject(); - x = center->Get(v8::String::NewSymbol("x"))->Uint32Value(); - y = center->Get(v8::String::NewSymbol("y"))->Uint32Value(); - } - if (options->Has(v8::String::New("axes"))) { - Local axes = options->Get(v8::String::NewSymbol("axes"))->ToObject(); - width = axes->Get(v8::String::NewSymbol("width"))->Uint32Value(); - height = axes->Get(v8::String::NewSymbol("height"))->Uint32Value(); - } - if (options->Has(v8::String::New("thickness"))) { - thickness = options->Get(v8::String::NewSymbol("thickness"))->Uint32Value(); - } - if (options->Has(v8::String::New("angle"))) { - angle = options->Get(v8::String::NewSymbol("angle"))->NumberValue(); - } - if (options->Has(v8::String::New("startAngle"))) { - startAngle = options->Get(v8::String::NewSymbol("startAngle"))->NumberValue(); - } - if (options->Has(v8::String::New("endAngle"))) { - endAngle = options->Get(v8::String::NewSymbol("endAngle"))->NumberValue(); - } - if (options->Has(v8::String::New("lineType"))) { - lineType = options->Get(v8::String::NewSymbol("lineType"))->Uint32Value(); - } - if (options->Has(v8::String::New("shift"))) { - shift = options->Get(v8::String::NewSymbol("shift"))->Uint32Value(); - } - if (options->Has(v8::String::New("color"))) { - Local objColor = options->Get(v8::String::NewSymbol("color"))->ToObject(); - color = setColor(objColor); - } - } else { - x = args[0]->Uint32Value(); - y = args[1]->Uint32Value(); - width = args[2]->Uint32Value(); - height = args[3]->Uint32Value(); - - if(args[4]->IsArray()) { - Local objColor = args[4]->ToObject(); - color = setColor(objColor); - } + int x = args[0]->Uint32Value(); + int y = args[1]->Uint32Value(); + int width = args[2]->Uint32Value(); + int height = args[3]->Uint32Value(); + cv::Scalar color(0, 0, 255); - if(args[5]->IntegerValue()) - thickness = args[5]->IntegerValue(); - } + if(args[4]->IsArray()) { + Local objColor = args[4]->ToObject(); + color = setColor(objColor); + } - cv::ellipse(self->mat, cv::Point(x, y), cv::Size(width, height), angle, startAngle, endAngle, color, thickness, lineType, shift); - return scope.Close(v8::Null()); -} + int thickness = 1; + + if(args[5]->IntegerValue()) + thickness = args[5]->IntegerValue(); + cv::ellipse(self->mat, cv::Point(x, y), cv::Size(width, height), 0, 0, 360, color, thickness, 8, 0); + return scope.Close(v8::Null()); +} Handle @@ -662,7 +610,7 @@ Matrix::Rectangle(const Arguments& args) { if(args[3]->IntegerValue()) thickness = args[3]->IntegerValue(); - cv::rectangle(self->mat, cv::Point(x, y), cv::Point(x+width, y+height), color, thickness); + cv::rectangle(self->mat, cv::Point(x, y), cv::Point(width, height), color, thickness); } return scope.Close(v8::Null()); @@ -868,59 +816,36 @@ Matrix::GaussianBlur(const v8::Arguments& args) { Handle -Matrix::MedianBlur(const v8::Arguments &args) { - HandleScope scope; - cv::Mat blurred; - int ksize = 3; - Matrix *self = ObjectWrap::Unwrap(args.This()); +Matrix::BoxFilter(const v8::Arguments& args) { + HandleScope scope; + Matrix *self = ObjectWrap::Unwrap(args.This()); - if (args[0]->IsNumber()) { - ksize = args[0]->IntegerValue(); - if ((ksize % 2) == 0) { - return ThrowException(Exception::TypeError(String::New( - "'ksize' argument must be a positive odd integer"))); + cv::Mat boxFiltered; + cv::Size ksize; + if (args.Length() < 1) { + ksize = cv::Size(5, 5); } - } else { - return ThrowException(Exception::TypeError(String::New( - "'ksize' argument must be a positive odd integer"))); - } - - cv::medianBlur(self->mat, blurred, ksize); - blurred.copyTo(self->mat); - - return scope.Close(v8::Null()); -} - - -Handle -Matrix::BilateralFilter(const v8::Arguments &args) { - HandleScope scope; - cv::Mat filtered; - int d = 15; - double sigmaColor = 80; - double sigmaSpace = 80; - int borderType = cv::BORDER_DEFAULT; - - Matrix *self = ObjectWrap::Unwrap(args.This()); - - if (args.Length() != 0) { - if (args.Length() < 3 || args.Length() > 4) { - return ThrowException(Exception::TypeError(String::New( - "BilateralFilter takes 0, 3, or 4 arguments"))); - } else { - d = args[0]->IntegerValue(); - sigmaColor = args[1]->NumberValue(); - sigmaSpace = args[2]->NumberValue(); - if (args.Length() == 4) { - borderType = args[3]->IntegerValue(); - } + else { + if(!args[0]->IsArray()) { + return ThrowException(Exception::TypeError(String::New( + "'ksize' argument must be a 2 double array"))); + } + Local array = args[0]->ToObject(); + // TODO: Length check + Local x = array->Get(0); + Local y = array->Get(1); + if(!x->IsNumber() || !y->IsNumber()) { + return ThrowException(Exception::TypeError(String::New( + "'ksize' argument must be a 2 double array"))); + } + ksize = cv::Size(x->NumberValue(), y->NumberValue()); } - } - - cv::bilateralFilter(self->mat, filtered, d, sigmaColor, sigmaSpace, borderType); - filtered.copyTo(self->mat); + int ddepth = args[1]->NumberValue(); - return scope.Close(v8::Null()); + cv::boxFilter(self->mat, boxFiltered, ddepth, ksize); + boxFiltered.copyTo(self->mat); + + return scope.Close(v8::Null()); } @@ -1052,33 +977,6 @@ Matrix::BitwiseXor(const v8::Arguments& args) { return scope.Close(v8::Null()); } -Handle -Matrix::BitwiseNot(const v8::Arguments& args) { - HandleScope scope; - - Matrix *self = ObjectWrap::Unwrap(args.This()); - - Matrix *dst = ObjectWrap::Unwrap(args[0]->ToObject()); - - cv::bitwise_not(self->mat, dst->mat); - - return scope.Close(v8::Null()); -} - -Handle -Matrix::BitwiseAnd(const v8::Arguments& args) { - HandleScope scope; - - Matrix *self = ObjectWrap::Unwrap(args.This()); - - Matrix *src1 = ObjectWrap::Unwrap(args[0]->ToObject()); - Matrix *src2 = ObjectWrap::Unwrap(args[1]->ToObject()); - - cv::bitwise_and(src1->mat, src2->mat, self->mat); - - return scope.Close(v8::Null()); -} - Handle Matrix::CountNonZero(const v8::Arguments& args) { HandleScope scope; @@ -1169,9 +1067,7 @@ Matrix::DrawContour(const v8::Arguments& args) { color = setColor(objColor); } - int thickness = args.Length() < 4 ? 1 : args[3]->NumberValue(); - - cv::drawContours(self->mat, cont->contours, pos, color, thickness); + cv::drawContours(self->mat, cont->contours, pos, color, 1); return Undefined(); } @@ -1191,10 +1087,7 @@ Matrix::DrawAllContours(const v8::Arguments& args) { color = setColor(objColor); } - int thickness = args.Length() < 3 ? 1 : args[2]->NumberValue(); - - cv::drawContours(self->mat, cont->contours, -1, color, thickness); - + cv::drawContours(self->mat, cont->contours, -1, color, 1); return Undefined(); } @@ -1559,6 +1452,74 @@ Matrix::CopyTo(const v8::Arguments& args) { } +Handle +Matrix::ConvertTo(const v8::Arguments& args) { + HandleScope scope; + + Matrix * self = ObjectWrap::Unwrap(args.This()); + v8::String::Utf8Value str (args[0]->ToString()); + std::string str2 = std::string(*str); + const char * toTypeStr = (const char *) str2.c_str(); + + int toTypeInt; + double toAlpha = 1.0; + double toBeta = 0.0; + //types_c.h + if (!strcmp(toTypeStr, "CV_8U")) { toTypeInt = CV_8U; } + else if (!strcmp(toTypeStr, "CV_8S")) { toTypeInt = CV_8S; } + else if (!strcmp(toTypeStr, "CV_16U")) { toTypeInt = CV_16U; } + else if (!strcmp(toTypeStr, "CV_16S")) { toTypeInt = CV_16S; } + else if (!strcmp(toTypeStr, "CV_32S")) { toTypeInt = CV_32S; } + else if (!strcmp(toTypeStr, "CV_32F")) { toTypeInt = CV_32F; } + else if (!strcmp(toTypeStr, "CV_64F")) { toTypeInt = CV_64F; } + else if (!strcmp(toTypeStr, "CV_USRTYPE1")) { toTypeInt = CV_USRTYPE1; } + else if (!strcmp(toTypeStr, "CV_8UC1")) { toTypeInt = CV_8UC1; } + else if (!strcmp(toTypeStr, "CV_8UC2")) { toTypeInt = CV_8UC2; } + else if (!strcmp(toTypeStr, "CV_8UC3")) { toTypeInt = CV_8UC3; } + else if (!strcmp(toTypeStr, "CV_8UC4")) { toTypeInt = CV_8UC4; } + //else if (!strcmp(toTypeStr, "CV_8UC")) { toTypeInt = CV_8UC; } + else if (!strcmp(toTypeStr, "CV_8SC1")) { toTypeInt = CV_8SC1; } + else if (!strcmp(toTypeStr, "CV_8SC2")) { toTypeInt = CV_8SC2; } + else if (!strcmp(toTypeStr, "CV_8SC3")) { toTypeInt = CV_8SC3; } + else if (!strcmp(toTypeStr, "CV_8SC4")) { toTypeInt = CV_8SC4; } + //else if (!strcmp(toTypeStr, "CV_8SC")) { toTypeInt = CV_8SC; } + else if (!strcmp(toTypeStr, "CV_16UC1")) { toTypeInt = CV_16UC1; } + else if (!strcmp(toTypeStr, "CV_16UC2")) { toTypeInt = CV_16UC2; } + else if (!strcmp(toTypeStr, "CV_16UC3")) { toTypeInt = CV_16UC3; } + else if (!strcmp(toTypeStr, "CV_16UC4")) { toTypeInt = CV_16UC4; } + //else if (!strcmp(toTypeStr, "CV_16UC")) { toTypeInt = CV_16UC; } + else if (!strcmp(toTypeStr, "CV_16SC1")) { toTypeInt = CV_16SC1; } + else if (!strcmp(toTypeStr, "CV_16SC2")) { toTypeInt = CV_16SC2; } + else if (!strcmp(toTypeStr, "CV_16SC3")) { toTypeInt = CV_16SC3; } + else if (!strcmp(toTypeStr, "CV_16SC4")) { toTypeInt = CV_16SC4; } + //else if (!strcmp(toTypeStr, "CV_16SC")) { toTypeInt = CV_16SC; } + else if (!strcmp(toTypeStr, "CV_32SC1")) { toTypeInt = CV_32SC1; } + else if (!strcmp(toTypeStr, "CV_32SC2")) { toTypeInt = CV_32SC2; } + else if (!strcmp(toTypeStr, "CV_32SC3")) { toTypeInt = CV_32SC3; } + else if (!strcmp(toTypeStr, "CV_32SC4")) { toTypeInt = CV_32SC4; } + //else if (!strcmp(toTypeStr, "CV_32SC")) { toTypeInt = CV_32SC; } + else if (!strcmp(toTypeStr, "CV_32FC1")) { toTypeInt = CV_32FC1; } + else if (!strcmp(toTypeStr, "CV_32FC2")) { toTypeInt = CV_32FC2; } + else if (!strcmp(toTypeStr, "CV_32FC3")) { toTypeInt = CV_32FC3; } + else if (!strcmp(toTypeStr, "CV_32FC4")) { toTypeInt = CV_32FC4; } + //else if (!strcmp(toTypeStr, "CV_32FC")) { toTypeInt = CV_32FC; } + else if (!strcmp(toTypeStr, "CV_64FC1")) { toTypeInt = CV_64FC1; } + else if (!strcmp(toTypeStr, "CV_64FC2")) { toTypeInt = CV_64FC2; } + else if (!strcmp(toTypeStr, "CV_64FC3")) { toTypeInt = CV_64FC3; } + else if (!strcmp(toTypeStr, "CV_64FC4")) { toTypeInt = CV_64FC4; } + //else if (!strcmp(toTypeStr, "CV_64FC")) { toTypeInt = CV_64FC; } + else{ + toTypeInt = 0; // to avoid compiler warning + return v8::ThrowException(Exception::TypeError(String::New( + "Conversion type code is unsupported"))); + } + //cv::Mat::convertTo(self->mat, toTypeInt, toAlpha, toBeta); + self->mat.convertTo(self->mat, toTypeInt, toAlpha, toBeta); + + //return scope.Close(v8::Null()); + return scope.Close(Undefined()); +} + // @author SergeMv // Does in-place color transformation @@ -1783,196 +1744,3 @@ Matrix::MinMaxLoc(const v8::Arguments& args) { return scope.Close(result); } - - -// @author ytham -// Pushes some matrix (argument) the back of a matrix (self) -Handle -Matrix::PushBack(const v8::Arguments& args) { - HandleScope scope; - - Matrix *self = ObjectWrap::Unwrap(args.This()); - - Matrix *m_input = ObjectWrap::Unwrap(args[0]->ToObject()); - - self->mat.push_back(m_input->mat); - - return scope.Close(args.This()); -} - -Handle -Matrix::PutText(const v8::Arguments& args) { - HandleScope scope; - - Matrix *self = ObjectWrap::Unwrap(args.This()); - - v8::String::AsciiValue textString(args[0]); - char *text = (char *) malloc(textString.length() + 1); - strcpy(text, *textString); - - int x = args[1]->IntegerValue(); - int y = args[2]->IntegerValue(); - - v8::String::AsciiValue fontString(args[3]); - char *font = (char *) malloc(fontString.length() + 1); - strcpy(font, *fontString); - int constFont = cv::FONT_HERSHEY_SIMPLEX; - - if (!strcmp(font, "HERSEY_SIMPLEX")) { constFont = cv::FONT_HERSHEY_SIMPLEX; } - else if (!strcmp(font, "HERSEY_PLAIN")) { constFont = cv::FONT_HERSHEY_PLAIN; } - else if (!strcmp(font, "HERSEY_DUPLEX")) { constFont = cv::FONT_HERSHEY_DUPLEX; } - else if (!strcmp(font, "HERSEY_COMPLEX")) { constFont = cv::FONT_HERSHEY_COMPLEX; } - else if (!strcmp(font, "HERSEY_TRIPLEX")) { constFont = cv::FONT_HERSHEY_TRIPLEX; } - else if (!strcmp(font, "HERSEY_COMPLEX_SMALL")) { constFont = cv::FONT_HERSHEY_COMPLEX_SMALL; } - else if (!strcmp(font, "HERSEY_SCRIPT_SIMPLEX")) { constFont = cv::FONT_HERSHEY_SCRIPT_SIMPLEX; } - else if (!strcmp(font, "HERSEY_SCRIPT_COMPLEX")) { constFont = cv::FONT_HERSHEY_SCRIPT_COMPLEX; } - else if (!strcmp(font, "HERSEY_SCRIPT_SIMPLEX")) { constFont = cv::FONT_HERSHEY_SCRIPT_SIMPLEX; } - - cv::Scalar color(0, 0, 255); - - if(args[4]->IsArray()) { - Local objColor = args[4]->ToObject(); - color = setColor(objColor); - } - - double scale = args.Length() < 6 ? 1 : args[5]->NumberValue(); - - cv::putText(self->mat, text, cv::Point(x, y), constFont, scale, color, 2); - - return scope.Close(Undefined()); -} - -Handle -Matrix::GetPerspectiveTransform(const v8::Arguments& args) { - HandleScope scope; - - // extract quad args - Local srcArray = args[0]->ToObject(); - Local tgtArray = args[1]->ToObject(); - - std::vector src_corners(4); - std::vector tgt_corners(4); - for (unsigned int i = 0; i < 4; i++) { - src_corners[i] = cvPoint(srcArray->Get(i*2)->IntegerValue(),srcArray->Get(i*2+1)->IntegerValue()); - tgt_corners[i] = cvPoint(tgtArray->Get(i*2)->IntegerValue(),tgtArray->Get(i*2+1)->IntegerValue()); - } - - Local xfrm = Matrix::constructor->GetFunction()->NewInstance(); - Matrix *xfrmmat = ObjectWrap::Unwrap(xfrm); - xfrmmat->mat = cv::getPerspectiveTransform(src_corners, tgt_corners); - - return scope.Close(xfrm); -} - -Handle -Matrix::WarpPerspective(const v8::Arguments& args) { - SETUP_FUNCTION(Matrix) - - Matrix *xfrm = ObjectWrap::Unwrap(args[0]->ToObject()); - - int width = args[1]->IntegerValue(); - int height = args[2]->IntegerValue(); - - int flags = cv::INTER_LINEAR; - int borderMode = cv::BORDER_REPLICATE; - - cv::Scalar borderColor(0, 0, 255); - - if(args[3]->IsArray()) { - Local objColor = args[3]->ToObject(); - borderColor = setColor(objColor); - } - - cv::Mat res = cv::Mat(width, height, CV_32FC3); - - cv::warpPerspective(self->mat, res, xfrm->mat, cv::Size(width, height), flags, borderMode, borderColor); - - ~self->mat; - self->mat = res; - - return scope.Close(v8::Null()); -} - -Handle -Matrix::CopyWithMask(const v8::Arguments& args) { - SETUP_FUNCTION(Matrix) - - // param 0 - destination image: - Matrix *dest = ObjectWrap::Unwrap(args[0]->ToObject()); - // param 1 - mask. same size as src and dest - Matrix *mask = ObjectWrap::Unwrap(args[1]->ToObject()); - - self->mat.copyTo(dest->mat,mask->mat); - - return scope.Close(Undefined()); -} - - -Handle -Matrix::SetWithMask(const v8::Arguments& args) { - SETUP_FUNCTION(Matrix) - - // param 0 - target value: - Local valArray = args[0]->ToObject(); - cv::Scalar newvals; - newvals.val[0] = valArray->Get(0)->NumberValue(); - newvals.val[1] = valArray->Get(1)->NumberValue(); - newvals.val[2] = valArray->Get(2)->NumberValue(); - - // param 1 - mask. same size as src and dest - Matrix *mask = ObjectWrap::Unwrap(args[1]->ToObject()); - - self->mat.setTo(newvals,mask->mat); - - return scope.Close(Undefined()); -} - -Handle -Matrix::MeanWithMask(const v8::Arguments& args) { - SETUP_FUNCTION(Matrix) - - // param 0 - mask. same size as src and dest - Matrix *mask = ObjectWrap::Unwrap(args[0]->ToObject()); - - cv::Scalar means = cv::mean(self->mat, mask->mat); - v8::Local arr = v8::Array::New(3); - arr->Set(0, Number::New( means[0] )); - arr->Set(1, Number::New( means[1] )); - arr->Set(2, Number::New( means[2] )); - - return scope.Close(arr); -} - -Handle -Matrix::Shift(const v8::Arguments& args){ - SETUP_FUNCTION(Matrix) - - cv::Mat res; - - double tx = args[0]->NumberValue(); - double ty = args[1]->NumberValue(); - - // get the integer values of args - cv::Point2i deltai(ceil(tx), ceil(ty)); - - int fill=cv::BORDER_REPLICATE; - cv::Scalar value=cv::Scalar(0,0,0,0); - - // INTEGER SHIFT - // first create a border around the parts of the Mat that will be exposed - int t = 0, b = 0, l = 0, r = 0; - if (deltai.x > 0) l = deltai.x; - if (deltai.x < 0) r = -deltai.x; - if (deltai.y > 0) t = deltai.y; - if (deltai.y < 0) b = -deltai.y; - cv::Mat padded; - cv::copyMakeBorder(self->mat, padded, t, b, l, r, fill, value); - - // construct the region of interest around the new matrix - cv::Rect roi = cv::Rect(std::max(-deltai.x,0),std::max(-deltai.y,0),0,0) + self->mat.size(); - res = padded(roi); - ~self->mat; - self->mat = res; - - return scope.Close(Undefined()); -} \ No newline at end of file diff --git a/src/Matrix.h b/src/Matrix.h index 3331e44e..915bfd8d 100755 --- a/src/Matrix.h +++ b/src/Matrix.h @@ -3,7 +3,7 @@ class Matrix: public node::ObjectWrap { public: - cv::Mat mat; + cv::Mat mat; static Persistent constructor; static void Init(Handle target); static Handle New(const Arguments &args); @@ -28,6 +28,7 @@ class Matrix: public node::ObjectWrap { JSFUNC(Width) JSFUNC(Height) JSFUNC(Channels) + JSFUNC(Type) JSFUNC(Clone) JSFUNC(Ellipse) JSFUNC(Rectangle) @@ -48,8 +49,7 @@ class Matrix: public node::ObjectWrap { JSFUNC(ConvertGrayscale) JSFUNC(ConvertHSVscale) JSFUNC(GaussianBlur) - JSFUNC(MedianBlur) - JSFUNC(BilateralFilter) + JSFUNC(BoxFilter) JSFUNC(Copy) JSFUNC(Flip) JSFUNC(ROI) @@ -57,8 +57,6 @@ class Matrix: public node::ObjectWrap { JSFUNC(AbsDiff) JSFUNC(AddWeighted) JSFUNC(BitwiseXor) - JSFUNC(BitwiseNot) - JSFUNC(BitwiseAnd) JSFUNC(CountNonZero) //JSFUNC(Split) JSFUNC(Canny) @@ -83,6 +81,7 @@ class Matrix: public node::ObjectWrap { JSFUNC(MeanStdDev) JSFUNC(CopyTo) + JSFUNC(ConvertTo) JSFUNC(CvtColor) JSFUNC(Split) JSFUNC(Merge) @@ -92,25 +91,14 @@ class Matrix: public node::ObjectWrap { JSFUNC(MatchTemplate) JSFUNC(MinMaxLoc) - - JSFUNC(PushBack) - - JSFUNC(PutText) - JSFUNC(GetPerspectiveTransform) - JSFUNC(WarpPerspective) - - JSFUNC(CopyWithMask) - JSFUNC(SetWithMask) - JSFUNC(MeanWithMask) - JSFUNC(Shift) /* - static Handle Val(const Arguments& args); - static Handle RowRange(const Arguments& args); - static Handle ColRange(const Arguments& args); - static Handle Diag(const Arguments& args); - static Handle Clone(const Arguments& args); - static Handle CopyTo(const Arguments& args); - static Handle ConvertTo(const Arguments& args); + static Handle Val(const Arguments& args); + static Handle RowRange(const Arguments& args); + static Handle ColRange(const Arguments& args); + static Handle Diag(const Arguments& args); + static Handle Clone(const Arguments& args); + static Handle CopyTo(const Arguments& args); + static Handle ConvertTo(const Arguments& args); static Handle AssignTo(const Arguments& args); static Handle SetTo(const Arguments& args); static Handle Reshape(const Arguments& args); @@ -130,8 +118,7 @@ class Matrix: public node::ObjectWrap { static Handle Depth(const Arguments& args); static Handle Channels(const Arguments& args); static Handle StepOne(const Arguments& args); - static Handle GetPerspectiveTransform(const Arguments& args); - static Handle WarpPerspective(const Arguments& args); + */ diff --git a/src/VideoCaptureWrap.cc b/src/VideoCaptureWrap.cc index fb8a7968..d28ae506 100755 --- a/src/VideoCaptureWrap.cc +++ b/src/VideoCaptureWrap.cc @@ -2,9 +2,6 @@ #include "Matrix.h" #include "OpenCV.h" -#include -using namespace std; - void AsyncRead(uv_work_t *req); void AfterAsyncRead(uv_work_t *req); @@ -34,9 +31,6 @@ VideoCaptureWrap::Init(Handle target) { //Local proto = constructor->PrototypeTemplate(); NODE_SET_PROTOTYPE_METHOD(constructor, "read", Read); - NODE_SET_PROTOTYPE_METHOD(constructor, "setWidth", SetWidth); - NODE_SET_PROTOTYPE_METHOD(constructor, "setHeight", SetHeight); - NODE_SET_PROTOTYPE_METHOD(constructor, "setPosition", SetPosition); target->Set(String::NewSymbol("VideoCapture"), constructor->GetFunction()); }; @@ -83,54 +77,6 @@ VideoCaptureWrap::VideoCaptureWrap(const std::string& filename){ } -Handle -VideoCaptureWrap::SetWidth(const Arguments &args){ - - HandleScope scope; - VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); - - if(args.Length() != 1) - return scope.Close(Undefined()); - - int w = args[0]->IntegerValue(); - - if(v->cap.isOpened()) - v->cap.set(CV_CAP_PROP_FRAME_WIDTH, w); - - return scope.Close(Undefined()); -} - -Handle -VideoCaptureWrap::SetHeight(const Arguments &args){ - - HandleScope scope; - VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); - - if(args.Length() != 1) - return scope.Close(Undefined()); - - int h = args[0]->IntegerValue(); - - v->cap.set(CV_CAP_PROP_FRAME_HEIGHT, h); - - return Undefined(); -} - -Handle -VideoCaptureWrap::SetPosition(const Arguments &args){ - - HandleScope scope; - VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); - - if(args.Length() != 1) - return scope.Close(Undefined()); - - int pos = args[0]->IntegerValue(); - - v->cap.set(CV_CAP_PROP_POS_FRAMES, pos); - - return Undefined(); -} Handle VideoCaptureWrap::Read(const Arguments &args) { diff --git a/src/VideoCaptureWrap.h b/src/VideoCaptureWrap.h index b2392731..397ee27a 100755 --- a/src/VideoCaptureWrap.h +++ b/src/VideoCaptureWrap.h @@ -13,13 +13,6 @@ class VideoCaptureWrap: public node::ObjectWrap { static Handle Read(const v8::Arguments&); - //(Optional) For setting width and height of the input video stream - static Handle SetWidth(const v8::Arguments&); - static Handle SetHeight(const v8::Arguments&); - - // to set frame position - static Handle SetPosition(const v8::Arguments&); - static Handle GetFrameAt(const v8::Arguments&); diff --git a/src/init.cc b/src/init.cc index 1610800f..b6aa7589 100755 --- a/src/init.cc +++ b/src/init.cc @@ -7,7 +7,12 @@ #include "CamShift.h" #include "HighGUI.h" #include "FaceRecognizer.h" - +#include "KeyPoint.h" +#include "DMatch.h" +#include "Feature2D.h" +#include "FeatureDetector.h" +#include "DescriptorExtractor.h" +#include "DescriptorMatcher.h" extern "C" void init(Handle target) { @@ -20,7 +25,14 @@ init(Handle target) { Contour::Init(target); TrackedObject::Init(target); NamedWindow::Init(target); - + KeyPoint::Init(target); + DMatch::Init(target); + Algorithm::Init(target); + DescriptorExtractor::Init(target); + DescriptorMatcher::Init(target); + FeatureDetector::Init(target); + Feature2D::Init(target); + #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4 FaceRecognizerWrap::Init(target); #endif From de429f18c0b480da0f9a1300c217cacce7f572dc Mon Sep 17 00:00:00 2001 From: Jorge Lahoz Date: Tue, 2 Sep 2014 22:30:53 +0200 Subject: [PATCH 2/4] More binding functions for Matrix --- src/Matrix.cc | 300 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 298 insertions(+), 2 deletions(-) diff --git a/src/Matrix.cc b/src/Matrix.cc index ca2d2333..165ee5ff 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -60,6 +60,8 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "convertGrayscale", ConvertGrayscale); NODE_SET_PROTOTYPE_METHOD(constructor, "convertHSVscale", ConvertHSVscale); NODE_SET_PROTOTYPE_METHOD(constructor, "gaussianBlur", GaussianBlur); + NODE_SET_PROTOTYPE_METHOD(constructor, "medianBlur", MedianBlur); + NODE_SET_PROTOTYPE_METHOD(constructor, "bilateralFilter", BilateralFilter); NODE_SET_PROTOTYPE_METHOD(constructor, "boxFilter", BoxFilter); NODE_SET_PROTOTYPE_METHOD(constructor, "copy", Copy); NODE_SET_PROTOTYPE_METHOD(constructor, "flip", Flip); @@ -68,6 +70,8 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "absDiff", AbsDiff); NODE_SET_PROTOTYPE_METHOD(constructor, "addWeighted", AddWeighted); NODE_SET_PROTOTYPE_METHOD(constructor, "bitwiseXor", BitwiseXor); + NODE_SET_PROTOTYPE_METHOD(constructor, "bitwiseNot", BitwiseNot); + NODE_SET_PROTOTYPE_METHOD(constructor, "bitwiseAnd", BitwiseAnd); NODE_SET_PROTOTYPE_METHOD(constructor, "countNonZero", CountNonZero); //NODE_SET_PROTOTYPE_METHOD(constructor, "split", Split); NODE_SET_PROTOTYPE_METHOD(constructor, "canny", Canny); @@ -96,11 +100,23 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "floodFill", FloodFill); - NODE_SET_PROTOTYPE_METHOD(constructor, "matchTemplate", MatchTemplate); - NODE_SET_PROTOTYPE_METHOD(constructor, "minMaxLoc", MinMaxLoc); + NODE_SET_PROTOTYPE_METHOD(constructor, "matchTemplate", MatchTemplate); + NODE_SET_PROTOTYPE_METHOD(constructor, "minMaxLoc", MinMaxLoc); + + NODE_SET_PROTOTYPE_METHOD(constructor, "pushBack", PushBack); + + NODE_SET_PROTOTYPE_METHOD(constructor, "putText", PutText); + + NODE_SET_PROTOTYPE_METHOD(constructor, "getPerspectiveTransform", GetPerspectiveTransform); + NODE_SET_PROTOTYPE_METHOD(constructor, "warpPerspective", WarpPerspective); NODE_SET_METHOD(constructor, "Eye", Eye); + NODE_SET_PROTOTYPE_METHOD(constructor, "copyWithMask", CopyWithMask); + NODE_SET_PROTOTYPE_METHOD(constructor, "setWithMask", SetWithMask); + NODE_SET_PROTOTYPE_METHOD(constructor, "meanWithMask", MeanWithMask); + NODE_SET_PROTOTYPE_METHOD(constructor, "shift", Shift); + target->Set(String::NewSymbol("Matrix"), m->GetFunction()); }; @@ -815,6 +831,63 @@ Matrix::GaussianBlur(const v8::Arguments& args) { } +Handle +Matrix::MedianBlur(const v8::Arguments &args) { + HandleScope scope; + cv::Mat blurred; + int ksize = 3; + Matrix *self = ObjectWrap::Unwrap(args.This()); + + if (args[0]->IsNumber()) { + ksize = args[0]->IntegerValue(); + if ((ksize % 2) == 0) { + return ThrowException(Exception::TypeError(String::New( + "'ksize' argument must be a positive odd integer"))); + } + } else { + return ThrowException(Exception::TypeError(String::New( + "'ksize' argument must be a positive odd integer"))); + } + + cv::medianBlur(self->mat, blurred, ksize); + blurred.copyTo(self->mat); + + return scope.Close(v8::Null()); +} + + +Handle +Matrix::BilateralFilter(const v8::Arguments &args) { + HandleScope scope; + cv::Mat filtered; + int d = 15; + double sigmaColor = 80; + double sigmaSpace = 80; + int borderType = cv::BORDER_DEFAULT; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + if (args.Length() != 0) { + if (args.Length() < 3 || args.Length() > 4) { + return ThrowException(Exception::TypeError(String::New( + "BilateralFilter takes 0, 3, or 4 arguments"))); + } else { + d = args[0]->IntegerValue(); + sigmaColor = args[1]->NumberValue(); + sigmaSpace = args[2]->NumberValue(); + if (args.Length() == 4) { + borderType = args[3]->IntegerValue(); + } + } + } + + cv::bilateralFilter(self->mat, filtered, d, sigmaColor, sigmaSpace, borderType); + filtered.copyTo(self->mat); + + return scope.Close(v8::Null()); +} + + Handle Matrix::BoxFilter(const v8::Arguments& args) { HandleScope scope; @@ -977,6 +1050,35 @@ Matrix::BitwiseXor(const v8::Arguments& args) { return scope.Close(v8::Null()); } + +Handle +Matrix::BitwiseNot(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + Matrix *dst = ObjectWrap::Unwrap(args[0]->ToObject()); + + cv::bitwise_not(self->mat, dst->mat); + + return scope.Close(v8::Null()); +} + + +Handle +Matrix::BitwiseAnd(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + Matrix *src1 = ObjectWrap::Unwrap(args[0]->ToObject()); + Matrix *src2 = ObjectWrap::Unwrap(args[1]->ToObject()); + + cv::bitwise_and(src1->mat, src2->mat, self->mat); + + return scope.Close(v8::Null()); +} + Handle Matrix::CountNonZero(const v8::Arguments& args) { HandleScope scope; @@ -1744,3 +1846,197 @@ Matrix::MinMaxLoc(const v8::Arguments& args) { return scope.Close(result); } + + +// @author ytham +// Pushes some matrix (argument) the back of a matrix (self) +Handle +Matrix::PushBack(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + Matrix *m_input = ObjectWrap::Unwrap(args[0]->ToObject()); + + self->mat.push_back(m_input->mat); + + return scope.Close(args.This()); +} + +Handle +Matrix::PutText(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + v8::String::AsciiValue textString(args[0]); + char *text = (char *) malloc(textString.length() + 1); + strcpy(text, *textString); + + int x = args[1]->IntegerValue(); + int y = args[2]->IntegerValue(); + + v8::String::AsciiValue fontString(args[3]); + char *font = (char *) malloc(fontString.length() + 1); + strcpy(font, *fontString); + int constFont = cv::FONT_HERSHEY_SIMPLEX; + + if (!strcmp(font, "HERSEY_SIMPLEX")) { constFont = cv::FONT_HERSHEY_SIMPLEX; } + else if (!strcmp(font, "HERSEY_PLAIN")) { constFont = cv::FONT_HERSHEY_PLAIN; } + else if (!strcmp(font, "HERSEY_DUPLEX")) { constFont = cv::FONT_HERSHEY_DUPLEX; } + else if (!strcmp(font, "HERSEY_COMPLEX")) { constFont = cv::FONT_HERSHEY_COMPLEX; } + else if (!strcmp(font, "HERSEY_TRIPLEX")) { constFont = cv::FONT_HERSHEY_TRIPLEX; } + else if (!strcmp(font, "HERSEY_COMPLEX_SMALL")) { constFont = cv::FONT_HERSHEY_COMPLEX_SMALL; } + else if (!strcmp(font, "HERSEY_SCRIPT_SIMPLEX")) { constFont = cv::FONT_HERSHEY_SCRIPT_SIMPLEX; } + else if (!strcmp(font, "HERSEY_SCRIPT_COMPLEX")) { constFont = cv::FONT_HERSHEY_SCRIPT_COMPLEX; } + else if (!strcmp(font, "HERSEY_SCRIPT_SIMPLEX")) { constFont = cv::FONT_HERSHEY_SCRIPT_SIMPLEX; } + + cv::Scalar color(0, 0, 255); + + if(args[4]->IsArray()) { + Local objColor = args[4]->ToObject(); + color = setColor(objColor); + } + + double scale = args.Length() < 6 ? 1 : args[5]->NumberValue(); + + cv::putText(self->mat, text, cv::Point(x, y), constFont, scale, color, 2); + + return scope.Close(Undefined()); +} + +Handle +Matrix::GetPerspectiveTransform(const v8::Arguments& args) { + HandleScope scope; + + // extract quad args + Local srcArray = args[0]->ToObject(); + Local tgtArray = args[1]->ToObject(); + + std::vector src_corners(4); + std::vector tgt_corners(4); + for (unsigned int i = 0; i < 4; i++) { + src_corners[i] = cvPoint(srcArray->Get(i*2)->IntegerValue(),srcArray->Get(i*2+1)->IntegerValue()); + tgt_corners[i] = cvPoint(tgtArray->Get(i*2)->IntegerValue(),tgtArray->Get(i*2+1)->IntegerValue()); + } + + Local xfrm = Matrix::constructor->GetFunction()->NewInstance(); + Matrix *xfrmmat = ObjectWrap::Unwrap(xfrm); + xfrmmat->mat = cv::getPerspectiveTransform(src_corners, tgt_corners); + + return scope.Close(xfrm); +} + +Handle +Matrix::WarpPerspective(const v8::Arguments& args) { + SETUP_FUNCTION(Matrix) + + Matrix *xfrm = ObjectWrap::Unwrap(args[0]->ToObject()); + + int width = args[1]->IntegerValue(); + int height = args[2]->IntegerValue(); + + int flags = cv::INTER_LINEAR; + int borderMode = cv::BORDER_REPLICATE; + + cv::Scalar borderColor(0, 0, 255); + + if(args[3]->IsArray()) { + Local objColor = args[3]->ToObject(); + borderColor = setColor(objColor); + } + + cv::Mat res = cv::Mat(width, height, CV_32FC3); + + cv::warpPerspective(self->mat, res, xfrm->mat, cv::Size(width, height), flags, borderMode, borderColor); + + ~self->mat; + self->mat = res; + + return scope.Close(v8::Null()); +} + + +Handle +Matrix::CopyWithMask(const v8::Arguments& args) { + SETUP_FUNCTION(Matrix) + + // param 0 - destination image: + Matrix *dest = ObjectWrap::Unwrap(args[0]->ToObject()); + // param 1 - mask. same size as src and dest + Matrix *mask = ObjectWrap::Unwrap(args[1]->ToObject()); + + self->mat.copyTo(dest->mat,mask->mat); + + return scope.Close(Undefined()); +} + + +Handle +Matrix::SetWithMask(const v8::Arguments& args) { + SETUP_FUNCTION(Matrix) + + // param 0 - target value: + Local valArray = args[0]->ToObject(); + cv::Scalar newvals; + newvals.val[0] = valArray->Get(0)->NumberValue(); + newvals.val[1] = valArray->Get(1)->NumberValue(); + newvals.val[2] = valArray->Get(2)->NumberValue(); + + // param 1 - mask. same size as src and dest + Matrix *mask = ObjectWrap::Unwrap(args[1]->ToObject()); + + self->mat.setTo(newvals,mask->mat); + + return scope.Close(Undefined()); +} + +Handle +Matrix::MeanWithMask(const v8::Arguments& args) { + SETUP_FUNCTION(Matrix) + + // param 0 - mask. same size as src and dest + Matrix *mask = ObjectWrap::Unwrap(args[0]->ToObject()); + + cv::Scalar means = cv::mean(self->mat, mask->mat); + v8::Local arr = v8::Array::New(3); + arr->Set(0, Number::New( means[0] )); + arr->Set(1, Number::New( means[1] )); + arr->Set(2, Number::New( means[2] )); + + return scope.Close(arr); +} + +Handle +Matrix::Shift(const v8::Arguments& args){ + SETUP_FUNCTION(Matrix) + + cv::Mat res; + + double tx = args[0]->NumberValue(); + double ty = args[1]->NumberValue(); + + // get the integer values of args + cv::Point2i deltai(ceil(tx), ceil(ty)); + + int fill=cv::BORDER_REPLICATE; + cv::Scalar value=cv::Scalar(0,0,0,0); + + // INTEGER SHIFT + // first create a border around the parts of the Mat that will be exposed + int t = 0, b = 0, l = 0, r = 0; + if (deltai.x > 0) l = deltai.x; + if (deltai.x < 0) r = -deltai.x; + if (deltai.y > 0) t = deltai.y; + if (deltai.y < 0) b = -deltai.y; + cv::Mat padded; + cv::copyMakeBorder(self->mat, padded, t, b, l, r, fill, value); + + // construct the region of interest around the new matrix + cv::Rect roi = cv::Rect(std::max(-deltai.x,0),std::max(-deltai.y,0),0,0) + self->mat.size(); + res = padded(roi); + ~self->mat; + self->mat = res; + + return scope.Close(Undefined()); +} From 217124472c9526b80f1f3786cd002cc7f2b29547 Mon Sep 17 00:00:00 2001 From: Jorge Lahoz Date: Tue, 2 Sep 2014 22:40:47 +0200 Subject: [PATCH 3/4] Forgiveness --- src/Matrix.cc | 4 ++-- src/Matrix.h | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Matrix.cc b/src/Matrix.cc index 165ee5ff..4e682985 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -82,8 +82,8 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "drawContour", DrawContour); NODE_SET_PROTOTYPE_METHOD(constructor, "drawAllContours", DrawAllContours); - NODE_SET_PROTOTYPE_METHOD(constructor, "goodFeaturesToTrack", GoodFeaturesToTrack); - NODE_SET_PROTOTYPE_METHOD(constructor, "houghLinesP", HoughLinesP); + NODE_SET_PROTOTYPE_METHOD(constructor, "goodFeaturesToTrack", GoodFeaturesToTrack); + NODE_SET_PROTOTYPE_METHOD(constructor, "houghLinesP", HoughLinesP); NODE_SET_PROTOTYPE_METHOD(constructor, "inRange", inRange); NODE_SET_PROTOTYPE_METHOD(constructor, "adjustROI", AdjustROI); diff --git a/src/Matrix.h b/src/Matrix.h index 915bfd8d..1563ccbe 100755 --- a/src/Matrix.h +++ b/src/Matrix.h @@ -49,6 +49,8 @@ class Matrix: public node::ObjectWrap { JSFUNC(ConvertGrayscale) JSFUNC(ConvertHSVscale) JSFUNC(GaussianBlur) + JSFUNC(MedianBlur) + JSFUNC(BilateralFilter) JSFUNC(BoxFilter) JSFUNC(Copy) JSFUNC(Flip) @@ -57,6 +59,8 @@ class Matrix: public node::ObjectWrap { JSFUNC(AbsDiff) JSFUNC(AddWeighted) JSFUNC(BitwiseXor) + JSFUNC(BitwiseNot) + JSFUNC(BitwiseAnd) JSFUNC(CountNonZero) //JSFUNC(Split) JSFUNC(Canny) @@ -91,6 +95,19 @@ class Matrix: public node::ObjectWrap { JSFUNC(MatchTemplate) JSFUNC(MinMaxLoc) + + JSFUNC(PushBack) + + JSFUNC(PutText) + + JSFUNC(GetPerspectiveTransform) + JSFUNC(WarpPerspective) + + JSFUNC(CopyWithMask) + JSFUNC(SetWithMask) + JSFUNC(MeanWithMask) + JSFUNC(Shift) + /* static Handle Val(const Arguments& args); static Handle RowRange(const Arguments& args); @@ -110,7 +127,6 @@ class Matrix: public node::ObjectWrap { static Handle Zeroes(const Arguments& args); static Handle Ones(const Arguments& args); // create, increment, release - static Handle PushBack(const Arguments& args); static Handle PopBack(const Arguments& args); static Handle Total(const Arguments& args); static Handle IsContinous(const Arguments& args); From 3e260b7eda8a6fbf557f7c8edad1ece279a5c047 Mon Sep 17 00:00:00 2001 From: Jorge Lahoz Date: Sat, 6 Sep 2014 21:51:03 +0200 Subject: [PATCH 4/4] Add mask support to bitwise_and bind --- src/Matrix.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Matrix.cc b/src/Matrix.cc index 4e682985..b9a4cf10 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -1073,9 +1073,17 @@ Matrix::BitwiseAnd(const v8::Arguments& args) { Matrix *src1 = ObjectWrap::Unwrap(args[0]->ToObject()); Matrix *src2 = ObjectWrap::Unwrap(args[1]->ToObject()); + Matrix *mask = NULL; + if (args.Length()>2 && !(args[2]->IsNull()) && args[2]->IsObject()){ + mask = ObjectWrap::Unwrap(args[2]->ToObject()); + } - cv::bitwise_and(src1->mat, src2->mat, self->mat); - + if (mask!=NULL) { + cv::bitwise_and(src1->mat, src2->mat, self->mat, mask->mat); + }else{ + cv::bitwise_and(src1->mat, src2->mat, self->mat); + } + return scope.Close(v8::Null()); }