From 841fe088f663c9330820dc94854b2b6490dd3467 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Sat, 11 Nov 2017 11:03:14 +0000 Subject: [PATCH 1/5] Background subtractor: Add async, add CreateMOG2, CreateGMG, Add some MOG parameters. now OpenCV 2.4 and 3.x --- src/BackgroundSubtractor.cc | 407 +++++++++++++++++++++++++++++++++++- src/BackgroundSubtractor.h | 17 +- 2 files changed, 414 insertions(+), 10 deletions(-) diff --git a/src/BackgroundSubtractor.cc b/src/BackgroundSubtractor.cc index a600ddf..9df10d3 100644 --- a/src/BackgroundSubtractor.cc +++ b/src/BackgroundSubtractor.cc @@ -3,18 +3,47 @@ #include #include -#ifdef HAVE_OPENCV_VIDEO +#ifdef HAVE_BACKGROUNDSUBTRACTOR + +#ifdef HAVE_OPENCV_BGSEGM -#if CV_MAJOR_VERSION >= 3 #ifdef __GNUC__ -#warning TODO: port me to OpenCV 3 +#warning Building with HAVE_OPENCV_BGSEGM #else // vs style message pragma -#pragma message ( "TODO: port me to OpenCV 3" ) +#pragma message ( "Building with HAVE_OPENCV_BGSEGM" ) #endif +cv::bgsegm::BackgroundSubtractorMOG* getMOG(BackgroundSubtractorWrap *wrap) { + return dynamic_cast(wrap->subtractor.get()); +} +#else +#ifdef __GNUC__ +#warning Building without HAVE_OPENCV_BGSEGM +#else +// vs style message pragma +#pragma message ( "Building without HAVE_OPENCV_BGSEGM - only MOG2 will be available" ) +#endif +// without bgsem, it can't be MOG anyway +void* getMOG(BackgroundSubtractorWrap *wrap) { + return NULL; +} #endif -#if ((CV_MAJOR_VERSION == 2) && (CV_MINOR_VERSION >=4)) + +class BGAutoMutex { +public: + BGAutoMutex(cv::Mutex &m){ + mutex = &m; + mutex->lock(); + }; + + ~BGAutoMutex(){ + mutex->unlock(); + mutex = NULL; + }; +private: + cv::Mutex *mutex; +}; Nan::Persistent BackgroundSubtractorWrap::constructor; @@ -28,7 +57,14 @@ void BackgroundSubtractorWrap::Init(Local target) { ctor->SetClassName(Nan::New("BackgroundSubtractor").ToLocalChecked()); Nan::SetMethod(ctor, "createMOG", CreateMOG); + Nan::SetMethod(ctor, "createMOG2", CreateMOG2); + Nan::SetMethod(ctor, "createGMG", CreateGMG); Nan::SetPrototypeMethod(ctor, "applyMOG", ApplyMOG); + Nan::SetPrototypeMethod(ctor, "apply", Apply); + Nan::SetPrototypeMethod(ctor, "history", History); + Nan::SetPrototypeMethod(ctor, "nmixtures", Mixtures); + Nan::SetPrototypeMethod(ctor, "noiseSigma", NoiseSigma); + Nan::SetPrototypeMethod(ctor, "backgroundRatio", BackgroundRatio); target->Set(Nan::New("BackgroundSubtractor").ToLocalChecked(), ctor->GetFunction()); } @@ -41,11 +77,40 @@ NAN_METHOD(BackgroundSubtractorWrap::New) { } // Create MOG by default - cv::Ptr bg; +#ifdef HAVE_OPENCV_BGSEGM + cv::Ptr bg = cv::bgsegm::createBackgroundSubtractorMOG(); + if (NULL == bg){ + JSTHROW_TYPE("OpenCV NULL from cv::bgsegm::createBackgroundSubtractorMOG()"); + } BackgroundSubtractorWrap *pt = new BackgroundSubtractorWrap(bg); + pt->Wrap(info.This()); info.GetReturnValue().Set(info.This()); +#else + // if no bgsem, then default to MOG2 + cv::Ptr bg = cv::createBackgroundSubtractorMOG2(); + if (NULL == bg){ + JSTHROW_TYPE("OpenCV NULL from cv::createBackgroundSubtractorMOG2()"); + } + BackgroundSubtractorWrap *pt = new BackgroundSubtractorWrap(bg); + + pt->Wrap(info.This()); + + info.GetReturnValue().Set(info.This()); +#endif + +#else + cv::Ptr bg = new cv::BackgroundSubtractorMOG(); + if (NULL == bg){ + JSTHROW_TYPE("OpenCV NULL from new cv::BackgroundSubtractorMOG()"); + } + BackgroundSubtractorWrap *pt = new BackgroundSubtractorWrap(bg); + + pt->Wrap(info.This()); + + info.GetReturnValue().Set(info.This()); +#endif } NAN_METHOD(BackgroundSubtractorWrap::CreateMOG) { @@ -65,13 +130,108 @@ NAN_METHOD(BackgroundSubtractorWrap::CreateMOG) { Local n = Nan::NewInstance(Nan::GetFunction(Nan::New(BackgroundSubtractorWrap::constructor)).ToLocalChecked()).ToLocalChecked(); - cv::Ptr bg; +#if CV_MAJOR_VERSION >= 3 +#ifdef HAVE_OPENCV_BGSEGM + cv::Ptr bg = cv::bgsegm::createBackgroundSubtractorMOG(); + if (NULL == bg){ + JSTHROW_TYPE("OpenCV NULL from cv::bgsegm::createBackgroundSubtractorMOG()"); + } + BackgroundSubtractorWrap *pt = new BackgroundSubtractorWrap(bg); + + pt->Wrap(n); + info.GetReturnValue().Set( n ); +#else + JSTHROW_TYPE("OpenCV built without bgsem (opencv_contrib)") +#endif +#else + cv::Ptr bg = new cv::BackgroundSubtractorMOG(); + if (NULL == bg){ + JSTHROW_TYPE("OpenCV NULL from new cv::BackgroundSubtractorMOG()"); + } + BackgroundSubtractorWrap *pt = new BackgroundSubtractorWrap(bg); + + pt->Wrap(n); + info.GetReturnValue().Set( n ); +#endif +} + +NAN_METHOD(BackgroundSubtractorWrap::CreateMOG2) { + Nan::HandleScope scope; + + // int history = 200; + // int nmixtures = 5; + // double backgroundRatio = 0.7; + // double noiseSigma = 0; + // + // if(info.Length() > 1){ + // INT_FROM_ARGS(history, 0) + // INT_FROM_ARGS(nmixtures, 1) + // DOUBLE_FROM_ARGS(backgroundRatio, 2) + // DOUBLE_FROM_ARGS(noiseSigma, 3) + // } + + Local n = Nan::NewInstance(Nan::GetFunction(Nan::New(BackgroundSubtractorWrap::constructor)).ToLocalChecked()).ToLocalChecked(); + +#if CV_MAJOR_VERSION >= 3 + cv::Ptr bg = cv::createBackgroundSubtractorMOG2(); + if (NULL == bg){ + JSTHROW_TYPE("OpenCV NULL from cv::createBackgroundSubtractorMOG2()"); + } +#else + cv::Ptr bg = new cv::BackgroundSubtractorMOG(); + if (NULL == bg){ + JSTHROW_TYPE("OpenCV NULL from new cv::BackgroundSubtractorMOG()"); + } +#endif BackgroundSubtractorWrap *pt = new BackgroundSubtractorWrap(bg); pt->Wrap(n); info.GetReturnValue().Set( n ); } +NAN_METHOD(BackgroundSubtractorWrap::CreateGMG) { + Nan::HandleScope scope; + + // int history = 200; + // int nmixtures = 5; + // double backgroundRatio = 0.7; + // double noiseSigma = 0; + // + // if(info.Length() > 1){ + // INT_FROM_ARGS(history, 0) + // INT_FROM_ARGS(nmixtures, 1) + // DOUBLE_FROM_ARGS(backgroundRatio, 2) + // DOUBLE_FROM_ARGS(noiseSigma, 3) + // } + + Local n = Nan::NewInstance(Nan::GetFunction(Nan::New(BackgroundSubtractorWrap::constructor)).ToLocalChecked()).ToLocalChecked(); + +#if CV_MAJOR_VERSION >= 3 +#ifdef HAVE_OPENCV_BGSEGM + cv::Ptr bg = cv::bgsegm::createBackgroundSubtractorGMG(); + if (NULL == bg){ + JSTHROW_TYPE("OpenCV NULL from cv::bgsegm::createBackgroundSubtractorGMG()"); + } + BackgroundSubtractorWrap *pt = new BackgroundSubtractorWrap(bg); + + pt->Wrap(n); + info.GetReturnValue().Set( n ); +#else + JSTHROW_TYPE("OpenCV built without bgsem (opencv_contrib) - use MOG2") +#endif +#else + cv::Ptr bg = new cv::BackgroundSubtractorMOG(); + if (NULL == bg){ + JSTHROW_TYPE("OpenCV NULL from new cv::BackgroundSubtractorMOG()"); + } + BackgroundSubtractorWrap *pt = new BackgroundSubtractorWrap(bg); + + pt->Wrap(n); + info.GetReturnValue().Set( n ); +#endif +} + + // Fetch foreground mask NAN_METHOD(BackgroundSubtractorWrap::ApplyMOG) { SETUP_FUNCTION(BackgroundSubtractorWrap); @@ -85,6 +245,14 @@ NAN_METHOD(BackgroundSubtractorWrap::ApplyMOG) { return; } + if (NULL == self->subtractor){ + argv[0] = Nan::New("BackgroundSubtractor not created").ToLocalChecked(); + argv[1] = Nan::Null(); + cb->Call(Nan::GetCurrentContext()->Global(), 2, argv); + return; + } + + try { Local fgMask = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); @@ -106,9 +274,18 @@ NAN_METHOD(BackgroundSubtractorWrap::ApplyMOG) { return Nan::ThrowTypeError("Error loading file"); } + cv::Mat _fgMask; + { + // wait here if already in apply - auto-release on scope exit + BGAutoMutex(self->applymutex); +#if CV_MAJOR_VERSION >= 3 + self->subtractor->apply(mat, _fgMask); +#else self->subtractor->operator()(mat, _fgMask); - +#endif + } + img->mat = _fgMask; mat.release(); @@ -129,6 +306,219 @@ NAN_METHOD(BackgroundSubtractorWrap::ApplyMOG) { } } + +class AsyncBackgroundSubtractorWorker: public Nan::AsyncWorker { +public: + AsyncBackgroundSubtractorWorker( + Nan::Callback *callback, + BackgroundSubtractorWrap *bg, + Matrix *img) : + Nan::AsyncWorker(callback), + bg(bg), + img(img) { + } + + ~AsyncBackgroundSubtractorWorker() { + } + + // Executed inside the worker-thread. + // It is not safe to access V8, or V8 data structures + // here, so everything we need for input and output + // should go on `this`. + void Execute() { + // wait here if already in apply - auto-release on scope exit + BGAutoMutex(bg->applymutex); +#if CV_MAJOR_VERSION >= 3 + bg->subtractor->apply(this->img->mat, _fgMask); +#else + bg->subtractor->operator()(this->img->mat, _fgMask); +#endif + } + + // Executed when the async work is complete + // this function will be run inside the main event loop + // so it is safe to use V8 again + void HandleOKCallback() { + Nan::HandleScope scope; + + Local im_to_return= Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); + Matrix *imgout = Nan::ObjectWrap::Unwrap(im_to_return); + imgout->mat = _fgMask; + + Local argv[] = { + Nan::Null() + , im_to_return + }; + + Nan::TryCatch try_catch; + callback->Call(2, argv); + if (try_catch.HasCaught()) { + Nan::FatalException(try_catch); + } + } + +private: + BackgroundSubtractorWrap *bg; + Matrix *img; + cv::Mat _fgMask; +}; + + +// Fetch foreground mask +NAN_METHOD(BackgroundSubtractorWrap::Apply) { + SETUP_FUNCTION(BackgroundSubtractorWrap); + int callback_arg = -1; + int numargs = info.Length(); + int success = 1; + + Local cb; + + if (info[numargs-1]->IsFunction()){ + callback_arg = numargs-1; + cb = Local::Cast(info[callback_arg]); + } + + + + // if async + if (callback_arg){ + Local argv[2]; + + if (info.Length() == 0) { + argv[0] = Nan::New("Input image missing").ToLocalChecked(); + argv[1] = Nan::Null(); + cb->Call(Nan::GetCurrentContext()->Global(), 2, argv); + return; + } + if (NULL == self->subtractor){ + argv[0] = Nan::New("BackgroundSubtractor not created").ToLocalChecked(); + argv[1] = Nan::Null(); + cb->Call(Nan::GetCurrentContext()->Global(), 2, argv); + return; + } + + Nan::Callback *callback = new Nan::Callback(cb.As()); + Matrix *_img = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); + Nan::AsyncQueueWorker(new AsyncBackgroundSubtractorWorker( callback, self, _img)); + return; + } else { //syncronous - return the image + + try { + Local fgMask = + Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); + Matrix *img = Nan::ObjectWrap::Unwrap(fgMask); + + cv::Mat mat; + if (Buffer::HasInstance(info[0])) { + 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); + mat = cv::imdecode(*mbuf, -1); + //mbuf->release(); + } else { + Matrix *_img = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); + mat = (_img->mat).clone(); + } + + if (mat.empty()) { + return Nan::ThrowTypeError("Empty matrix?"); + } + + { + // wait here if already in apply - auto-release on scope exit + BGAutoMutex(self->applymutex); + cv::Mat _fgMask; + #if CV_MAJOR_VERSION >= 3 + self->subtractor->apply(mat, _fgMask); + #else + self->subtractor->operator()(mat, _fgMask); + #endif + img->mat = _fgMask; + } + + mat.release(); + + info.GetReturnValue().Set(fgMask); + return; + + } catch (cv::Exception& e) { + const char* err_msg = e.what(); + Nan::ThrowError(err_msg); + return; + } + + } +} + + +NAN_METHOD(BackgroundSubtractorWrap::History) { + SETUP_FUNCTION(BackgroundSubtractorWrap); + auto mog = getMOG(self); + if (!mog) { + Nan::ThrowError("Not using a BackgroundSubtractorMOG"); + } +// only support for V3+ with opencv-contrib +#ifdef HAVE_OPENCV_BGSEGM + if (info.Length() > 0) { + mog->setHistory(info[0]->NumberValue()); + } + info.GetReturnValue().Set(mog->getHistory()); +#else + info.GetReturnValue().Set(Nan::Null()); +#endif +} + +NAN_METHOD(BackgroundSubtractorWrap::BackgroundRatio) { + SETUP_FUNCTION(BackgroundSubtractorWrap); + auto mog = getMOG(self); + if (!mog) { + Nan::ThrowError("Not using a BackgroundSubtractorMOG"); + } +// only support for V3+ with opencv-contrib +#ifdef HAVE_OPENCV_BGSEGM + if (info.Length() > 0) { + mog->setBackgroundRatio(info[0]->NumberValue()); + } + info.GetReturnValue().Set(mog->getBackgroundRatio()); +#else + info.GetReturnValue().Set(Nan::Null()); +#endif +} + +NAN_METHOD(BackgroundSubtractorWrap::NoiseSigma) { + SETUP_FUNCTION(BackgroundSubtractorWrap); + auto mog = getMOG(self); + if (!mog) { + Nan::ThrowError("Not using a BackgroundSubtractorMOG"); + } +// only support for V3+ with opencv-contrib +#ifdef HAVE_OPENCV_BGSEGM + if (info.Length() > 0) { + mog->setNoiseSigma(info[0]->NumberValue()); + } + info.GetReturnValue().Set(mog->getNoiseSigma()); +#else + info.GetReturnValue().Set(Nan::Null()); +#endif +} + +NAN_METHOD(BackgroundSubtractorWrap::Mixtures) { + SETUP_FUNCTION(BackgroundSubtractorWrap); + auto mog = getMOG(self); + if (!mog) { + Nan::ThrowError("Not using a BackgroundSubtractorMOG"); + } +// only support for V3+ with opencv-contrib +#ifdef HAVE_OPENCV_BGSEGM + if (info.Length() > 0) { + mog->setNMixtures(info[0]->NumberValue()); + } + info.GetReturnValue().Set(mog->getNMixtures()); +#else + info.GetReturnValue().Set(Nan::Null()); +#endif +} + BackgroundSubtractorWrap::BackgroundSubtractorWrap( cv::Ptr _subtractor) { subtractor = _subtractor; @@ -136,4 +526,3 @@ BackgroundSubtractorWrap::BackgroundSubtractorWrap( #endif -#endif diff --git a/src/BackgroundSubtractor.h b/src/BackgroundSubtractor.h index 649fae9..5ab7016 100644 --- a/src/BackgroundSubtractor.h +++ b/src/BackgroundSubtractor.h @@ -2,13 +2,19 @@ #ifdef HAVE_OPENCV_VIDEO -#if ((CV_MAJOR_VERSION == 2) && (CV_MINOR_VERSION >=4)) +#if ((CV_MAJOR_VERSION == 2) && (CV_MINOR_VERSION >=4)) || (CV_MAJOR_VERSION >= 3) +#define HAVE_BACKGROUNDSUBTRACTOR #include +#ifdef HAVE_OPENCV_BGSEGM +#include +#endif + class BackgroundSubtractorWrap: public Nan::ObjectWrap { public: cv::Ptr subtractor; + cv::Mutex applymutex; static Nan::Persistent constructor; static void Init(Local target); @@ -17,7 +23,16 @@ public: BackgroundSubtractorWrap(cv::Ptr bg); static NAN_METHOD(CreateMOG); + static NAN_METHOD(CreateMOG2); + static NAN_METHOD(CreateGMG); + static NAN_METHOD(ApplyMOG); + static NAN_METHOD(Apply); + static NAN_METHOD(History); + static NAN_METHOD(Mixtures); + static NAN_METHOD(NoiseSigma); + static NAN_METHOD(BackgroundRatio); + }; #endif From cbb7f31b48cd706e0359b22a25ffe474ce92880e Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Sat, 11 Nov 2017 11:29:57 +0000 Subject: [PATCH 2/5] add back in missing #ifdef --- src/BackgroundSubtractor.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BackgroundSubtractor.cc b/src/BackgroundSubtractor.cc index 9df10d3..277e55e 100644 --- a/src/BackgroundSubtractor.cc +++ b/src/BackgroundSubtractor.cc @@ -77,6 +77,7 @@ NAN_METHOD(BackgroundSubtractorWrap::New) { } // Create MOG by default +#if CV_MAJOR_VERSION >= 3 #ifdef HAVE_OPENCV_BGSEGM cv::Ptr bg = cv::bgsegm::createBackgroundSubtractorMOG(); if (NULL == bg){ From 507bb2482bb21d11e5c003b207cb739479bb4b61 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Sat, 11 Nov 2017 12:14:55 +0000 Subject: [PATCH 3/5] Fix Synchronous Apply() --- src/BackgroundSubtractor.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BackgroundSubtractor.cc b/src/BackgroundSubtractor.cc index 277e55e..114c613 100644 --- a/src/BackgroundSubtractor.cc +++ b/src/BackgroundSubtractor.cc @@ -382,7 +382,7 @@ NAN_METHOD(BackgroundSubtractorWrap::Apply) { // if async - if (callback_arg){ + if (callback_arg > 0){ Local argv[2]; if (info.Length() == 0) { @@ -402,7 +402,7 @@ NAN_METHOD(BackgroundSubtractorWrap::Apply) { Matrix *_img = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); Nan::AsyncQueueWorker(new AsyncBackgroundSubtractorWorker( callback, self, _img)); return; - } else { //syncronous - return the image + } else { //synchronous - return the image try { Local fgMask = From 4f585151873a2ceb7547d122a96b5164b8421903 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Sat, 11 Nov 2017 12:37:25 +0000 Subject: [PATCH 4/5] Add bgsubtractor example/test. --- examples/bgsubtractor.js | 104 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 examples/bgsubtractor.js diff --git a/examples/bgsubtractor.js b/examples/bgsubtractor.js new file mode 100644 index 0000000..aa945c1 --- /dev/null +++ b/examples/bgsubtractor.js @@ -0,0 +1,104 @@ +var path = require('path'), + cv = require('../lib/opencv'); + +var bg = null; + + +var do_sync = function(done){ + // When opening a file, the full path must be passed to opencv + var vid = new cv.VideoCapture(path.join(__dirname, 'files', 'motion.mov')); + var x = 0; + + // synchronous + var iter = function(){ + vid.read(function(err, m2){ + if (err) throw err; + var mat = bg.apply(m2); + // mat is a monochrome img where moving objects are white + if (x++<100){ + //console.log("iter "+x); + setTimeout(iter, 1); + } else { + delete vid; + console.log("bg sync done"); + if (undefined !== done) + done(); + } + }) + }; + + iter(); +}; + +var do_async = function(done){ + // restart video read + var vid = new cv.VideoCapture(path.join(__dirname, 'files', 'motion.mov')); + var x = 0; + + // asynchronous + var iter = function(){ + vid.read(function(err, m2){ + if (err) throw err; + bg.apply(m2, function(err, mat){ + if (err) throw err; + // mat is a monochrome img where moving objects are white + if (x++<100){ + //console.log("iter "+x); + iter(); + } else { + console.log("bg async done"); + delete vid; + if (undefined !== done) + done(); + } + }); + }) + }; + + iter(); +}; + +var do_default = function( done ){ + console.log("doing Default"); + bg = new cv.BackgroundSubtractor(); + do_sync( function(){ + do_async(done); + }); +} + +var do_gmg = function( done ){ + console.log("doing GMG"); + bg = cv.BackgroundSubtractor.createGMG(); + do_sync( function(){ + console.log("not doing GMG Async - crashes my pi"); + //do_async(done); + done(); + }); +} + +var do_mog = function( done ){ + console.log("doing MOG"); + bg = cv.BackgroundSubtractor.createMOG(); + do_sync( function(){ + do_async(done); + }); +} + +var do_mog2 = function( done ){ + console.log("doing MOG2"); + bg = cv.BackgroundSubtractor.createMOG2(); + do_sync( function(){ + do_async(done); + }); +} + +do_default(function(){ + do_mog(function(){ + do_mog2(function(){ + do_gmg(function(){ + + }); + }); + }); +}); + From 1e8587fe9a82002eb0fe74b6948bd8636b738b42 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Sat, 11 Nov 2017 12:51:00 +0000 Subject: [PATCH 5/5] bgsubtrator - add manual GC else node kills my pi. Add delete of images once consumed. --- examples/bgsubtractor.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/bgsubtractor.js b/examples/bgsubtractor.js index aa945c1..b780644 100644 --- a/examples/bgsubtractor.js +++ b/examples/bgsubtractor.js @@ -3,6 +3,9 @@ var path = require('path'), var bg = null; +require("v8").setFlagsFromString('--expose_gc'); + +var gc = require("vm").runInNewContext('gc'); var do_sync = function(done){ // When opening a file, the full path must be passed to opencv @@ -14,6 +17,7 @@ var do_sync = function(done){ vid.read(function(err, m2){ if (err) throw err; var mat = bg.apply(m2); + delete m2; // mat is a monochrome img where moving objects are white if (x++<100){ //console.log("iter "+x); @@ -21,6 +25,7 @@ var do_sync = function(done){ } else { delete vid; console.log("bg sync done"); + gc(); if (undefined !== done) done(); } @@ -40,6 +45,7 @@ var do_async = function(done){ vid.read(function(err, m2){ if (err) throw err; bg.apply(m2, function(err, mat){ + delete mat; if (err) throw err; // mat is a monochrome img where moving objects are white if (x++<100){ @@ -48,6 +54,7 @@ var do_async = function(done){ } else { console.log("bg async done"); delete vid; + gc(); if (undefined !== done) done(); } @@ -70,9 +77,8 @@ var do_gmg = function( done ){ console.log("doing GMG"); bg = cv.BackgroundSubtractor.createGMG(); do_sync( function(){ - console.log("not doing GMG Async - crashes my pi"); - //do_async(done); - done(); + //console.log("not doing GMG Async - crashes my pi"); + do_async(done); }); }