Merge pull request #574 from btsimonh/btsimonh-readImageAsync

Btsimonh read image async
This commit is contained in:
Peter Braden 2017-11-06 09:26:05 +01:00 committed by GitHub
commit ca7847d651
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 384 additions and 10 deletions

111
examples/readimage.js Normal file
View File

@ -0,0 +1,111 @@
var cv = require('../lib/opencv');
// read as a buffer for decode operations later
var fs = require('fs');
var imgdata = fs.readFileSync("./files/mona.png");
var img = cv.readImage("./files/mona.png");
console.log('Synchronous readImage("./files/mona.png")'+img.width()+'x'+img.height());
cv.readImage("./files/mona.png", function(err, im){
console.log('callback readImage("./files/mona.png", fn(){})'+im.width()+'x'+im.height());
});
img = cv.readImage( 100, 100 );
console.log('Synchronous readImage(100, 100) (create mat)'+img.width()+'x'+img.height()+' type '+img.type());
cv.readImage(100, 100, function(err, im){
console.log('callback readImage(100, 100, fn(){}) (create mat)'+im.width()+'x'+im.height());
});
img = cv.readImage(imgdata);
console.log('Synchronous readImage(imgdata:Buffer)'+img.width()+'x'+img.height());
cv.readImage(imgdata, function(err, im){
console.log('callback readImage(imgdata:Buffer, fn(){})'+im.width()+'x'+im.height());
});
// try with flags now
console.log('Now with flags');
img = cv.readImage("./files/mona.png", 0);
console.log('Synchronous readImage("./files/mona.png", 0) (monochrome)'+img.width()+'x'+img.height()+' type '+img.type());
cv.readImage("./files/mona.png", 1, function(err, im){
console.log('callback readImage("./files/mona.png", 1, fn(){}) (colour)'+im.width()+'x'+im.height()+' type '+im.type());
});
img = cv.readImage( 100, 100, cv.Constants.CV_8UC3 );
console.log('Synchronous readImage(100, 100, cv.Constants.CV_8UC3) (create 8 bit 3 channel mat)'+img.width()+'x'+img.height()+' type '+img.type());
cv.readImage(100, 100, cv.Constants.CV_8UC1, function(err, im){
console.log('callback readImage(100, 100, cv.Constants.CV_8UC1, fn(){}) (create mat)'+im.width()+'x'+im.height()+' type '+im.type());
});
img = cv.readImage(imgdata, 0);
console.log('Synchronous readImage(imgdata:Buffer, 0) (monochrome)'+img.width()+'x'+img.height()+' type '+img.type());
cv.readImage(imgdata, 1, function(err, im){
console.log('callback readImage(imgdata:Buffer, 1, fn(){}) (colour)'+im.width()+'x'+im.height()+' type '+im.type());
});
// try with readImageAsync
console.log('Now with readImageAsync');
img = cv.readImageAsync("./files/mona.png");
console.log('Synchronous readImageAsync("./files/mona.png")'+img.width()+'x'+img.height());
cv.readImageAsync("./files/mona.png", function(err, im){
console.log('Asynchronous callback readImageAsync("./files/mona.png", fn(){})'+im.width()+'x'+im.height());
});
img = cv.readImageAsync( 100, 100 );
console.log('Synchronous readImageAsync(100, 100) (create mat)'+img.width()+'x'+img.height()+' type '+img.type());
cv.readImageAsync(100, 100, function(err, im){
console.log('!!Synchronous!! callback readImageAsync(100, 100, fn(){}) (create mat)'+im.width()+'x'+im.height());
});
img = cv.readImageAsync(imgdata);
console.log('Synchronous readImageAsync(imgdata:Buffer)'+img.width()+'x'+img.height());
cv.readImageAsync(imgdata, function(err, im){
console.log('Asynchronous callback readImageAsync(imgdata:Buffer, fn(){})'+im.width()+'x'+im.height());
});
// try with flags now
console.log('Now Async with flags');
img = cv.readImageAsync("./files/mona.png", 0);
console.log('Synchronous readImageAsync("./files/mona.png", 0) (monochrome)'+img.width()+'x'+img.height()+' type '+img.type());
cv.readImageAsync("./files/mona.png", 1, function(err, im){
console.log('Asynchronous callback readImageAsync("./files/mona.png", 1, fn(){}) (colour)'+im.width()+'x'+im.height()+' type '+im.type());
});
img = cv.readImageAsync( 100, 100, cv.Constants.CV_8UC3 );
console.log('Synchronous readImageAsync(100, 100, cv.Constants.CV_8UC3) (create 8 bit 3 channel mat)'+img.width()+'x'+img.height()+' type '+img.type());
cv.readImageAsync(100, 100, cv.Constants.CV_8UC1, function(err, im){
console.log('!!Synchronous!! callback readImageAsync(100, 100, cv.Constants.CV_8UC1, fn(){}) (create mat)'+im.width()+'x'+im.height()+' type '+im.type());
});
img = cv.readImageAsync(imgdata, 0);
console.log('Synchronous readImageAsync(imgdata:Buffer, 0) (monochrome)'+img.width()+'x'+img.height()+' type '+img.type());
cv.readImageAsync(imgdata, 1, function(err, im){
console.log('Asynchronous callback readImageAsync(imgdata:Buffer, 1, fn(){}) (colour)'+im.width()+'x'+im.height()+' type '+im.type());
});
console.log('\nTruely Async callbacks should be after this line\n');

View File

@ -11,13 +11,238 @@ void OpenCV::Init(Local<Object> target) {
target->Set(Nan::New<String>("version").ToLocalChecked(), Nan::New<String>(out, n).ToLocalChecked()); target->Set(Nan::New<String>("version").ToLocalChecked(), Nan::New<String>(out, n).ToLocalChecked());
Nan::SetMethod(target, "readImage", ReadImage); Nan::SetMethod(target, "readImage", ReadImage);
Nan::SetMethod(target, "readImageAsync", ReadImageAsync);
Nan::SetMethod(target, "readImageMulti", ReadImageMulti); Nan::SetMethod(target, "readImageMulti", ReadImageMulti);
} }
// worker which decodes an image from data.
class AsyncImDecodeWorker: public Nan::AsyncWorker {
public:
AsyncImDecodeWorker(Nan::Callback *callback, uint8_t *buf, unsigned len, int flags = -1):
Nan::AsyncWorker(callback),
buf(buf),
len(len),
flags(flags){
}
~AsyncImDecodeWorker() {
}
void Execute() {
// Local<Object> img_to_return =
// Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
// img = Nan::ObjectWrap::Unwrap<Matrix>(img_to_return);
cv::Mat *mbuf = new cv::Mat(len, 1, CV_64FC1, buf);
outputmat = cv::imdecode(*mbuf, flags);
}
void HandleOKCallback() {
Nan::HandleScope scope;
Local<Object> im_to_return= Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(im_to_return);
img->mat = outputmat;
Local<Value> argv[] = {
Nan::Null(),
im_to_return
};
Nan::TryCatch try_catch;
callback->Call(2, argv);
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
}
}
private:
uint8_t *buf;
unsigned len;
int flags;
cv::Mat outputmat;
//Matrix *img;
};
// worker which reads an image from a file.
class AsyncImReadWorker: public Nan::AsyncWorker {
public:
AsyncImReadWorker(Nan::Callback *callback, std::string filename, int flags = CV_LOAD_IMAGE_UNCHANGED):
Nan::AsyncWorker(callback),
filename(filename),
flags(flags) {
}
~AsyncImReadWorker() {
}
void Execute() {
outputmat = cv::imread(filename, CV_LOAD_IMAGE_UNCHANGED);
}
void HandleOKCallback() {
Nan::HandleScope scope;
Local<Object> im_to_return= Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(im_to_return);
img->mat = outputmat;
Local<Value> argv[] = {
Nan::Null(),
im_to_return
};
Nan::TryCatch try_catch;
callback->Call(2, argv);
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
}
}
private:
std::string filename;
int flags;
cv::Mat outputmat;
};
NAN_METHOD(OpenCV::ReadImageAsync) {
Nan::EscapableHandleScope scope;
Local<Value> argv[2];
argv[0] = Nan::Null();
argv[1] = Nan::Null();
int callback_arg = -1;
int numargs = info.Length();
Local<Function> cb;
// deal with situation where we have int, int, cb
if (info[numargs-1]->IsFunction()){
callback_arg = numargs-1;
cb = Local<Function>::Cast(info[callback_arg]);
}
try {
if (info[0]->IsNumber() && info[1]->IsNumber()) {
//////////////////////////////
// create image from a filename
// always do sync as this take no time?
int width, height;
int type = CV_64FC1;
// if we have a type arg
if ((numargs > 2) && info[2]->IsNumber()){
type = info[2]->Uint32Value();
}
width = info[0]->Uint32Value();
height = info[1]->Uint32Value();
Local<Object> img_to_return =
Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(img_to_return);
img->mat = *(new cv::Mat(width, height, type));
if (callback_arg < 0){
info.GetReturnValue().Set(img_to_return);
return;
} else {
argv[0] = Nan::Null();
argv[1] = img_to_return;
cb->Call(Nan::GetCurrentContext()->Global(), 2, argv);
return;
}
// WILL have returned by here unless exception
//////////////////////////////
} else if (info[0]->IsString()) {
//////////////////////////////
// read image from a filename
std::string filename = std::string(*Nan::Utf8String(info[0]->ToString()));
int flags = CV_LOAD_IMAGE_UNCHANGED;
if (numargs > 1){
if (info[1]->IsNumber()){
flags = info[1]->Uint32Value();
}
}
if (callback_arg < 0){
Local<Object> img_to_return =
Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(img_to_return);
img->mat = cv::imread(filename, flags);
info.GetReturnValue().Set(img_to_return);
return;
} else {
Nan::Callback *callback = new Nan::Callback(cb.As<Function>());
Nan::AsyncQueueWorker(new AsyncImReadWorker(callback, filename, flags));
return;
}
// WILL have returned by here unless exception
//////////////////////////////
} else if (Buffer::HasInstance(info[0])) {
//////////////////////////////
// read image from a buffer
// if sync
int flags = CV_LOAD_IMAGE_UNCHANGED;
if (numargs > 1){
if (info[1]->IsNumber()){
flags = info[1]->Uint32Value();
}
}
if (callback_arg < 0){
Local<Object> img_to_return =
Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(img_to_return);
uint8_t *buf = (uint8_t *) Buffer::Data(info[0]->ToObject());
unsigned len = Buffer::Length(info[0]->ToObject());
cv::Mat *mbuf = new cv::Mat(len, 1, CV_64FC1, buf);
img->mat = cv::imdecode(*mbuf, flags);
info.GetReturnValue().Set(img_to_return);
return;
} else {
// async
uint8_t *buf = (uint8_t *) Buffer::Data(info[0]->ToObject());
unsigned len = Buffer::Length(info[0]->ToObject());
Nan::Callback *callback = new Nan::Callback(cb.As<Function>());
Nan::AsyncQueueWorker(new AsyncImDecodeWorker(callback, buf, len, flags));
return;
}
// WILL have returned by here unless exception
//////////////////////////////
}
} catch (cv::Exception& e) {
argv[0] = Nan::Error(e.what());
argv[1] = Nan::Null();
}
Nan::TryCatch try_catch;
// if we got a callback
if (callback_arg >= 0){
// if using callback
cb->Call(Nan::GetCurrentContext()->Global(), 2, argv);
} else {
// can only get here by exception
info.GetReturnValue().Set(Nan::New<Boolean>(false));
}
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
}
return;
}
NAN_METHOD(OpenCV::ReadImage) { NAN_METHOD(OpenCV::ReadImage) {
Nan::EscapableHandleScope scope; Nan::EscapableHandleScope scope;
REQ_FUN_ARG(1, cb);
Local<Value> argv[2]; Local<Value> argv[2];
argv[0] = Nan::Null(); argv[0] = Nan::Null();
@ -26,45 +251,82 @@ NAN_METHOD(OpenCV::ReadImage) {
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(im_h); Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(im_h);
argv[1] = im_h; argv[1] = im_h;
int callback_arg = -1;
int numargs = info.Length();
int success = 1;
Local<Function> cb;
// deal with situation where we have int, int, cb
if (info[numargs-1]->IsFunction()){
callback_arg = numargs-1;
cb = Local<Function>::Cast(info[callback_arg]);
}
try { try {
cv::Mat mat; cv::Mat mat;
if (info[0]->IsNumber() && info[1]->IsNumber()) { if (info[0]->IsNumber() && info[1]->IsNumber()) {
int width, height; int width, height;
int type = CV_64FC1;
// if we have a type arg
if ((numargs > 2) && info[2]->IsNumber()){
type = info[2]->Uint32Value();
}
width = info[0]->Uint32Value(); width = info[0]->Uint32Value();
height = info[1]->Uint32Value(); height = info[1]->Uint32Value();
mat = *(new cv::Mat(width, height, CV_64FC1)); mat = *(new cv::Mat(width, height, type));
} else if (info[0]->IsString()) { } else if (info[0]->IsString()) {
std::string filename = std::string(*Nan::Utf8String(info[0]->ToString())); std::string filename = std::string(*Nan::Utf8String(info[0]->ToString()));
mat = cv::imread(filename, CV_LOAD_IMAGE_UNCHANGED); int flags = CV_LOAD_IMAGE_UNCHANGED;
if (numargs > 1){
if (info[1]->IsNumber()){
flags = info[1]->Uint32Value();
}
}
mat = cv::imread(filename, flags);
} else if (Buffer::HasInstance(info[0])) { } else if (Buffer::HasInstance(info[0])) {
uint8_t *buf = (uint8_t *) Buffer::Data(info[0]->ToObject()); uint8_t *buf = (uint8_t *) Buffer::Data(info[0]->ToObject());
unsigned len = Buffer::Length(info[0]->ToObject()); unsigned len = Buffer::Length(info[0]->ToObject());
int flags = CV_LOAD_IMAGE_UNCHANGED;
if (numargs > 1){
if (info[1]->IsNumber()){
flags = info[1]->Uint32Value();
}
}
cv::Mat *mbuf = new cv::Mat(len, 1, CV_64FC1, buf); cv::Mat *mbuf = new cv::Mat(len, 1, CV_64FC1, buf);
mat = cv::imdecode(*mbuf, CV_LOAD_IMAGE_UNCHANGED); mat = cv::imdecode(*mbuf, flags);
if (mat.empty()) { if (mat.empty()) {
success = 0;
argv[0] = Nan::Error("Error loading file"); argv[0] = Nan::Error("Error loading file");
} }
} }
img->mat = mat; img->mat = mat;
} catch (cv::Exception& e) { } catch (cv::Exception& e) {
argv[0] = Nan::Error(e.what()); argv[0] = Nan::Error(e.what());
argv[1] = Nan::Null(); argv[1] = Nan::Null();
success = 0;
} }
Nan::TryCatch try_catch; Nan::TryCatch try_catch;
cb->Call(Nan::GetCurrentContext()->Global(), 2, argv); // if we got a callback
if (callback_arg >= 0){
// if using callback
cb->Call(Nan::GetCurrentContext()->Global(), 2, argv);
} else {
// if to return the mat
if (success)
info.GetReturnValue().Set(im_h);
else
info.GetReturnValue().Set(Nan::New<Boolean>(false));
}
if (try_catch.HasCaught()) { if (try_catch.HasCaught()) {
Nan::FatalException(try_catch); Nan::FatalException(try_catch);
} }
return; return;
} }

View File

@ -86,6 +86,7 @@ public:
static void Init(Local<Object> target); static void Init(Local<Object> target);
static NAN_METHOD(ReadImage); static NAN_METHOD(ReadImage);
static NAN_METHOD(ReadImageAsync);
static NAN_METHOD(ReadImageMulti); static NAN_METHOD(ReadImageMulti);
}; };