diff --git a/binding.gyp b/binding.gyp index 6318322..97ccd40 100755 --- a/binding.gyp +++ b/binding.gyp @@ -1,6 +1,8 @@ { "targets": [{ - "target_name": "opencv", + + "target_name": "opencv", + "sources": [ "src/init.cc", "src/Matrix.cc", @@ -12,6 +14,7 @@ "src/CamShift.cc", "src/HighGUI.cc", "src/FaceRecognizer.cc", + "src/Features2d.cc", "src/BackgroundSubtractor.cc", "src/Constants.cc", "src/Calib3D.cc", diff --git a/examples/dissimilarity.js b/examples/dissimilarity.js new file mode 100644 index 0000000..15e5e52 --- /dev/null +++ b/examples/dissimilarity.js @@ -0,0 +1,17 @@ +var cv = require('../lib/opencv'); + +cv.readImage("./examples/files/car1.jpg", function(err, car1) { + if (err) throw err; + + cv.readImage("./examples/files/car2.jpg", function(err, car2) { + if (err) throw err; + + cv.ImageSimilarity(car1, car2, function (err, dissimilarity) { + if (err) throw err; + + console.log('Dissimilarity: ', dissimilarity); + }); + + }); + +}); diff --git a/package.json b/package.json old mode 100755 new mode 100644 index 00d13d6..f74011b --- a/package.json +++ b/package.json @@ -3,18 +3,20 @@ "description": "Node Bindings to OpenCV", "author": "Peter Braden ", "dependencies": { - "node-pre-gyp": "0.5.31", "buffers": "0.1.1", - "nan": "1.4.3" + "nan": "^1.7.0", + "node-pre-gyp": "^0.6.4" }, "version": "3.0.1", "devDependencies": { "tape": "^3.0.0", - "aws-sdk": "~2.0.21", - "glob": "^4.0.6", - "request": "^2.45.0" + "aws-sdk": "~2.1.20", + "glob": "^5.0.3", + "request": "^2.44.0" }, - "bundledDependencies":["node-pre-gyp"], + "bundledDependencies": [ + "node-pre-gyp" + ], "license": "MIT", "scripts": { "build": "node-gyp build", @@ -36,10 +38,10 @@ "node": ">=0.10" }, "binary": { - "module_name" : "opencv", - "module_path" : "./build/{module_name}/v{version}/{configuration}/{node_abi}-{platform}-{arch}/", - "remote_path" : "./{module_name}/v{version}/{configuration}/", + "module_name": "opencv", + "module_path": "./build/{module_name}/v{version}/{configuration}/{node_abi}-{platform}-{arch}/", + "remote_path": "./{module_name}/v{version}/{configuration}/", "package_name": "{node_abi}-{platform}-{arch}.tar.gz", - "host" : "https://node-opencv.s3.amazonaws.com" + "host": "https://node-opencv.s3.amazonaws.com" } } diff --git a/src/CascadeClassifierWrap.cc b/src/CascadeClassifierWrap.cc index ac8a35f..2398103 100755 --- a/src/CascadeClassifierWrap.cc +++ b/src/CascadeClassifierWrap.cc @@ -21,7 +21,7 @@ CascadeClassifierWrap::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(ctor, "detectMultiScale", DetectMultiScale); target->Set(NanNew("CascadeClassifier"), ctor->GetFunction()); -}; +}; NAN_METHOD(CascadeClassifierWrap::New) { NanScope(); @@ -29,7 +29,7 @@ NAN_METHOD(CascadeClassifierWrap::New) { if (args.This()->InternalFieldCount() == 0) NanThrowTypeError("Cannot instantiate without new"); - CascadeClassifierWrap *pt = new CascadeClassifierWrap(*args[0]); + CascadeClassifierWrap *pt = new CascadeClassifierWrap(*args[0]); pt->Wrap(args.This()); NanReturnValue( args.This() ); } @@ -39,10 +39,10 @@ CascadeClassifierWrap::CascadeClassifierWrap(v8::Value* fileName){ std::string filename; filename = std::string(*NanAsciiString(fileName->ToString())); - + if (!cc.load(filename.c_str())){ NanThrowTypeError("Error loading file"); - } + } } @@ -63,14 +63,15 @@ class AsyncDetectMultiScale : public NanAsyncWorker { equalizeHist( gray, gray); this->cc->cc.detectMultiScale(gray, objects, this->scale, this->neighbors, 0 | CV_HAAR_SCALE_IMAGE, cv::Size(this->minw, this->minh)); - + res = objects; } void HandleOKCallback () { NanScope(); // this->matrix->Unref(); - + + Handle argv[2]; v8::Local arr = NanNew(this->res.size()); for(unsigned int i = 0; i < this->res.size(); i++ ){ @@ -82,20 +83,17 @@ class AsyncDetectMultiScale : public NanAsyncWorker { arr->Set(i, x); } - //argv[1] = arr; - Local argv[] = { - NanNull() - , arr - }; - + argv[0] = NanNull(); + argv[1] = arr; + TryCatch try_catch; callback->Call(2, argv); if (try_catch.HasCaught()) { FatalException(try_catch); } - + } - + private: CascadeClassifierWrap *cc; Matrix* im; @@ -104,7 +102,7 @@ class AsyncDetectMultiScale : public NanAsyncWorker { int minw; int minh; std::vector res; - + }; @@ -114,7 +112,7 @@ NAN_METHOD(CascadeClassifierWrap::DetectMultiScale){ NanScope(); CascadeClassifierWrap *self = ObjectWrap::Unwrap(args.This()); - + if (args.Length() < 2){ NanThrowTypeError("detectMultiScale takes at least 2 args"); } @@ -142,5 +140,5 @@ NAN_METHOD(CascadeClassifierWrap::DetectMultiScale){ NanAsyncQueueWorker( new AsyncDetectMultiScale(callback, self, im, scale, neighbors, minw, minh) ); NanReturnUndefined(); - + } diff --git a/src/Features2d.cc b/src/Features2d.cc new file mode 100644 index 0000000..b0654e7 --- /dev/null +++ b/src/Features2d.cc @@ -0,0 +1,105 @@ +#include "Features2d.h" +#include "Matrix.h" +#include +#include + +#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4 + +void +Features::Init(Handle target) { + NanScope(); + + NODE_SET_METHOD(target, "ImageSimilarity", Similarity); +}; + +class AsyncDetectSimilarity : public NanAsyncWorker { + public: + AsyncDetectSimilarity(NanCallback *callback, cv::Mat image1, cv::Mat image2) : NanAsyncWorker(callback), image1(image1), image2(image2), dissimilarity(0) {} + ~AsyncDetectSimilarity() {} + + void Execute () { + + cv::Ptr detector = cv::FeatureDetector::create("ORB"); + cv::Ptr extractor = cv::DescriptorExtractor::create("ORB"); + cv::Ptr matcher = cv::DescriptorMatcher::create("BruteForce-Hamming"); + + std::vector matches; + + cv::Mat descriptors1 = cv::Mat(); + cv::Mat descriptors2 = cv::Mat(); + + std::vector keypoints1; + std::vector keypoints2; + + detector->detect(image1, keypoints1); + detector->detect(image2, keypoints2); + + extractor->compute(image1, keypoints1, descriptors1); + extractor->compute(image2, keypoints2, descriptors2); + + matcher->match(descriptors1, descriptors2, matches); + + double max_dist = 0; + double min_dist = 100; + + //-- Quick calculation of max and min distances between keypoints + for (int i = 0; i < descriptors1.rows; i++) { + double dist = matches[i].distance; + if( dist < min_dist ) min_dist = dist; + if( dist > max_dist ) max_dist = dist; + } + + //-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist, + //-- or a small arbitary value ( 0.02 ) in the event that min_dist is very + //-- small) + //-- PS.- radiusMatch can also be used here. + std::vector good_matches; + double good_matches_sum = 0.0; + + for (int i = 0; i < descriptors1.rows; i++ ) { + double distance = matches[i].distance; + if (distance <= std::max(2*min_dist, 0.02)) { + good_matches.push_back(matches[i]); + good_matches_sum += distance; + } + } + + dissimilarity = (double)good_matches_sum / (double)good_matches.size(); + + } + + void HandleOKCallback () { + NanScope(); + + Handle argv[2]; + + argv[0] = NanNull(); + argv[1] = NanNew(dissimilarity); + + callback->Call(2, argv); + + } + + private: + cv::Mat image1; + cv::Mat image2; + double dissimilarity; + +}; + +NAN_METHOD(Features::Similarity) { + NanScope(); + + REQ_FUN_ARG(2, cb); + + cv::Mat image1 = ObjectWrap::Unwrap(args[0]->ToObject())->mat; + cv::Mat image2 = ObjectWrap::Unwrap(args[1]->ToObject())->mat; + + NanCallback *callback = new NanCallback(cb.As()); + + NanAsyncQueueWorker( new AsyncDetectSimilarity(callback, image1, image2) ); + NanReturnUndefined(); + +}; + +#endif diff --git a/src/Features2d.h b/src/Features2d.h new file mode 100644 index 0000000..07062af --- /dev/null +++ b/src/Features2d.h @@ -0,0 +1,16 @@ +#include "OpenCV.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4 + +#include +#include + +class Features: public node::ObjectWrap { + public: + static Persistent constructor; + static void Init(Handle target); + + static NAN_METHOD(Similarity); +}; + +#endif diff --git a/src/init.cc b/src/init.cc index a107061..8d9171e 100755 --- a/src/init.cc +++ b/src/init.cc @@ -8,6 +8,7 @@ #include "CamShift.h" #include "HighGUI.h" #include "FaceRecognizer.h" +#include "Features2d.h" #include "Constants.h" #include "Calib3D.h" #include "ImgProc.h" @@ -23,7 +24,7 @@ init(Handle target) { CascadeClassifierWrap::Init(target); VideoCaptureWrap::Init(target); Contour::Init(target); - TrackedObject::Init(target); + TrackedObject::Init(target); NamedWindow::Init(target); Constants::Init(target); Calib3D::Init(target); @@ -34,7 +35,8 @@ init(Handle target) { #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4 - FaceRecognizerWrap::Init(target); + Features::Init(target); + FaceRecognizerWrap::Init(target); #endif };