diff --git a/.travis.yml b/.travis.yml index 1508190..e516cf6 100755 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: node_js node_js: - '0.10' - '0.11' + - '0.12' compiler: clang diff --git a/CHANGELOG.md b/CHANGELOG.md index 86c9edb..d5a7a62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ # Changelog +### 2.0.0 + +- 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 :) diff --git a/package.json b/package.json index 1761858..ab83078 100755 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "buffers": "0.1.1", "nan": "1.4.3" }, - "version": "1.0.0", + "version": "2.0.0", "devDependencies": { "tape": "^3.0.0", "aws-sdk": "~2.0.21" diff --git a/src/Matrix.cc b/src/Matrix.cc index 91faa07..1f0b9d9 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -82,6 +82,7 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(ctor, "equalizeHist", EqualizeHist); NODE_SET_PROTOTYPE_METHOD(ctor, "floodFill", FloodFill); NODE_SET_PROTOTYPE_METHOD(ctor, "matchTemplate", MatchTemplate); + NODE_SET_PROTOTYPE_METHOD(ctor, "templateMatches", TemplateMatches); NODE_SET_PROTOTYPE_METHOD(ctor, "minMaxLoc", MinMaxLoc); NODE_SET_PROTOTYPE_METHOD(ctor, "pushBack", PushBack); NODE_SET_PROTOTYPE_METHOD(ctor, "putText", PutText); @@ -1726,6 +1727,84 @@ NAN_METHOD(Matrix::FloodFill){ NanReturnValue(NanNew( 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); +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; + 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 = NanNew(limit); + + 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 = NanNew(pt.x); + Local y_value = NanNew(pt.y); + Local probability_value = NanNew(probability); + + 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++; + } + + NanReturnValue(probabilites_array); +} + // @author ytham // Match Template filter // Usage: output = input.matchTemplate("templateFileString", method); diff --git a/src/Matrix.h b/src/Matrix.h index f041bca..7ea1aa4 100755 --- a/src/Matrix.h +++ b/src/Matrix.h @@ -96,6 +96,7 @@ class Matrix: public node::ObjectWrap { JSFUNC(FloodFill) JSFUNC(MatchTemplate) + JSFUNC(TemplateMatches) JSFUNC(MinMaxLoc) JSFUNC(PushBack)