From 056b6cd68e5c80c86b1877fe8234fd7acc0a6190 Mon Sep 17 00:00:00 2001 From: Oskar Dahlberg Date: Thu, 11 Sep 2014 16:59:22 +0200 Subject: [PATCH 1/8] New method for filtering template matches --- src/Matrix.cc | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/Matrix.h | 1 + 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/Matrix.cc b/src/Matrix.cc index 8dfc669..e338449 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -96,7 +96,8 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "floodFill", FloodFill); - NODE_SET_PROTOTYPE_METHOD(constructor, "matchTemplate", MatchTemplate); + NODE_SET_PROTOTYPE_METHOD(constructor, "matchTemplate", MatchTemplate); + NODE_SET_PROTOTYPE_METHOD(constructor, "templateMatches", TemplateMatches); NODE_SET_PROTOTYPE_METHOD(constructor, "minMaxLoc", MinMaxLoc); NODE_SET_PROTOTYPE_METHOD(constructor, "pushBack", PushBack); @@ -1719,6 +1720,87 @@ Matrix::FloodFill(const Arguments& args){ return scope.Close(Number::New( ret )); } +// @author olfox +// Returns an array of the most probable positions +// Usage: output = input.templateMatches(min_probability, max_probability, limit, ascending, min_x_distance, min_y_distance); +Handle +Matrix::TemplateMatches(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + bool filter_min_probability = (args.Length() >= 1) ? args[0]->IsNumber() : false; + bool filter_max_probability = (args.Length() >= 2) ? args[1]->IsNumber() : false; + double min_probability = filter_min_probability ? args[0]->NumberValue() : 0; + double max_probability = filter_max_probability ? args[1]->NumberValue() : 0; + int limit = (args.Length() >= 3) ? args[2]->IntegerValue() : 0; + bool ascending = (args.Length() >= 4) ? args[3]->BooleanValue() : false; + int min_x_distance = (args.Length() >= 5) ? args[4]->IntegerValue() : 0; + int min_y_distance = (args.Length() >= 6) ? args[5]->IntegerValue() : 0; + + cv::Mat_ indices; + + if (ascending) + cv::sortIdx(self->mat.reshape(0,1), indices, CV_SORT_ASCENDING + CV_SORT_EVERY_ROW); + else + cv::sortIdx(self->mat.reshape(0,1), indices, CV_SORT_DESCENDING + CV_SORT_EVERY_ROW); + + cv::Mat hit_mask = cv::Mat::zeros(self->mat.size(), CV_64F); + v8::Local probabilites_array = v8::Array::New(); + + cv::Mat_::const_iterator begin = self->mat.begin(); + cv::Mat_::const_iterator it = indices.begin(); + cv::Mat_::const_iterator end = indices.end(); + int index = 0; + for (; (limit == 0 || index < limit) && it != end; ++it) { + cv::Point pt = (begin + *it).pos(); + + float probability = self->mat.at(pt.y, pt.x); + + if (filter_min_probability && probability < min_probability) { + if (ascending) continue; + else break; + } + + if (filter_max_probability && probability > max_probability) { + if (ascending) break; + else continue; + } + + if (min_x_distance != 0 || min_y_distance != 0) { + // Check hit mask color for for every corner + + cv::Size maxSize = hit_mask.size(); + int max_x = maxSize.width - 1; + int max_y = maxSize.height - 1; + cv::Point top_left = cv::Point(max(0, pt.x - min_x_distance), max(0, pt.y - min_y_distance)); + cv::Point top_right = cv::Point(min(max_x, pt.x + min_x_distance), max(0, pt.y - min_y_distance)); + cv::Point bottom_left = cv::Point(max(0, pt.x - min_x_distance), min(max_y, pt.y + min_y_distance)); + cv::Point bottom_right = cv::Point(min(max_x, pt.x + min_x_distance), min(max_y, pt.y + min_y_distance)); + if (hit_mask.at(top_left.y, top_left.x) > 0) continue; + if (hit_mask.at(top_right.y, top_right.x) > 0) continue; + if (hit_mask.at(bottom_left.y, bottom_left.x) > 0) continue; + if (hit_mask.at(bottom_right.y, bottom_right.x) > 0) continue; + cv::Scalar color(255.0); + cv::rectangle(hit_mask, top_left, bottom_right, color, CV_FILLED); + } + + Local x_value = v8::Number::New(pt.x); + Local y_value = v8::Number::New(pt.y); + Local probability_value = v8::Number::New(probability); + + Local probability_object = Object::New(); + probability_object->Set(String::NewSymbol("x"), x_value); + probability_object->Set(String::NewSymbol("y"), y_value); + probability_object->Set(String::NewSymbol("probability"), probability_value); + + probabilites_array->Set(index, probability_object); + index++; + } + + return scope.Close(probabilites_array); +} + // @author ytham // Match Template filter // Usage: output = input.matchTemplate(templateMatrix, method); diff --git a/src/Matrix.h b/src/Matrix.h index 3331e44..083ac6a 100755 --- a/src/Matrix.h +++ b/src/Matrix.h @@ -91,6 +91,7 @@ class Matrix: public node::ObjectWrap { JSFUNC(FloodFill) JSFUNC(MatchTemplate) + JSFUNC(TemplateMatches) JSFUNC(MinMaxLoc) JSFUNC(PushBack) From 037fa6a7a595828ff9494771658d4baa96d475d6 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Wed, 4 Feb 2015 13:27:11 -0500 Subject: [PATCH 2/8] Removed unused code to avoid compile warning --- src/BackgroundSubtractor.cc | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/BackgroundSubtractor.cc b/src/BackgroundSubtractor.cc index e9de264..18a581c 100644 --- a/src/BackgroundSubtractor.cc +++ b/src/BackgroundSubtractor.cc @@ -21,7 +21,7 @@ BackgroundSubtractorWrap::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(ctor, "applyMOG", ApplyMOG); target->Set(NanNew("BackgroundSubtractor"), ctor->GetFunction()); - + }; NAN_METHOD(BackgroundSubtractorWrap::New) { @@ -42,17 +42,17 @@ NAN_METHOD(BackgroundSubtractorWrap::New) { NAN_METHOD(BackgroundSubtractorWrap::CreateMOG) { NanScope(); - int history = 200; - int nmixtures = 5; - double backgroundRatio = 0.7; - double noiseSigma = 0; - - if(args.Length() > 1){ - INT_FROM_ARGS(history, 0) - INT_FROM_ARGS(nmixtures, 1) - DOUBLE_FROM_ARGS(backgroundRatio, 2) - DOUBLE_FROM_ARGS(noiseSigma, 3) - } + // int history = 200; + // int nmixtures = 5; + // double backgroundRatio = 0.7; + // double noiseSigma = 0; + // + // if(args.Length() > 1){ + // INT_FROM_ARGS(history, 0) + // INT_FROM_ARGS(nmixtures, 1) + // DOUBLE_FROM_ARGS(backgroundRatio, 2) + // DOUBLE_FROM_ARGS(noiseSigma, 3) + // } Local n = NanNew(BackgroundSubtractorWrap::constructor)->GetFunction()->NewInstance(); @@ -83,13 +83,13 @@ NAN_METHOD(BackgroundSubtractorWrap::ApplyMOG) { Local fgMask = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); Matrix *img = ObjectWrap::Unwrap(fgMask); - + cv::Mat mat; - + if(Buffer::HasInstance(args[0])){ uint8_t *buf = (uint8_t *) Buffer::Data(args[0]->ToObject()); - unsigned len = Buffer::Length(args[0]->ToObject()); + unsigned len = Buffer::Length(args[0]->ToObject()); cv::Mat *mbuf = new cv::Mat(len, 1, CV_64FC1, buf); mat = cv::imdecode(*mbuf, -1); //mbuf->release(); @@ -116,13 +116,13 @@ NAN_METHOD(BackgroundSubtractorWrap::ApplyMOG) { TryCatch try_catch; cb->Call(NanGetCurrentContext()->Global(), 2, argv); - + if (try_catch.HasCaught()) { FatalException(try_catch); } NanReturnUndefined(); - } + } catch( cv::Exception& e ){ const char* err_msg = e.what(); NanThrowError(err_msg); From 373fa339f71a19046f0b363aaa25ca6642dee153 Mon Sep 17 00:00:00 2001 From: Peter Braden Date: Wed, 11 Feb 2015 18:35:00 +0100 Subject: [PATCH 3/8] Remove unused 'sleep_for' variable to suppress compile warning --- src/CascadeClassifierWrap.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/CascadeClassifierWrap.cc b/src/CascadeClassifierWrap.cc index d2f8871..ac8a35f 100755 --- a/src/CascadeClassifierWrap.cc +++ b/src/CascadeClassifierWrap.cc @@ -50,7 +50,7 @@ CascadeClassifierWrap::CascadeClassifierWrap(v8::Value* fileName){ class AsyncDetectMultiScale : public NanAsyncWorker { public: - AsyncDetectMultiScale(NanCallback *callback, CascadeClassifierWrap *cc, Matrix* im, double scale, int neighbors, int minw, int minh, int sleep_for) : NanAsyncWorker(callback), cc(cc), im(im), scale(scale), neighbors(neighbors), minw(minw), minh(minh), sleep_for(sleep_for) {} + AsyncDetectMultiScale(NanCallback *callback, CascadeClassifierWrap *cc, Matrix* im, double scale, int neighbors, int minw, int minh) : NanAsyncWorker(callback), cc(cc), im(im), scale(scale), neighbors(neighbors), minw(minw), minh(minh) {} ~AsyncDetectMultiScale() {} void Execute () { @@ -103,7 +103,6 @@ class AsyncDetectMultiScale : public NanAsyncWorker { int neighbors; int minw; int minh; - int sleep_for; std::vector res; }; @@ -141,7 +140,7 @@ NAN_METHOD(CascadeClassifierWrap::DetectMultiScale){ NanCallback *callback = new NanCallback(cb.As()); - NanAsyncQueueWorker( new AsyncDetectMultiScale(callback, self, im, scale, neighbors, minw, minh, 1) ); + NanAsyncQueueWorker( new AsyncDetectMultiScale(callback, self, im, scale, neighbors, minw, minh) ); NanReturnUndefined(); } From 03ce7973bf39988cc428bdf14f4b62c7538d3fc6 Mon Sep 17 00:00:00 2001 From: Peter Braden Date: Wed, 11 Feb 2015 19:20:19 +0100 Subject: [PATCH 4/8] Use Nan for template matches --- src/Matrix.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Matrix.cc b/src/Matrix.cc index 40b9dc8..d1f5382 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -1730,11 +1730,8 @@ NAN_METHOD(Matrix::FloodFill){ // @author olfox // Returns an array of the most probable positions // Usage: output = input.templateMatches(min_probability, max_probability, limit, ascending, min_x_distance, min_y_distance); -Handle -Matrix::TemplateMatches(const v8::Arguments& args) { - HandleScope scope; - - Matrix *self = ObjectWrap::Unwrap(args.This()); +NAN_METHOD(Matrix::TemplateMatches){ + SETUP_FUNCTION(Matrix) bool filter_min_probability = (args.Length() >= 1) ? args[0]->IsNumber() : false; bool filter_max_probability = (args.Length() >= 2) ? args[1]->IsNumber() : false; From ae5887c4cd21a145124074bd45164657fc325053 Mon Sep 17 00:00:00 2001 From: Peter Braden Date: Wed, 11 Feb 2015 19:44:38 +0100 Subject: [PATCH 5/8] Use Nan for rest of the method --- src/Matrix.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Matrix.cc b/src/Matrix.cc index d1f5382..1f0b9d9 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -1750,7 +1750,7 @@ NAN_METHOD(Matrix::TemplateMatches){ cv::sortIdx(self->mat.reshape(0,1), indices, CV_SORT_DESCENDING + CV_SORT_EVERY_ROW); cv::Mat hit_mask = cv::Mat::zeros(self->mat.size(), CV_64F); - v8::Local probabilites_array = v8::Array::New(); + v8::Local probabilites_array = NanNew(limit); cv::Mat_::const_iterator begin = self->mat.begin(); cv::Mat_::const_iterator it = indices.begin(); @@ -1789,20 +1789,20 @@ NAN_METHOD(Matrix::TemplateMatches){ cv::rectangle(hit_mask, top_left, bottom_right, color, CV_FILLED); } - Local x_value = v8::Number::New(pt.x); - Local y_value = v8::Number::New(pt.y); - Local probability_value = v8::Number::New(probability); + Local x_value = NanNew(pt.x); + Local y_value = NanNew(pt.y); + Local probability_value = NanNew(probability); - Local probability_object = Object::New(); - probability_object->Set(String::NewSymbol("x"), x_value); - probability_object->Set(String::NewSymbol("y"), y_value); - probability_object->Set(String::NewSymbol("probability"), probability_value); + Local probability_object = NanNew(); + probability_object->Set(NanNew("x"), x_value); + probability_object->Set(NanNew("y"), y_value); + probability_object->Set(NanNew("probability"), probability_value); probabilites_array->Set(index, probability_object); index++; } - return scope.Close(probabilites_array); + NanReturnValue(probabilites_array); } // @author ytham From 4618b158804b1301444498e0339ad2d334b64c3d Mon Sep 17 00:00:00 2001 From: Peter Braden Date: Wed, 11 Feb 2015 19:45:13 +0100 Subject: [PATCH 6/8] Travis test 0.12 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index eae5110..52ec0ef 100755 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: node_js node_js: - "0.10" - "0.11" + - "0.12" before_install: - sudo apt-get update From 9e4f904da76433164ff768fd1e2c6aadd409d052 Mon Sep 17 00:00:00 2001 From: Peter Braden Date: Wed, 11 Feb 2015 19:52:11 +0100 Subject: [PATCH 7/8] Keep changelog up to date --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86c9edb..6247af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ # Changelog +### Next + +- Support for node 0.12 +- Camera Calibration Functions from @queuecumber +- Fix for Nan 1.5.1 from @IMGNRY +- More build fixes from @scanlime +- Matrix crop prototype from @dbpieter +- Many fixes from @madshall + +Thanks to everyone that contributed! + + ### 1.0.0 Ok, let's do a proper semver release :) From 081ca6056fac34716b212d62f1224c9f662ac99e Mon Sep 17 00:00:00 2001 From: Peter Braden Date: Wed, 11 Feb 2015 19:52:50 +0100 Subject: [PATCH 8/8] Much overdue release. 2.0.0 --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6247af4..d5a7a62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Changelog -### Next +### 2.0.0 - Support for node 0.12 - Camera Calibration Functions from @queuecumber diff --git a/package.json b/package.json index 7ce4b0a..0401826 100755 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "buffers": "0.1.1", "nan": "1.4.3" }, - "version": "1.0.0", + "version": "2.0.0", "devDependencies": { "tape": "^3.0.0" },