diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.travis.yml b/.travis.yml old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/TODO b/TODO old mode 100644 new mode 100755 index 9a897e3..10f9c14 --- a/TODO +++ b/TODO @@ -42,4 +42,4 @@ cv.loadImage('test.jpg', function(err, im){ http://www.athile.net/library/wiki/index.php?title=Library/V8/Tutorial#Wrapping_a_Javascript_function_as_a_std::function.3C.3E -https://www.cloudkick.com/blog/2010/aug/23/writing-nodejs-native-extensions/ \ No newline at end of file +https://www.cloudkick.com/blog/2010/aug/23/writing-nodejs-native-extensions/ diff --git a/binding.gyp b/binding.gyp old mode 100644 new mode 100755 diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..3929a7a --- /dev/null +++ b/build.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +node-waf configure build && +cd examples && +#node face_detection.js +node $1 diff --git a/data/haarcascade_eye.xml b/data/haarcascade_eye.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_eye_tree_eyeglasses.xml b/data/haarcascade_eye_tree_eyeglasses.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_frontalface_alt.xml b/data/haarcascade_frontalface_alt.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_frontalface_alt2.xml b/data/haarcascade_frontalface_alt2.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_frontalface_alt_tree.xml b/data/haarcascade_frontalface_alt_tree.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_frontalface_default.xml b/data/haarcascade_frontalface_default.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_fullbody.xml b/data/haarcascade_fullbody.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_lefteye_2splits.xml b/data/haarcascade_lefteye_2splits.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_lowerbody.xml b/data/haarcascade_lowerbody.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_mcs_eyepair_big.xml b/data/haarcascade_mcs_eyepair_big.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_mcs_eyepair_small.xml b/data/haarcascade_mcs_eyepair_small.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_mcs_lefteye.xml b/data/haarcascade_mcs_lefteye.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_mcs_mouth.xml b/data/haarcascade_mcs_mouth.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_mcs_nose.xml b/data/haarcascade_mcs_nose.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_mcs_righteye.xml b/data/haarcascade_mcs_righteye.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_mcs_upperbody.xml b/data/haarcascade_mcs_upperbody.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_profileface.xml b/data/haarcascade_profileface.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_righteye_2splits.xml b/data/haarcascade_righteye_2splits.xml old mode 100644 new mode 100755 diff --git a/data/haarcascade_upperbody.xml b/data/haarcascade_upperbody.xml old mode 100644 new mode 100755 diff --git a/doc b/doc new file mode 100755 index 0000000..71198c2 --- /dev/null +++ b/doc @@ -0,0 +1,61 @@ +Examples +Face Detection + + cv.readImage("./examples/test.jpg", function(err, im){ + im.detectObject("./examples/haarcascade_frontalface_alt.xml", {}, function(err, faces){ + for (var i=0;i maxArea) { + big.drawContour(contours, i, GREEN); + } + } + + all.drawAllContours(contours, WHITE); + + + big.save('/tmp/big.png'); + all.save('/tmp/all.png'); +}); diff --git a/examples/convert_image.js b/examples/convert_image.js new file mode 100755 index 0000000..eeb88da --- /dev/null +++ b/examples/convert_image.js @@ -0,0 +1,18 @@ +var cv = require('../lib/opencv'); + + +cv.readImage("./mona.png", function(err, im) { + + img_hsv = im.copy(); + img_gray = im.copy(); + + img_hsv.convertHSVscale(); + img_gray.convertGrayscale(); + + im.save("/tmp/nor.png"); + img_hsv.save("/tmp/hsv.png"); + img_gray.save("/tmp/gray.png"); + + console.log("Guardado"); +}); + diff --git a/examples/face-proxy.js b/examples/face-proxy.js old mode 100644 new mode 100755 diff --git a/examples/face_detection.js b/examples/face_detection.js new file mode 100755 index 0000000..4538973 --- /dev/null +++ b/examples/face_detection.js @@ -0,0 +1,18 @@ +var cv = require('../lib/opencv') + , assert = require('assert') + , fs =require('fs') + + +//console.log(cv.version) +cv.readImage("./mona.png", function(err, im){ + + im.detectObject("./haarcascade_frontalface_alt.xml", {}, function(err, faces){ + + for (var i=0;i CascadeClassifierWrap::constructor; @@ -61,6 +63,8 @@ struct classifier_baton_t { int minh; int sleep_for; std::vector res; + + uv_work_t request; }; @@ -102,42 +106,47 @@ CascadeClassifierWrap::DetectMultiScale(const v8::Arguments& args){ baton->minw = minw; baton->minh = minh; baton->sleep_for = 1; - self->Ref(); + baton->request.data = baton; +// self->Ref(); - eio_custom(EIO_DetectMultiScale, EIO_PRI_DEFAULT, EIO_AfterDetectMultiScale, baton); - ev_ref(EV_DEFAULT_UC); +// eio_custom(EIO_DetectMultiScale, EIO_PRI_DEFAULT, EIO_AfterDetectMultiScale, baton); +// ev_ref(EV_DEFAULT_UC); + + uv_queue_work(uv_default_loop(), &baton->request, AsyncDetectMultiScale, AfterAsyncDetectMultiScale); return Undefined(); } - -void -CascadeClassifierWrap::EIO_DetectMultiScale(eio_req *req){ + +void AsyncDetectMultiScale(uv_work_t *req) { classifier_baton_t *baton = static_cast(req->data); - sleep(baton->sleep_for); - +// sleep(baton->sleep_for); std::vector objects; cv::Mat gray; - cvtColor( baton->im->mat, gray, CV_BGR2GRAY ); - equalizeHist( gray, gray); + if(baton->im->mat.channels() != 1) + cvtColor(baton->im->mat, gray, CV_BGR2GRAY); + + equalizeHist( gray, gray); baton->cc->cc.detectMultiScale(gray, objects, baton->scale, baton->neighbors, 0, cv::Size(baton->minw, baton->minh)); baton->res = objects; + + } -int -CascadeClassifierWrap::EIO_AfterDetectMultiScale(eio_req *req){ +void AfterAsyncDetectMultiScale(uv_work_t *req) { + HandleScope scope; classifier_baton_t *baton = static_cast(req->data); - ev_unref(EV_DEFAULT_UC); - baton->cc->Unref(); +// ev_unref(EV_DEFAULT_UC); +// baton->cc->Unref(); Local argv[2]; @@ -169,6 +178,6 @@ CascadeClassifierWrap::EIO_AfterDetectMultiScale(eio_req *req){ delete baton; - return 0; +// return 0; } diff --git a/src/CascadeClassifierWrap.h b/src/CascadeClassifierWrap.h old mode 100644 new mode 100755 index 936c325..e4c7cf0 --- a/src/CascadeClassifierWrap.h +++ b/src/CascadeClassifierWrap.h @@ -16,4 +16,4 @@ class CascadeClassifierWrap: public node::ObjectWrap { static void EIO_DetectMultiScale(eio_req *req); static int EIO_AfterDetectMultiScale(eio_req *req); -}; \ No newline at end of file +}; diff --git a/src/Contours.cc b/src/Contours.cc new file mode 100755 index 0000000..b2f8263 --- /dev/null +++ b/src/Contours.cc @@ -0,0 +1,73 @@ +#include "Contours.h" +#include "OpenCV.h" + +#include + +v8::Persistent Contour::constructor; + + +void +Contour::Init(Handle target) { + HandleScope scope; + + //Class + v8::Local m = v8::FunctionTemplate::New(New); + m->SetClassName(v8::String::NewSymbol("Contours")); + + // Constructor + constructor = Persistent::New(m); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("Contours")); + + // Prototype + Local proto = constructor->PrototypeTemplate(); + + + NODE_SET_PROTOTYPE_METHOD(constructor, "size", Size); + NODE_SET_PROTOTYPE_METHOD(constructor, "area", Area); + target->Set(String::NewSymbol("Contours"), m->GetFunction()); +}; + + +Handle +Contour::New(const Arguments &args) { + HandleScope scope; + + if (args.This()->InternalFieldCount() == 0) + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot instantiate without new"))); + + Contour *contours; + contours = new Contour; + + contours->Wrap(args.Holder()); + return scope.Close(args.Holder()); +} + + +Contour::Contour(): ObjectWrap() { +} + + +Handle +Contour::Size(const Arguments &args) { + HandleScope scope; + + Contour *self = ObjectWrap::Unwrap(args.This()); + + return scope.Close(Number::New(self->contours.size())); + +} + + +Handle +Contour::Area(const Arguments &args) { + HandleScope scope; + + Contour *self = ObjectWrap::Unwrap(args.This()); + int pos = args[0]->NumberValue(); + + //return scope.Close(Number::New(contourArea(self->contours))); + return scope.Close(Number::New(contourArea(cv::Mat(self->contours[pos])))); + + +} diff --git a/src/Contours.h b/src/Contours.h new file mode 100755 index 0000000..cc8d630 --- /dev/null +++ b/src/Contours.h @@ -0,0 +1,18 @@ +#include "OpenCV.h" + +class Contour: public node::ObjectWrap { + public: + + cv::Mat mat; + vector > contours; + static Persistent constructor; + static void Init(Handle target); + static Handle New(const Arguments &args); + + Contour(); + + //JSFUNC(Size) + static Handle Size(const v8::Arguments&); + static Handle Area(const v8::Arguments&); +}; + diff --git a/src/Matrix.cc b/src/Matrix.cc old mode 100644 new mode 100755 index 7460cd0..f7e8c3a --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -1,162 +1,199 @@ +#include "Contours.h" #include "Matrix.h" #include "OpenCV.h" v8::Persistent Matrix::constructor; +cv::Scalar setColor(Local objColor); + +// void Matrix::Init(Handle target) { - HandleScope scope; + HandleScope scope; - //Class - v8::Local m = v8::FunctionTemplate::New(New); - m->SetClassName(v8::String::NewSymbol("Matrix")); + //Class + v8::Local m = v8::FunctionTemplate::New(New); + m->SetClassName(v8::String::NewSymbol("Matrix")); - // Constructor - constructor = Persistent::New(m); - constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(String::NewSymbol("Matrix")); + // Constructor + constructor = Persistent::New(m); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("Matrix")); - // Prototype - Local proto = constructor->PrototypeTemplate(); + // Prototype + Local proto = constructor->PrototypeTemplate(); - NODE_SET_PROTOTYPE_METHOD(constructor, "row", Row); - NODE_SET_PROTOTYPE_METHOD(constructor, "col", Col); + NODE_SET_PROTOTYPE_METHOD(constructor, "row", Row); + NODE_SET_PROTOTYPE_METHOD(constructor, "col", Col); - NODE_SET_PROTOTYPE_METHOD(constructor, "pixelRow", PixelRow); - NODE_SET_PROTOTYPE_METHOD(constructor, "pixelCol", PixelCol); + NODE_SET_PROTOTYPE_METHOD(constructor, "pixelRow", PixelRow); + NODE_SET_PROTOTYPE_METHOD(constructor, "pixelCol", PixelCol); - NODE_SET_PROTOTYPE_METHOD(constructor, "empty", Empty); - NODE_SET_PROTOTYPE_METHOD(constructor, "get", Get); - NODE_SET_PROTOTYPE_METHOD(constructor, "set", Set); - NODE_SET_PROTOTYPE_METHOD(constructor, "width", Width); - NODE_SET_PROTOTYPE_METHOD(constructor, "height", Height); - NODE_SET_PROTOTYPE_METHOD(constructor, "size", Size); - NODE_SET_PROTOTYPE_METHOD(constructor, "toBuffer", ToBuffer); - NODE_SET_PROTOTYPE_METHOD(constructor, "ellipse", Ellipse); - NODE_SET_PROTOTYPE_METHOD(constructor, "save", Save); - NODE_SET_PROTOTYPE_METHOD(constructor, "resize", Resize); + NODE_SET_PROTOTYPE_METHOD(constructor, "empty", Empty); + NODE_SET_PROTOTYPE_METHOD(constructor, "get", Get); + NODE_SET_PROTOTYPE_METHOD(constructor, "set", Set); + NODE_SET_PROTOTYPE_METHOD(constructor, "width", Width); + NODE_SET_PROTOTYPE_METHOD(constructor, "height", Height); + NODE_SET_PROTOTYPE_METHOD(constructor, "size", Size); + NODE_SET_PROTOTYPE_METHOD(constructor, "toBuffer", ToBuffer); + NODE_SET_PROTOTYPE_METHOD(constructor, "ellipse", Ellipse); + NODE_SET_PROTOTYPE_METHOD(constructor, "save", Save); + NODE_SET_PROTOTYPE_METHOD(constructor, "resize", Resize); + NODE_SET_PROTOTYPE_METHOD(constructor, "channels", Channels); - NODE_SET_METHOD(constructor, "Eye", Eye); + NODE_SET_PROTOTYPE_METHOD(constructor, "convertGrayscale", ConvertGrayscale); + NODE_SET_PROTOTYPE_METHOD(constructor, "convertHSVscale", ConvertHSVscale); + NODE_SET_PROTOTYPE_METHOD(constructor, "copy", Copy); + NODE_SET_PROTOTYPE_METHOD(constructor, "ptr", Ptr); + NODE_SET_PROTOTYPE_METHOD(constructor, "addWeighted", AddWeighted); + NODE_SET_PROTOTYPE_METHOD(constructor, "split", Split); + NODE_SET_PROTOTYPE_METHOD(constructor, "bla", Bla); + NODE_SET_PROTOTYPE_METHOD(constructor, "canny", Canny); + NODE_SET_PROTOTYPE_METHOD(constructor, "dilate", Dilate); + + NODE_SET_PROTOTYPE_METHOD(constructor, "findContours", FindContours); + NODE_SET_PROTOTYPE_METHOD(constructor, "drawContour", DrawContour); + NODE_SET_PROTOTYPE_METHOD(constructor, "drawAllContours", DrawAllContours); + + NODE_SET_METHOD(constructor, "Eye", Eye); - target->Set(String::NewSymbol("Matrix"), m->GetFunction()); -}; + target->Set(String::NewSymbol("Matrix"), m->GetFunction()); +}; Handle Matrix::New(const Arguments &args) { - HandleScope scope; + HandleScope scope; - if (args.This()->InternalFieldCount() == 0) - return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot instantiate without new"))); + if (args.This()->InternalFieldCount() == 0) + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot instantiate without new"))); - Matrix *mat; + Matrix *mat; - if (args.Length() == 0){ - mat = new Matrix; - } else if (args.Length() == 2 && args[0]->IsInt32() && args[1]->IsInt32()){ - mat = new Matrix(args[0]->IntegerValue(), args[1]->IntegerValue()); - } - mat->Wrap(args.Holder()); - return scope.Close(args.Holder()); + if (args.Length() == 0){ + mat = new Matrix; + } else if (args.Length() == 2 && args[0]->IsInt32() && args[1]->IsInt32()){ + mat = new Matrix(args[0]->IntegerValue(), args[1]->IntegerValue()); + } + + mat->Wrap(args.Holder()); + return scope.Close(args.Holder()); } + Matrix::Matrix(): ObjectWrap() { - mat = cv::Mat(); + mat = cv::Mat(); } + Matrix::Matrix(int w, int h): ObjectWrap() { mat = cv::Mat(w, h, CV_32FC3); + //TODO:Parametrizar esto + //mat = cv::Mat(h, w, CV_8UC3); } -Handle + +Handle Matrix::Empty(const Arguments& args){ - SETUP_FUNCTION(Matrix) + SETUP_FUNCTION(Matrix) - return scope.Close(Boolean::New(self->mat.empty())); + return scope.Close(Boolean::New(self->mat.empty())); } -Handle +Handle Matrix::Get(const Arguments& args){ - SETUP_FUNCTION(Matrix) + SETUP_FUNCTION(Matrix) - int i = args[0]->IntegerValue(); - int j = args[1]->IntegerValue(); + int i = args[0]->IntegerValue(); + int j = args[1]->IntegerValue(); - return scope.Close(Number::New(self->mat.at(i,j))); + return scope.Close(Number::New(self->mat.at(i,j))); } Handle Matrix::Set(const Arguments& args){ - SETUP_FUNCTION(Matrix) + SETUP_FUNCTION(Matrix) - int i = args[0]->IntegerValue(); - int j = args[1]->IntegerValue(); - double val = args[2]->NumberValue(); + int i = args[0]->IntegerValue(); + int j = args[1]->IntegerValue(); + double val = args[2]->NumberValue(); - self->mat.at(i,j) = val; + if(args.Length() == 4) { + self->mat.at(i,j)[args[3]->NumberValue()] = val; - return scope.Close(Undefined()); + } else if(args.Length() == 3) { + self->mat.at(i,j)[0] = val; + self->mat.at(i,j)[1] = val; + self->mat.at(i,j)[2] = val; + + } else { + return ThrowException(Exception::TypeError(String::New("Invalid number of arguments"))); + } + + return scope.Close(Undefined()); } Handle Matrix::Size(const Arguments& args){ - SETUP_FUNCTION(Matrix) + SETUP_FUNCTION(Matrix) - v8::Local arr = v8::Array::New(2); - arr->Set(0, Number::New(self->mat.size().height)); - arr->Set(1, Number::New(self->mat.size().width)); + v8::Local arr = v8::Array::New(2); + arr->Set(0, Number::New(self->mat.size().height)); + arr->Set(1, Number::New(self->mat.size().width)); - return scope.Close(arr); + return scope.Close(arr); } Handle Matrix::Row(const Arguments& args){ - SETUP_FUNCTION(Matrix) + SETUP_FUNCTION(Matrix) - int width = self->mat.size().width; - int y = args[0]->IntegerValue(); - v8::Local arr = v8::Array::New(width); + int width = self->mat.size().width; + int y = args[0]->IntegerValue(); + v8::Local arr = v8::Array::New(width); - for (int x=0; xmat.channels() == 1){ - v = self->mat.at(y, x); - } else { - // Assume 3 channel RGB - unsigned int val = 0; - cv::Vec3b pixel = self->mat.at(y, x); - val &= (uchar) pixel.val[2]; - val &= ((uchar) pixel.val[1]) << 8; - val &= ((uchar) pixel.val[0]) << 16; - v = (double) val; - } - arr->Set(x, Number::New(v)); - } - return scope.Close(arr); + for (int x=0; xmat.channels() == 1){ + v = self->mat.at(y, x); + } else { + // Assume 3 channel RGB + unsigned int val = 0; + cv::Vec3b pixel = self->mat.at(y, x); + val &= (uchar) pixel.val[2]; + val &= ((uchar) pixel.val[1]) << 8; + val &= ((uchar) pixel.val[0]) << 16; + v = (double) val; + } + arr->Set(x, Number::New(v)); + } + + return scope.Close(arr); } Handle -Matrix::PixelRow(const Arguments& args){ - SETUP_FUNCTION(Matrix) + Matrix::PixelRow(const Arguments& args){ + SETUP_FUNCTION(Matrix) - int width = self->mat.size().width; - int y = args[0]->IntegerValue(); - v8::Local arr = v8::Array::New(width * 3); + int width = self->mat.size().width; + int y = args[0]->IntegerValue(); + v8::Local arr = v8::Array::New(width * 3); - for (int x=0; xmat.at(y, x); - int offset = x * 3; - arr->Set(offset , Number::New((double)pixel.val[0])); - arr->Set(offset + 1, Number::New((double)pixel.val[1])); - arr->Set(offset + 2, Number::New((double)pixel.val[2])); - } - return scope.Close(arr); + for (int x=0; xmat.at(y, x); + int offset = x * 3; + arr->Set(offset , Number::New((double)pixel.val[0])); + arr->Set(offset + 1, Number::New((double)pixel.val[1])); + arr->Set(offset + 2, Number::New((double)pixel.val[2])); +} + + return scope.Close(arr); } Handle @@ -206,46 +243,51 @@ Matrix::PixelCol(const Arguments& args){ Handle Matrix::Width(const Arguments& args){ - SETUP_FUNCTION(Matrix) + SETUP_FUNCTION(Matrix) - return scope.Close(Number::New(self->mat.size().width)); + return scope.Close(Number::New(self->mat.size().width)); } Handle Matrix::Height(const Arguments& args){ - SETUP_FUNCTION(Matrix) + SETUP_FUNCTION(Matrix) - return scope.Close(Number::New(self->mat.size().height)); -} + return scope.Close(Number::New(self->mat.size().height)); +} +Handle +Matrix::Channels(const Arguments& args){ + SETUP_FUNCTION(Matrix) + + return scope.Close(Number::New(self->mat.channels())); +} Handle Matrix::ToBuffer(const v8::Arguments& args){ - SETUP_FUNCTION(Matrix) - - std::vector vec(0); - std::vector params(0);//CV_IMWRITE_JPEG_QUALITY 90 + SETUP_FUNCTION(Matrix) - cv::imencode(".jpg", self->mat, vec, params); + std::vector vec(0); + std::vector params(0);//CV_IMWRITE_JPEG_QUALITY 90 - node::Buffer *buf = node::Buffer::New(vec.size()); - uchar* data = (uchar*) Buffer::Data(buf); - memcpy(data, &vec[0], vec.size()); + cv::imencode(".jpg", self->mat, vec, params); - v8::Local globalObj = v8::Context::GetCurrent()->Global(); - v8::Local bufferConstructor = v8::Local::Cast(globalObj->Get(v8::String::New("Buffer"))); - v8::Handle constructorArgs[3] = {buf->handle_, v8::Integer::New(vec.size()), v8::Integer::New(0)}; - v8::Local actualBuffer = bufferConstructor->NewInstance(3, constructorArgs); + node::Buffer *buf = node::Buffer::New(vec.size()); + uchar* data = (uchar*) Buffer::Data(buf); + memcpy(data, &vec[0], vec.size()); - return scope.Close(actualBuffer); -} + v8::Local globalObj = v8::Context::GetCurrent()->Global(); + v8::Local bufferConstructor = v8::Local::Cast(globalObj->Get(v8::String::New("Buffer"))); + v8::Handle constructorArgs[3] = {buf->handle_, v8::Integer::New(vec.size()), v8::Integer::New(0)}; + v8::Local actualBuffer = bufferConstructor->NewInstance(3, constructorArgs); + + return scope.Close(actualBuffer); +} - // ellipse(x, y, wid, height, angle, startangle, endangle, color, thickness, linetype, shift) Handle Matrix::Ellipse(const v8::Arguments& args){ - SETUP_FUNCTION(Matrix) + SETUP_FUNCTION(Matrix) int x = args[0]->Uint32Value(); int y = args[1]->Uint32Value(); @@ -256,38 +298,250 @@ Matrix::Ellipse(const v8::Arguments& args){ cv::ellipse(self->mat, cv::Point(x, y), cv::Size(width, height), 0, 0, 360, cv::Scalar( (color >> 16) & 0xff , (color >> 8) & 0xff, color & 0xff ), 4, 8, 0); return scope.Close(v8::Null()); -} + } Handle Matrix::Save(const v8::Arguments& args){ - HandleScope scope; + HandleScope scope; - if (!args[0]->IsString()) - return ThrowException(Exception::TypeError(String::New("filename required"))); - - Matrix *self = ObjectWrap::Unwrap(args.This()); - String::AsciiValue filename(args[0]); - int res = cv::imwrite(*filename, self->mat); - return scope.Close(Number::New(res)); + if (!args[0]->IsString()) + return ThrowException(Exception::TypeError(String::New("filename required"))); + + Matrix *self = ObjectWrap::Unwrap(args.This()); + String::AsciiValue filename(args[0]); + int res = cv::imwrite(*filename, self->mat); + return scope.Close(Number::New(res)); } + Handle Matrix::Eye(const v8::Arguments& args){ - HandleScope scope; + HandleScope scope; - int w = args[0]->Uint32Value(); - int h = args[1]->Uint32Value(); + int w = args[0]->Uint32Value(); + int h = args[1]->Uint32Value(); - Local im_h = Matrix::constructor->GetFunction()->NewInstance(); - Matrix *img = ObjectWrap::Unwrap(im_h); - cv::Mat mat = cv::Mat::eye(w, h, CV_32F); + Local im_h = Matrix::constructor->GetFunction()->NewInstance(); + Matrix *img = ObjectWrap::Unwrap(im_h); + cv::Mat mat = cv::Mat::eye(w, h, CV_64FC1); - img->mat = mat; - return scope.Close(im_h); + img->mat = mat; + return scope.Close(im_h); } +Handle +Matrix::ConvertGrayscale(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + if(self->mat.channels() != 3) + return ThrowException(String::New("Image is no 3-channel")); + + cv::Mat gray; + + cv::cvtColor(self->mat, gray, CV_BGR2GRAY); + gray.copyTo(self->mat); + + + return scope.Close(v8::Null()); +} + + +Handle +Matrix::ConvertHSVscale(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + if(self->mat.channels() != 3) + return ThrowException(String::New("Image is no 3-channel")); + + cv::Mat hsv; + + cv::cvtColor(self->mat, hsv, CV_BGR2HSV); + hsv.copyTo(self->mat); + + return scope.Close(v8::Null()); +} + + +Handle +Matrix::Copy(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + Local img_to_return = Matrix::constructor->GetFunction()->NewInstance(); + Matrix *img = ObjectWrap::Unwrap(img_to_return); + self->mat.copyTo(img->mat); + + return scope.Close(img_to_return); +} + + +Handle +Matrix::Ptr(const v8::Arguments& args) { + HandleScope scope; + Matrix *self = ObjectWrap::Unwrap(args.This()); + int line = args[0]->Uint32Value(); + + + char* data = self->mat.ptr(line); + //uchar* data = self->mat.data; + +/* + char *mydata = "Random raw data\0"; +*/ + node::Buffer *return_buffer = Buffer::New((char *)data, self->mat.step); + return scope.Close( return_buffer->handle_ ); + +// return Undefined(); +} + +Handle +Matrix::Bla(const v8::Arguments& args) { + HandleScope scope; + int i = args[1]->Uint32Value(); + + int div = 64; + + if (Buffer::HasInstance(args[0])){ + + char *buf = (char *) Buffer::Data(args[0]->ToObject()); + unsigned len = Buffer::Length(args[0]->ToObject()); + + } + return Undefined(); + +} + + +Handle +Matrix::AddWeighted(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + Matrix *src1 = ObjectWrap::Unwrap(args[0]->ToObject()); + Matrix *src2 = ObjectWrap::Unwrap(args[2]->ToObject()); + + float alpha = args[1]->NumberValue(); + float beta = args[3]->NumberValue(); + int gamma = 0; + + cv::addWeighted(src1->mat, alpha, src2->mat, beta, gamma, self->mat); + + + return scope.Close(v8::Null()); +} + + +Handle +Matrix::Split(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + return scope.Close(v8::Null()); +} + + +Handle +Matrix::Canny(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + int lowThresh = args[0]->NumberValue(); + int highThresh = args[1]->NumberValue(); + + cv::Canny(self->mat, self->mat, lowThresh, highThresh); + + return scope.Close(v8::Null()); +} + + +Handle +Matrix::Dilate(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + int niters = args[0]->NumberValue(); + + cv::dilate(self->mat, self->mat, cv::Mat(), cv::Point(-1, -1), niters); + + return scope.Close(v8::Null()); +} + + +Handle +Matrix::FindContours(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + Local conts_to_return= Contour::constructor->GetFunction()->NewInstance(); + Contour *contours = ObjectWrap::Unwrap(conts_to_return); + + cv::findContours(self->mat, contours->contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); + + return scope.Close(conts_to_return); + +} + + +Handle +Matrix::DrawContour(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + Contour *cont = ObjectWrap::Unwrap(args[0]->ToObject()); + int pos = args[1]->NumberValue(); + + cv::Scalar color(0, 0, 255); + + if(args[2]->IsArray()) { + Local objColor = args[2]->ToObject(); + color = setColor(objColor); + } + + cv::drawContours(self->mat, cont->contours, pos, color, 1); + + return Undefined(); +} + + +Handle +Matrix::DrawAllContours(const v8::Arguments& args) { + HandleScope scope; + + Matrix *self = ObjectWrap::Unwrap(args.This()); + Contour *cont = ObjectWrap::Unwrap(args[0]->ToObject()); + + cv::Scalar color(0, 0, 255); + + if(args[1]->IsArray()) { + Local objColor = args[1]->ToObject(); + color = setColor(objColor); + } + + cv::drawContours(self->mat, cont->contours, -1, color, 1); + + return Undefined(); +} + + +cv::Scalar setColor(Local objColor) { + + Local valB = objColor->Get(0); + Local valG = objColor->Get(1); + Local valR = objColor->Get(2); + + cv::Scalar color = cv::Scalar(valB->IntegerValue(), valG->IntegerValue(), valR->IntegerValue()); + return color; + +} + Handle Matrix::Resize(const v8::Arguments& args){ diff --git a/src/Matrix.h b/src/Matrix.h old mode 100644 new mode 100755 index 959f209..50f32eb --- a/src/Matrix.h +++ b/src/Matrix.h @@ -61,6 +61,7 @@ class Matrix: public node::ObjectWrap { JSFUNC(Size) JSFUNC(Width) JSFUNC(Height) + JSFUNC(Channels) JSFUNC(ToBuffer) JSFUNC(Ellipse) JSFUNC(Empty) @@ -68,6 +69,19 @@ class Matrix: public node::ObjectWrap { JSFUNC(Resize) + JSFUNC(ConvertGrayscale) + JSFUNC(ConvertHSVscale) + JSFUNC(Copy) + JSFUNC(Ptr) + JSFUNC(Bla) + JSFUNC(AddWeighted) + JSFUNC(Split) + JSFUNC(Canny) + JSFUNC(Dilate) + + JSFUNC(FindContours) + JSFUNC(DrawContour) + JSFUNC(DrawAllContours) }; diff --git a/src/OpenCV.cc b/src/OpenCV.cc old mode 100644 new mode 100755 diff --git a/src/OpenCV.h b/src/OpenCV.h old mode 100644 new mode 100755 index e64ddf4..c231d51 --- a/src/OpenCV.h +++ b/src/OpenCV.h @@ -10,6 +10,7 @@ #include #include + using namespace v8; using namespace node; diff --git a/src/Point.cc b/src/Point.cc old mode 100644 new mode 100755 diff --git a/src/Point.h b/src/Point.h old mode 100644 new mode 100755 diff --git a/src/VideoCaptureWrap.cc b/src/VideoCaptureWrap.cc old mode 100644 new mode 100755 index 20bba4c..4ac1d83 --- a/src/VideoCaptureWrap.cc +++ b/src/VideoCaptureWrap.cc @@ -2,64 +2,114 @@ #include "Matrix.h" #include "OpenCV.h" + +void AsyncRead(uv_work_t *req); +void AfterAsyncRead(uv_work_t *req); + v8::Persistent VideoCaptureWrap::constructor; +struct videocapture_baton { + + Persistent cb; + VideoCaptureWrap *vc; + Matrix *im; + + uv_work_t request; +}; + + void VideoCaptureWrap::Init(Handle target) { HandleScope scope; - // Constructor - constructor = Persistent::New(FunctionTemplate::New(VideoCaptureWrap::New)); - constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(String::NewSymbol("VideoCapture")); + // Constructor + constructor = Persistent::New(FunctionTemplate::New(VideoCaptureWrap::New)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("VideoCapture")); - // Prototype - Local proto = constructor->PrototypeTemplate(); - - NODE_SET_PROTOTYPE_METHOD(constructor, "getFrame", GetFrame); + // Prototype + Local proto = constructor->PrototypeTemplate(); - target->Set(String::NewSymbol("VideoCapture"), constructor->GetFunction()); + NODE_SET_PROTOTYPE_METHOD(constructor, "read", Read); + + target->Set(String::NewSymbol("VideoCapture"), constructor->GetFunction()); }; Handle VideoCaptureWrap::New(const Arguments &args) { - HandleScope scope; + HandleScope scope; if (args.This()->InternalFieldCount() == 0) - return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new"))); + return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new"))); - VideoCaptureWrap *v; + VideoCaptureWrap *v; - if (args[0]->IsNumber()){ - v = new VideoCaptureWrap(args[0]->NumberValue()); - } else {} - v->Wrap(args.This()); - return args.This(); + if (args[0]->IsNumber()){ + v = new VideoCaptureWrap(args[0]->NumberValue()); + } else {} + + + v->Wrap(args.This()); + + return args.This(); } - VideoCaptureWrap::VideoCaptureWrap(int device){ - HandleScope scope; - cv::VideoCapture cap(device); + HandleScope scope; + cap.open(device); - if(!cap.isOpened()){ - ThrowException(Exception::Error(String::New("Camera could not be opened"))); - } + if(!cap.isOpened()){ + ThrowException(Exception::Error(String::New("Camera could not be opened"))); + } } Handle -VideoCaptureWrap::GetFrame(const Arguments &args) { - SETUP_FUNCTION(VideoCaptureWrap) +VideoCaptureWrap::Read(const Arguments &args) { - cv::Mat frame; - self->cap.retrieve(frame); + HandleScope scope; + VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); + + REQ_FUN_ARG(0, cb); + + videocapture_baton *baton = new videocapture_baton(); + baton->vc = v; + baton->cb = Persistent::New(cb); + baton->im = new Matrix(); + baton->request.data = baton; + + uv_queue_work(uv_default_loop(), &baton->request, AsyncRead, AfterAsyncRead); + return Undefined(); - Local im_h = Matrix::constructor->GetFunction()->NewInstance(); - Matrix *im = ObjectWrap::Unwrap(im_h); - im->mat = frame; - return scope.Close(im_h); } - +void AsyncRead(uv_work_t *req) { + videocapture_baton *baton = static_cast(req->data); + + baton->vc->cap.read(baton->im->mat); +} + + +void AfterAsyncRead(uv_work_t *req) { + + HandleScope scope; + + videocapture_baton *baton = static_cast(req->data); + + Local im_to_return= Matrix::constructor->GetFunction()->NewInstance(); + Matrix *img = ObjectWrap::Unwrap(im_to_return); + cv::Mat mat; + mat = baton->im->mat; + + img->mat = mat; + Local argv[1]; + + argv[0] = im_to_return; + + baton->cb->Call(Context::GetCurrent()->Global(), 1, argv); + baton->cb.Dispose(); + + delete baton; + +} diff --git a/src/VideoCaptureWrap.h b/src/VideoCaptureWrap.h old mode 100644 new mode 100755 index 56a3514..397ee27 --- a/src/VideoCaptureWrap.h +++ b/src/VideoCaptureWrap.h @@ -11,7 +11,9 @@ class VideoCaptureWrap: public node::ObjectWrap { VideoCaptureWrap(const std::string& filename); VideoCaptureWrap(int device); - static Handle GetFrame(const v8::Arguments&); + static Handle Read(const v8::Arguments&); + + static Handle GetFrameAt(const v8::Arguments&); }; diff --git a/src/init.cc b/src/init.cc old mode 100644 new mode 100755 index a57b03d..b4ea110 --- a/src/init.cc +++ b/src/init.cc @@ -3,6 +3,7 @@ #include "Matrix.h" #include "CascadeClassifierWrap.h" #include "VideoCaptureWrap.h" +#include "Contours.h" extern "C" void @@ -13,4 +14,5 @@ init(Handle target) { Matrix::Init(target); CascadeClassifierWrap::Init(target); VideoCaptureWrap::Init(target); + Contour::Init(target); }; diff --git a/test/unit.js b/test/unit.js old mode 100644 new mode 100755 diff --git a/todo b/todo new file mode 100755 index 0000000..10f9c14 --- /dev/null +++ b/todo @@ -0,0 +1,45 @@ + +im.calcHistograms(function(err, hist){}) + +im.calcHistograms(mask, function(err, hist){}) + + + + + +## Face recognition TODO + + +// Load Database +// TODO< + + + +cv.loadImage('test.jpg', function(err, im){ + im.detectObject("front-face.xml", {}, function(err, faces){ + _.each(faces, function(v){ + + // TODO { + + var section = im.slice(v.x, v.y, v.x + v.width, v.y + v.height); + section.convertGrayscale() + section.resize(WID, HEIGHT); + section.equaliseHistogram(); + + // } TODO + + }) + }) +}) + + + + + + +----- + + +http://www.athile.net/library/wiki/index.php?title=Library/V8/Tutorial#Wrapping_a_Javascript_function_as_a_std::function.3C.3E + +https://www.cloudkick.com/blog/2010/aug/23/writing-nodejs-native-extensions/ diff --git a/wscript b/wscript old mode 100644 new mode 100755