Merge github.com:talvarez/node-opencv

Conflicts:
	src/Matrix.cc
	src/Matrix.h
This commit is contained in:
Tomas Alvarez 2012-06-19 14:53:52 -03:00
commit 4d1ea2867b
58 changed files with 844 additions and 181 deletions

0
.gitignore vendored Normal file → Executable file
View File

0
.travis.yml Normal file → Executable file
View File

0
README.md Normal file → Executable file
View File

2
TODO Normal file → Executable file
View File

@ -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/
https://www.cloudkick.com/blog/2010/aug/23/writing-nodejs-native-extensions/

0
binding.gyp Normal file → Executable file
View File

6
build.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
node-waf configure build &&
cd examples &&
#node face_detection.js
node $1

0
data/haarcascade_eye.xml Normal file → Executable file
View File

0
data/haarcascade_eye_tree_eyeglasses.xml Normal file → Executable file
View File

0
data/haarcascade_frontalface_alt.xml Normal file → Executable file
View File

0
data/haarcascade_frontalface_alt2.xml Normal file → Executable file
View File

0
data/haarcascade_frontalface_alt_tree.xml Normal file → Executable file
View File

0
data/haarcascade_frontalface_default.xml Normal file → Executable file
View File

0
data/haarcascade_fullbody.xml Normal file → Executable file
View File

0
data/haarcascade_lefteye_2splits.xml Normal file → Executable file
View File

0
data/haarcascade_lowerbody.xml Normal file → Executable file
View File

0
data/haarcascade_mcs_eyepair_big.xml Normal file → Executable file
View File

0
data/haarcascade_mcs_eyepair_small.xml Normal file → Executable file
View File

0
data/haarcascade_mcs_lefteye.xml Normal file → Executable file
View File

0
data/haarcascade_mcs_mouth.xml Normal file → Executable file
View File

0
data/haarcascade_mcs_nose.xml Normal file → Executable file
View File

0
data/haarcascade_mcs_righteye.xml Normal file → Executable file
View File

0
data/haarcascade_mcs_upperbody.xml Normal file → Executable file
View File

0
data/haarcascade_profileface.xml Normal file → Executable file
View File

0
data/haarcascade_righteye_2splits.xml Normal file → Executable file
View File

0
data/haarcascade_upperbody.xml Normal file → Executable file
View File

61
doc Executable file
View File

@ -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<faces.length; i++){
var x = faces[i]
im.ellipse(x.x + x.width/2, x.y + x.height/2, x.width/2, x.height/2);
}
im.save('./out.jpg');
});
})
API Documentation
Matrix
The matrix is the most useful base datastructure in OpenCV. Things like images are just matrices of pixels.
Creation
new Matrix(width, height)
Or you can use opencv to read in image files. Supported formats are in the OpenCV docs, but jpgs etc are supported.
cv.readImage(filename, function(mat){
...
})
cv.readImage(buffer, function(mat){
...
})
If you need to pipe data into an image, you can use an imagestream:
var s = new cv.ImageStream()
s.on('load', function(matrix){
...
})
fs.createReadStream('./examples/test.jpg').pipe(s);
Accessors
var mat = new cv.Matrix.Eye(4,4); // Create identity matrix
mat.get(0,0) // 1
mat.row(0) // [1,0,0,0]
mat.col(4) // [0,0,0,1]
Image Processing
Object Detection
There is a shortcut method for Viola-Jones Haar Cascade object detection. This can be used for face detection etc.
mat.detectObject(haar_cascade_xml, opts, function(err, matches){})
WIP
This is a WIP. I've never written C++ before so the code may be interesting - if I'm doing stuff wrong please feel free to correct me.

16
examples/addweighted.js Executable file
View File

@ -0,0 +1,16 @@
var cv = require('../lib/opencv');
cv.readImage("./mona.png", function(err, orig) {
cv.readImage("./over_text.png", function(err, over_text) {
var result = new cv.Matrix(orig.width(), orig.height());
result.addWeighted(orig, 0.7, over_text, 0.9);
result.save("/tmp/weighted.png");
});
});

13
examples/camera.js Executable file
View File

@ -0,0 +1,13 @@
var cv = require('../lib/opencv');
var camera = new cv.VideoCapture(0);
setInterval(function() {
camera.read(function(im) {
im.save('/tmp/cam.png');
});
}, 1000);

36
examples/contours.js Executable file
View File

@ -0,0 +1,36 @@
var cv = require('../lib/opencv');
var lowThresh = 0;
var highThresh = 100;
var nIters = 2;
var maxArea = 2500;
var GREEN = [0, 255, 0]; //B, G, R
var WHITE = [255, 255, 255]; //B, G, R
cv.readImage('./stuff.png', function(err, im) {
var big = new cv.Matrix(im.width(), im.height());
var all = new cv.Matrix(im.width(), im.height());
im.convertGrayscale();
im_canny = im.copy();
im_canny.canny(lowThresh, highThresh);
im_canny.dilate(nIters);
contours = im_canny.findContours();
for(i = 0; i < contours.size(); i++) {
if(contours.area(i) > maxArea) {
big.drawContour(contours, i, GREEN);
}
}
all.drawAllContours(contours, WHITE);
big.save('/tmp/big.png');
all.save('/tmp/all.png');
});

18
examples/convert_image.js Executable file
View File

@ -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");
});

0
examples/face-proxy.js Normal file → Executable file
View File

18
examples/face_detection.js Executable file
View File

@ -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<faces.length; i++){
var x = faces[i];
im.ellipse(x.x + x.width/2, x.y + x.height/2, x.width/2, x.height/2);
}
im.save('./out.png');
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

BIN
examples/mona.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

BIN
examples/over_text.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

27
examples/salt.js Executable file
View File

@ -0,0 +1,27 @@
var cv = require('../lib/opencv');
cv.readImage("./mona.png", function(err, im) {
salt(im, 3000);
im.save("/tmp/salt.png");
});
function salt(img, n) {
if (img.channels() == 1) {
console.log("1 Canales");
} else if (img.channels() == 3) {
for(k = 0; k < n; k ++) {
i = Math.random() * img.width();
j = Math.random() * img.height();
img.set(j, i, 255);
}
}
}

BIN
examples/stuff.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

0
index.html Normal file → Executable file
View File

0
lib/bindings.js Normal file → Executable file
View File

2
lib/opencv.js Normal file → Executable file
View File

@ -1,5 +1,5 @@
var Stream = require('stream').Stream
, Buffers = require('buffers')
, Buffers = require('buffer')
, util = require('util');
var bindings = require('./bindings')

0
package.json Normal file → Executable file
View File

View File

@ -14,4 +14,4 @@ var cv = require('./lib/opencv')
im.save('./out.jpg');
});
})
})

39
src/CascadeClassifierWrap.cc Normal file → Executable file
View File

@ -3,6 +3,8 @@
#include "Matrix.h"
void AsyncDetectMultiScale(uv_work_t *req);
void AfterAsyncDetectMultiScale(uv_work_t *req);
Persistent<FunctionTemplate> CascadeClassifierWrap::constructor;
@ -61,6 +63,8 @@ struct classifier_baton_t {
int minh;
int sleep_for;
std::vector<cv::Rect> 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<classifier_baton_t *>(req->data);
sleep(baton->sleep_for);
// sleep(baton->sleep_for);
std::vector<cv::Rect> 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<classifier_baton_t *>(req->data);
ev_unref(EV_DEFAULT_UC);
baton->cc->Unref();
// ev_unref(EV_DEFAULT_UC);
// baton->cc->Unref();
Local<Value> argv[2];
@ -169,6 +178,6 @@ CascadeClassifierWrap::EIO_AfterDetectMultiScale(eio_req *req){
delete baton;
return 0;
// return 0;
}

2
src/CascadeClassifierWrap.h Normal file → Executable file
View File

@ -16,4 +16,4 @@ class CascadeClassifierWrap: public node::ObjectWrap {
static void EIO_DetectMultiScale(eio_req *req);
static int EIO_AfterDetectMultiScale(eio_req *req);
};
};

73
src/Contours.cc Executable file
View File

@ -0,0 +1,73 @@
#include "Contours.h"
#include "OpenCV.h"
#include <iostream>
v8::Persistent<FunctionTemplate> Contour::constructor;
void
Contour::Init(Handle<Object> target) {
HandleScope scope;
//Class
v8::Local<v8::FunctionTemplate> m = v8::FunctionTemplate::New(New);
m->SetClassName(v8::String::NewSymbol("Contours"));
// Constructor
constructor = Persistent<FunctionTemplate>::New(m);
constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(String::NewSymbol("Contours"));
// Prototype
Local<ObjectTemplate> 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<Value>
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<Value>
Contour::Size(const Arguments &args) {
HandleScope scope;
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
return scope.Close(Number::New(self->contours.size()));
}
Handle<Value>
Contour::Area(const Arguments &args) {
HandleScope scope;
Contour *self = ObjectWrap::Unwrap<Contour>(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]))));
}

18
src/Contours.h Executable file
View File

@ -0,0 +1,18 @@
#include "OpenCV.h"
class Contour: public node::ObjectWrap {
public:
cv::Mat mat;
vector<vector<cv::Point> > contours;
static Persistent<FunctionTemplate> constructor;
static void Init(Handle<Object> target);
static Handle<Value> New(const Arguments &args);
Contour();
//JSFUNC(Size)
static Handle<Value> Size(const v8::Arguments&);
static Handle<Value> Area(const v8::Arguments&);
};

512
src/Matrix.cc Normal file → Executable file
View File

@ -1,162 +1,199 @@
#include "Contours.h"
#include "Matrix.h"
#include "OpenCV.h"
v8::Persistent<FunctionTemplate> Matrix::constructor;
cv::Scalar setColor(Local<Object> objColor);
//
void
Matrix::Init(Handle<Object> target) {
HandleScope scope;
HandleScope scope;
//Class
v8::Local<v8::FunctionTemplate> m = v8::FunctionTemplate::New(New);
m->SetClassName(v8::String::NewSymbol("Matrix"));
//Class
v8::Local<v8::FunctionTemplate> m = v8::FunctionTemplate::New(New);
m->SetClassName(v8::String::NewSymbol("Matrix"));
// Constructor
constructor = Persistent<FunctionTemplate>::New(m);
constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(String::NewSymbol("Matrix"));
// Constructor
constructor = Persistent<FunctionTemplate>::New(m);
constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(String::NewSymbol("Matrix"));
// Prototype
Local<ObjectTemplate> proto = constructor->PrototypeTemplate();
// Prototype
Local<ObjectTemplate> 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<Value>
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<Value>
Handle<Value>
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<Value>
Handle<Value>
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<double>(i,j)));
return scope.Close(Number::New(self->mat.at<double>(i,j)));
}
Handle<Value>
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<double>(i,j) = val;
if(args.Length() == 4) {
self->mat.at<cv::Vec3b>(i,j)[args[3]->NumberValue()] = val;
return scope.Close(Undefined());
} else if(args.Length() == 3) {
self->mat.at<cv::Vec3b>(i,j)[0] = val;
self->mat.at<cv::Vec3b>(i,j)[1] = val;
self->mat.at<cv::Vec3b>(i,j)[2] = val;
} else {
return ThrowException(Exception::TypeError(String::New("Invalid number of arguments")));
}
return scope.Close(Undefined());
}
Handle<Value>
Matrix::Size(const Arguments& args){
SETUP_FUNCTION(Matrix)
SETUP_FUNCTION(Matrix)
v8::Local<v8::Array> 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<v8::Array> 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<Value>
Matrix::Row(const Arguments& args){
SETUP_FUNCTION(Matrix)
SETUP_FUNCTION(Matrix)
int width = self->mat.size().width;
int y = args[0]->IntegerValue();
v8::Local<v8::Array> arr = v8::Array::New(width);
int width = self->mat.size().width;
int y = args[0]->IntegerValue();
v8::Local<v8::Array> arr = v8::Array::New(width);
for (int x=0; x<width; x++){
double v = 0;
if (self->mat.channels() == 1){
v = self->mat.at<float>(y, x);
} else {
// Assume 3 channel RGB
unsigned int val = 0;
cv::Vec3b pixel = self->mat.at<cv::Vec3b>(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; x<width; x++){
double v = 0;
if (self->mat.channels() == 1){
v = self->mat.at<float>(y, x);
} else {
// Assume 3 channel RGB
unsigned int val = 0;
cv::Vec3b pixel = self->mat.at<cv::Vec3b>(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<Value>
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<v8::Array> arr = v8::Array::New(width * 3);
int width = self->mat.size().width;
int y = args[0]->IntegerValue();
v8::Local<v8::Array> arr = v8::Array::New(width * 3);
for (int x=0; x<width; x++){
cv::Vec3b pixel = self->mat.at<cv::Vec3b>(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; x<width; x++){
cv::Vec3b pixel = self->mat.at<cv::Vec3b>(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<Value>
@ -206,46 +243,51 @@ Matrix::PixelCol(const Arguments& args){
Handle<Value>
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<Value>
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<Value>
Matrix::Channels(const Arguments& args){
SETUP_FUNCTION(Matrix)
return scope.Close(Number::New(self->mat.channels()));
}
Handle<Value>
Matrix::ToBuffer(const v8::Arguments& args){
SETUP_FUNCTION(Matrix)
std::vector<uchar> vec(0);
std::vector<int> params(0);//CV_IMWRITE_JPEG_QUALITY 90
SETUP_FUNCTION(Matrix)
cv::imencode(".jpg", self->mat, vec, params);
std::vector<uchar> vec(0);
std::vector<int> 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<v8::Object> globalObj = v8::Context::GetCurrent()->Global();
v8::Local<v8::Function> bufferConstructor = v8::Local<v8::Function>::Cast(globalObj->Get(v8::String::New("Buffer")));
v8::Handle<v8::Value> constructorArgs[3] = {buf->handle_, v8::Integer::New(vec.size()), v8::Integer::New(0)};
v8::Local<v8::Object> 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<v8::Object> globalObj = v8::Context::GetCurrent()->Global();
v8::Local<v8::Function> bufferConstructor = v8::Local<v8::Function>::Cast(globalObj->Get(v8::String::New("Buffer")));
v8::Handle<v8::Value> constructorArgs[3] = {buf->handle_, v8::Integer::New(vec.size()), v8::Integer::New(0)};
v8::Local<v8::Object> actualBuffer = bufferConstructor->NewInstance(3, constructorArgs);
return scope.Close(actualBuffer);
}
// ellipse(x, y, wid, height, angle, startangle, endangle, color, thickness, linetype, shift)
Handle<Value>
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<Value>
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<Matrix>(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<Matrix>(args.This());
String::AsciiValue filename(args[0]);
int res = cv::imwrite(*filename, self->mat);
return scope.Close(Number::New(res));
}
Handle<Value>
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<Object> im_h = Matrix::constructor->GetFunction()->NewInstance();
Matrix *img = ObjectWrap::Unwrap<Matrix>(im_h);
cv::Mat mat = cv::Mat::eye(w, h, CV_32F);
Local<Object> im_h = Matrix::constructor->GetFunction()->NewInstance();
Matrix *img = ObjectWrap::Unwrap<Matrix>(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<Value>
Matrix::ConvertGrayscale(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(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<Value>
Matrix::ConvertHSVscale(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(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<Value>
Matrix::Copy(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(args.This());
Local<Object> img_to_return = Matrix::constructor->GetFunction()->NewInstance();
Matrix *img = ObjectWrap::Unwrap<Matrix>(img_to_return);
self->mat.copyTo(img->mat);
return scope.Close(img_to_return);
}
Handle<Value>
Matrix::Ptr(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(args.This());
int line = args[0]->Uint32Value();
char* data = self->mat.ptr<char>(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<Value>
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<Value>
Matrix::AddWeighted(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(args.This());
Matrix *src1 = ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());
Matrix *src2 = ObjectWrap::Unwrap<Matrix>(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<Value>
Matrix::Split(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(args.This());
return scope.Close(v8::Null());
}
Handle<Value>
Matrix::Canny(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(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<Value>
Matrix::Dilate(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(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<Value>
Matrix::FindContours(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(args.This());
Local<Object> conts_to_return= Contour::constructor->GetFunction()->NewInstance();
Contour *contours = ObjectWrap::Unwrap<Contour>(conts_to_return);
cv::findContours(self->mat, contours->contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
return scope.Close(conts_to_return);
}
Handle<Value>
Matrix::DrawContour(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(args.This());
Contour *cont = ObjectWrap::Unwrap<Contour>(args[0]->ToObject());
int pos = args[1]->NumberValue();
cv::Scalar color(0, 0, 255);
if(args[2]->IsArray()) {
Local<Object> objColor = args[2]->ToObject();
color = setColor(objColor);
}
cv::drawContours(self->mat, cont->contours, pos, color, 1);
return Undefined();
}
Handle<Value>
Matrix::DrawAllContours(const v8::Arguments& args) {
HandleScope scope;
Matrix *self = ObjectWrap::Unwrap<Matrix>(args.This());
Contour *cont = ObjectWrap::Unwrap<Contour>(args[0]->ToObject());
cv::Scalar color(0, 0, 255);
if(args[1]->IsArray()) {
Local<Object> objColor = args[1]->ToObject();
color = setColor(objColor);
}
cv::drawContours(self->mat, cont->contours, -1, color, 1);
return Undefined();
}
cv::Scalar setColor(Local<Object> objColor) {
Local<Value> valB = objColor->Get(0);
Local<Value> valG = objColor->Get(1);
Local<Value> valR = objColor->Get(2);
cv::Scalar color = cv::Scalar(valB->IntegerValue(), valG->IntegerValue(), valR->IntegerValue());
return color;
}
Handle<Value>
Matrix::Resize(const v8::Arguments& args){

14
src/Matrix.h Normal file → Executable file
View File

@ -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)
};

0
src/OpenCV.cc Normal file → Executable file
View File

1
src/OpenCV.h Normal file → Executable file
View File

@ -10,6 +10,7 @@
#include <highgui.h>
#include <string.h>
using namespace v8;
using namespace node;

0
src/Point.cc Normal file → Executable file
View File

0
src/Point.h Normal file → Executable file
View File

114
src/VideoCaptureWrap.cc Normal file → Executable file
View File

@ -2,64 +2,114 @@
#include "Matrix.h"
#include "OpenCV.h"
void AsyncRead(uv_work_t *req);
void AfterAsyncRead(uv_work_t *req);
v8::Persistent<FunctionTemplate> VideoCaptureWrap::constructor;
struct videocapture_baton {
Persistent<Function> cb;
VideoCaptureWrap *vc;
Matrix *im;
uv_work_t request;
};
void
VideoCaptureWrap::Init(Handle<Object> target) {
HandleScope scope;
// Constructor
constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(VideoCaptureWrap::New));
constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(String::NewSymbol("VideoCapture"));
// Constructor
constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(VideoCaptureWrap::New));
constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(String::NewSymbol("VideoCapture"));
// Prototype
Local<ObjectTemplate> proto = constructor->PrototypeTemplate();
NODE_SET_PROTOTYPE_METHOD(constructor, "getFrame", GetFrame);
// Prototype
Local<ObjectTemplate> 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<Value>
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<Value>
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<VideoCaptureWrap>(args.This());
REQ_FUN_ARG(0, cb);
videocapture_baton *baton = new videocapture_baton();
baton->vc = v;
baton->cb = Persistent<Function>::New(cb);
baton->im = new Matrix();
baton->request.data = baton;
uv_queue_work(uv_default_loop(), &baton->request, AsyncRead, AfterAsyncRead);
return Undefined();
Local<Object> im_h = Matrix::constructor->GetFunction()->NewInstance();
Matrix *im = ObjectWrap::Unwrap<Matrix>(im_h);
im->mat = frame;
return scope.Close(im_h);
}
void AsyncRead(uv_work_t *req) {
videocapture_baton *baton = static_cast<videocapture_baton *>(req->data);
baton->vc->cap.read(baton->im->mat);
}
void AfterAsyncRead(uv_work_t *req) {
HandleScope scope;
videocapture_baton *baton = static_cast<videocapture_baton *>(req->data);
Local<Object> im_to_return= Matrix::constructor->GetFunction()->NewInstance();
Matrix *img = ObjectWrap::Unwrap<Matrix>(im_to_return);
cv::Mat mat;
mat = baton->im->mat;
img->mat = mat;
Local<Value> argv[1];
argv[0] = im_to_return;
baton->cb->Call(Context::GetCurrent()->Global(), 1, argv);
baton->cb.Dispose();
delete baton;
}

4
src/VideoCaptureWrap.h Normal file → Executable file
View File

@ -11,7 +11,9 @@ class VideoCaptureWrap: public node::ObjectWrap {
VideoCaptureWrap(const std::string& filename);
VideoCaptureWrap(int device);
static Handle<Value> GetFrame(const v8::Arguments&);
static Handle<Value> Read(const v8::Arguments&);
static Handle<Value> GetFrameAt(const v8::Arguments&);
};

2
src/init.cc Normal file → Executable file
View File

@ -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<Object> target) {
Matrix::Init(target);
CascadeClassifierWrap::Init(target);
VideoCaptureWrap::Init(target);
Contour::Init(target);
};

0
test/unit.js Normal file → Executable file
View File

45
todo Executable file
View File

@ -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/

0
wscript Normal file → Executable file
View File