From bc62d03f844155d4e065824d627c4cbed8df5349 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Sat, 4 Nov 2017 14:53:44 +0000 Subject: [PATCH] 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); };