From 5d05f22d554b911de2dfb4d6e1942fc8ce1ead46 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Sat, 4 Nov 2017 13:20:39 +0000 Subject: [PATCH 1/4] cv.readImage: Add verison which returns mat (i.e. no callback fn). Fix create with width & height. Add readimage.js to examples folder. --- examples/readimage.js | 27 +++++++++++++++++++++++++++ src/OpenCV.cc | 30 +++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 examples/readimage.js diff --git a/examples/readimage.js b/examples/readimage.js new file mode 100644 index 0000000..435d6bb --- /dev/null +++ b/examples/readimage.js @@ -0,0 +1,27 @@ +var cv = require('../lib/opencv'); + + + +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()); + +cv.readImage(100, 100, function(err, im){ + console.log('callback readImage(100, 100, fn(){}) (create mat)'+im.width()+'x'+im.height()); +}); + +var fs = require('fs'); +var imgdata = fs.readFileSync("./files/mona.png"); + +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()); +}); diff --git a/src/OpenCV.cc b/src/OpenCV.cc index d77090e..9002c5e 100755 --- a/src/OpenCV.cc +++ b/src/OpenCV.cc @@ -17,7 +17,6 @@ void OpenCV::Init(Local target) { NAN_METHOD(OpenCV::ReadImage) { Nan::EscapableHandleScope scope; - REQ_FUN_ARG(1, cb); Local argv[2]; argv[0] = Nan::Null(); @@ -26,12 +25,23 @@ NAN_METHOD(OpenCV::ReadImage) { Matrix *img = Nan::ObjectWrap::Unwrap(im_h); argv[1] = im_h; + int callback_arg = -1; + int numargs = info.Length(); + int success = 1; + + Local cb; + + // deal with situation where we have int, int, cb + if (info[numargs-1]->IsFunction()){ + callback_arg = numargs-1; + cb = Local::Cast(info[callback_arg]); + } + try { cv::Mat mat; if (info[0]->IsNumber() && info[1]->IsNumber()) { int width, height; - width = info[0]->Uint32Value(); height = info[1]->Uint32Value(); mat = *(new cv::Mat(width, height, CV_64FC1)); @@ -48,6 +58,7 @@ NAN_METHOD(OpenCV::ReadImage) { mat = cv::imdecode(*mbuf, CV_LOAD_IMAGE_UNCHANGED); if (mat.empty()) { + success = 0; argv[0] = Nan::Error("Error loading file"); } } @@ -56,15 +67,24 @@ NAN_METHOD(OpenCV::ReadImage) { } catch (cv::Exception& e) { argv[0] = Nan::Error(e.what()); argv[1] = Nan::Null(); + success = 0; } 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(false)); + } if (try_catch.HasCaught()) { Nan::FatalException(try_catch); } - return; } From 2dd3745c819dd907bc596f62c01149e03f21dbac Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Sat, 4 Nov 2017 14:50:01 +0000 Subject: [PATCH 2/4] cv.readImage: add flags arguments plus update example --- examples/readimage.js | 39 +++++++++++++++++++++++++++++++++++---- src/OpenCV.cc | 26 +++++++++++++++++++++----- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/examples/readimage.js b/examples/readimage.js index 435d6bb..6017e1e 100644 --- a/examples/readimage.js +++ b/examples/readimage.js @@ -1,6 +1,12 @@ 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()); @@ -10,18 +16,43 @@ cv.readImage("./files/mona.png", function(err, im){ }); img = cv.readImage( 100, 100 ); -console.log('Synchronous readImage(100, 100) (create mat)'+img.width()+'x'+img.height()); +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()); }); -var fs = require('fs'); -var imgdata = fs.readFileSync("./files/mona.png"); - 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()); +}); + + + diff --git a/src/OpenCV.cc b/src/OpenCV.cc index 9002c5e..a282057 100755 --- a/src/OpenCV.cc +++ b/src/OpenCV.cc @@ -42,25 +42,41 @@ NAN_METHOD(OpenCV::ReadImage) { if (info[0]->IsNumber() && info[1]->IsNumber()) { 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(); - mat = *(new cv::Mat(width, height, CV_64FC1)); + mat = *(new cv::Mat(width, height, type)); } else if (info[0]->IsString()) { 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])) { uint8_t *buf = (uint8_t *) Buffer::Data(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); - mat = cv::imdecode(*mbuf, CV_LOAD_IMAGE_UNCHANGED); - + mat = cv::imdecode(*mbuf, flags); if (mat.empty()) { success = 0; argv[0] = Nan::Error("Error loading file"); } + } img->mat = mat; From bc62d03f844155d4e065824d627c4cbed8df5349 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Sat, 4 Nov 2017 14:53:44 +0000 Subject: [PATCH 3/4] Add cv.readImageAsync. same interface as readImage, only the callbacks are really Asynchronous, except for matrix creation. Introduces two Asyn Wrokers, one for readin images from disk, and one for decoding images from buffers. --- src/OpenCV.cc | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/OpenCV.h | 1 + 2 files changed, 227 insertions(+) diff --git a/src/OpenCV.cc b/src/OpenCV.cc index a282057..ab8c8a5 100755 --- a/src/OpenCV.cc +++ b/src/OpenCV.cc @@ -11,9 +11,235 @@ void OpenCV::Init(Local target) { target->Set(Nan::New("version").ToLocalChecked(), Nan::New(out, n).ToLocalChecked()); Nan::SetMethod(target, "readImage", ReadImage); + Nan::SetMethod(target, "readImageAsync", ReadImageAsync); 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 img_to_return = + // Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); + // img = Nan::ObjectWrap::Unwrap(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 im_to_return= Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); + Matrix *img = Nan::ObjectWrap::Unwrap(im_to_return); + img->mat = outputmat; + + Local 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 im_to_return= Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); + Matrix *img = Nan::ObjectWrap::Unwrap(im_to_return); + img->mat = outputmat; + + Local 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 argv[2]; + argv[0] = Nan::Null(); + argv[1] = Nan::Null(); + + int callback_arg = -1; + int numargs = info.Length(); + + Local cb; + + // deal with situation where we have int, int, cb + if (info[numargs-1]->IsFunction()){ + callback_arg = numargs-1; + cb = Local::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 img_to_return = + Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); + Matrix *img = Nan::ObjectWrap::Unwrap(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 img_to_return = + Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); + Matrix *img = Nan::ObjectWrap::Unwrap(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()); + 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 img_to_return = + Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); + Matrix *img = Nan::ObjectWrap::Unwrap(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()); + 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(false)); + } + if (try_catch.HasCaught()) { + Nan::FatalException(try_catch); + } + return; +} + + + NAN_METHOD(OpenCV::ReadImage) { Nan::EscapableHandleScope scope; diff --git a/src/OpenCV.h b/src/OpenCV.h index 60739de..6ef42db 100755 --- a/src/OpenCV.h +++ b/src/OpenCV.h @@ -86,6 +86,7 @@ public: static void Init(Local target); static NAN_METHOD(ReadImage); + static NAN_METHOD(ReadImageAsync); static NAN_METHOD(ReadImageMulti); }; From 862cb7f77757a8bed17e80881282b01f7fa308cd Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Sat, 4 Nov 2017 15:01:26 +0000 Subject: [PATCH 4/4] Update examples/readimage.js for readImageAsync. --- examples/readimage.js | 55 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/examples/readimage.js b/examples/readimage.js index 6017e1e..d0d49b9 100644 --- a/examples/readimage.js +++ b/examples/readimage.js @@ -7,7 +7,6 @@ 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()); @@ -56,3 +55,57 @@ cv.readImage(imgdata, 1, function(err, im){ + + +// 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'); +