From 95b05962450ef30894b2d18b31d688829b9f4241 Mon Sep 17 00:00:00 2001 From: Dan Schultzer Date: Sat, 8 Oct 2016 18:17:18 -0700 Subject: [PATCH 1/8] Add logic for available modules With OpenCV >3.1 and 2.4.13, OpenCV can now be installed without specific modules. This makes it so that `node-opencv` will still be able to compile. --- inc/Matrix.h | 2 +- lib/opencv.js | 141 ++++++++++++++++++----------------- src/BackgroundSubtractor.cc | 3 + src/BackgroundSubtractor.h | 4 + src/Calib3D.cc | 4 + src/Calib3D.h | 3 + src/CamShift.cc | 4 + src/CamShift.h | 3 + src/CascadeClassifierWrap.cc | 6 +- src/CascadeClassifierWrap.h | 7 +- src/Features2d.cc | 3 + src/Features2d.h | 4 + src/HighGUI.cc | 4 + src/HighGUI.h | 4 + src/ImgProc.cc | 4 + src/ImgProc.h | 4 + src/OpenCV.h | 35 +++++++-- src/VideoCaptureWrap.cc | 4 + src/VideoCaptureWrap.h | 4 + src/init.cc | 20 ++++- 20 files changed, 182 insertions(+), 81 deletions(-) diff --git a/inc/Matrix.h b/inc/Matrix.h index beed998..c2490a6 100755 --- a/inc/Matrix.h +++ b/inc/Matrix.h @@ -11,7 +11,7 @@ */ #ifndef NODE_OPENCV_MATRIX_H #define NODE_OPENCV_MATRIX_H -#include +#include #include namespace node_opencv { diff --git a/lib/opencv.js b/lib/opencv.js index a594700..f4b3901 100755 --- a/lib/opencv.js +++ b/lib/opencv.js @@ -7,30 +7,34 @@ var Stream = require('stream').Stream var cv = module.exports = require('./bindings'); var Matrix = cv.Matrix - , VideoCapture = cv.VideoCapture - , VideoWriter = cv.VideoWriter , ImageStream , ImageDataStream , ObjectDetectionStream , VideoStream; -Matrix.prototype.detectObject = function(classifier, opts, cb){ - var face_cascade; - opts = opts || {}; - cv._detectObjectClassifiers = cv._detectObjectClassifiers || {}; +if (cv.CascadeClassifier) { + Matrix.prototype.detectObject = function(classifier, opts, cb){ + var face_cascade; + opts = opts || {}; + cv._detectObjectClassifiers = cv._detectObjectClassifiers || {}; - if (!(face_cascade = cv._detectObjectClassifiers[classifier])){ - face_cascade = new cv.CascadeClassifier(classifier); - cv._detectObjectClassifiers[classifier] = face_cascade; + if (!(face_cascade = cv._detectObjectClassifiers[classifier])){ + face_cascade = new cv.CascadeClassifier(classifier); + cv._detectObjectClassifiers[classifier] = face_cascade; + } + + face_cascade.detectMultiScale(this, cb, opts.scale, opts.neighbors + , opts.min && opts.min[0], opts.min && opts.min[1]); + } +} else { + cv.Matrix.prototype.detectObject = function() { + throw new Error("You need to install OpenCV with OBJDETECT module"); } - - face_cascade.detectMultiScale(this, cb, opts.scale, opts.neighbors - , opts.min && opts.min[0], opts.min && opts.min[1]); } -Matrix.prototype.inspect = function(){ +cv.Matrix.prototype.inspect = function(){ var size = (this.size()||[]).join('x'); return "[ Matrix " + size + " ]"; } @@ -189,69 +193,70 @@ ImageDataStream.prototype.end = function(b){ }); } - -ObjectDetectionStream = cv.ObjectDetectionStream = function(cascade, opts){ - this.classifier = new cv.CascadeClassifier(cascade); - this.opts = opts || {}; - this.readable = true; - this.writable = true; -} -util.inherits(ObjectDetectionStream, Stream); - - -ObjectDetectionStream.prototype.write = function(m){ - var self = this; - this.classifier.detectMultiScale(m, function(err, objs){ - if (err) return self.emit('error', err); - self.emit('data', objs, m); +if (cv.CascadeClassifier) { + ObjectDetectionStream = cv.ObjectDetectionStream = function(cascade, opts){ + this.classifier = new cv.CascadeClassifier(cascade); + this.opts = opts || {}; + this.readable = true; + this.writable = true; } - , this.opts.scale - , this.opts.neighbors - , this.opts.min && this.opts.min[0] - , this.opts.min && this.opts.min[1]); -} + util.inherits(ObjectDetectionStream, Stream); - -VideoStream = cv.VideoStream = function(src){ - if (!(src instanceof VideoCapture)) src = new VideoCapture(src); - this.video = src; - this.readable = true; - this.paused = false; -} -util.inherits(VideoStream, Stream); - - -VideoStream.prototype.read = function(){ - var self = this; - var frame = function(){ - self.video.read(function(err, mat){ + ObjectDetectionStream.prototype.write = function(m){ + var self = this; + this.classifier.detectMultiScale(m, function(err, objs){ if (err) return self.emit('error', err); - self.emit('data', mat); - if (!self.paused) process.nextTick(frame); - }) + self.emit('data', objs, m); + } + , this.opts.scale + , this.opts.neighbors + , this.opts.min && this.opts.min[0] + , this.opts.min && this.opts.min[1]); + } +} + + +if (cv.VideoCapture) { + var VideoCapture = cv.VideoCapture + + VideoStream = cv.VideoStream = function(src){ + if (!(src instanceof VideoCapture)) src = new VideoCapture(src); + this.video = src; + this.readable = true; + this.paused = false; + } + util.inherits(VideoStream, Stream); + + + VideoStream.prototype.read = function(){ + var self = this; + var frame = function(){ + self.video.read(function(err, mat){ + if (err) return self.emit('error', err); + self.emit('data', mat); + if (!self.paused) process.nextTick(frame); + }) + } + + frame(); } - frame(); + VideoStream.prototype.pause = function(){ + this.paused = true; + } + + + VideoStream.prototype.resume = function(){ + this.paused = false; + this.read(); + } + + VideoCapture.prototype.toStream = function(){ + return new VideoStream(this); + } } -VideoStream.prototype.pause = function(){ - this.paused = true; -} - - -VideoStream.prototype.resume = function(){ - this.paused = false; - this.read(); -} - - -VideoCapture.prototype.toStream = function(){ - return new VideoStream(this); -} - - - // Provide cascade data for faces etc. var CASCADES = { FACE_CASCADE: 'haarcascade_frontalface_alt.xml' diff --git a/src/BackgroundSubtractor.cc b/src/BackgroundSubtractor.cc index 7ddba75..1d601a1 100644 --- a/src/BackgroundSubtractor.cc +++ b/src/BackgroundSubtractor.cc @@ -3,6 +3,8 @@ #include #include +#ifdef HAVE_OPENCV_VIDEO + #if CV_MAJOR_VERSION >= 3 #warning TODO: port me to OpenCV 3 #endif @@ -129,3 +131,4 @@ BackgroundSubtractorWrap::BackgroundSubtractorWrap( #endif +#endif diff --git a/src/BackgroundSubtractor.h b/src/BackgroundSubtractor.h index d661e33..649fae9 100644 --- a/src/BackgroundSubtractor.h +++ b/src/BackgroundSubtractor.h @@ -1,5 +1,7 @@ #include "OpenCV.h" +#ifdef HAVE_OPENCV_VIDEO + #if ((CV_MAJOR_VERSION == 2) && (CV_MINOR_VERSION >=4)) #include @@ -19,3 +21,5 @@ public: }; #endif + +#endif diff --git a/src/Calib3D.cc b/src/Calib3D.cc index 53c84d0..e8e5ddb 100644 --- a/src/Calib3D.cc +++ b/src/Calib3D.cc @@ -1,6 +1,8 @@ #include "Calib3D.h" #include "Matrix.h" +#ifdef HAVE_OPENCV_CALIB3D + inline Local matrixFromMat(cv::Mat &input) { Local matrixWrap = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); @@ -564,3 +566,5 @@ NAN_METHOD(Calib3D::ReprojectImageTo3D) { return; } } + +#endif diff --git a/src/Calib3D.h b/src/Calib3D.h index a1846c8..ca5e3fe 100644 --- a/src/Calib3D.h +++ b/src/Calib3D.h @@ -3,6 +3,8 @@ #include "OpenCV.h" +#ifdef HAVE_OPENCV_CALIB3D + #if CV_MAJOR_VERSION >= 3 #include #endif @@ -25,3 +27,4 @@ public: }; #endif +#endif diff --git a/src/CamShift.cc b/src/CamShift.cc index bcf00ce..638bddc 100644 --- a/src/CamShift.cc +++ b/src/CamShift.cc @@ -2,6 +2,8 @@ #include "OpenCV.h" #include "Matrix.h" +#ifdef HAVE_OPENCV_VIDEO + #if CV_MAJOR_VERSION >= 3 #include #endif @@ -176,3 +178,5 @@ NAN_METHOD(TrackedObject::Track) { info.GetReturnValue().Set(arr); } + +#endif diff --git a/src/CamShift.h b/src/CamShift.h index 7524408..af1bde9 100644 --- a/src/CamShift.h +++ b/src/CamShift.h @@ -1,5 +1,6 @@ #include "OpenCV.h" +#ifdef HAVE_OPENCV_VIDEO class TrackedObject: public Nan::ObjectWrap { public: @@ -20,3 +21,5 @@ public: JSFUNC(Track); }; + +#endif diff --git a/src/CascadeClassifierWrap.cc b/src/CascadeClassifierWrap.cc index b8c5a49..40c04a1 100755 --- a/src/CascadeClassifierWrap.cc +++ b/src/CascadeClassifierWrap.cc @@ -3,6 +3,8 @@ #include "Matrix.h" #include +#ifdef HAVE_OPENCV_OBJDETECT + Nan::Persistent CascadeClassifierWrap::constructor; void CascadeClassifierWrap::Init(Local target) { @@ -54,7 +56,7 @@ public: minw(minw), minh(minh) { } - + ~AsyncDetectMultiScale() { } @@ -149,3 +151,5 @@ NAN_METHOD(CascadeClassifierWrap::DetectMultiScale) { neighbors, minw, minh)); return; } + +#endif diff --git a/src/CascadeClassifierWrap.h b/src/CascadeClassifierWrap.h index d21c370..dee320f 100755 --- a/src/CascadeClassifierWrap.h +++ b/src/CascadeClassifierWrap.h @@ -1,6 +1,9 @@ #include "OpenCV.h" + +#ifdef HAVE_OPENCV_OBJDETECT + #if CV_MAJOR_VERSION >= 3 -#include + #include #endif class CascadeClassifierWrap: public Nan::ObjectWrap { @@ -20,3 +23,5 @@ public: static void EIO_DetectMultiScale(uv_work_t *req); static int EIO_AfterDetectMultiScale(uv_work_t *req); }; + +#endif diff --git a/src/Features2d.cc b/src/Features2d.cc index fa8f1cb..f2b75cb 100644 --- a/src/Features2d.cc +++ b/src/Features2d.cc @@ -6,6 +6,8 @@ #include #include +#ifdef HAVE_OPENCV_FEATURES2D + void Features::Init(Local target) { Nan::HandleScope scope; @@ -112,3 +114,4 @@ NAN_METHOD(Features::Similarity) { } #endif +#endif diff --git a/src/Features2d.h b/src/Features2d.h index e793f86..3d02977 100644 --- a/src/Features2d.h +++ b/src/Features2d.h @@ -2,6 +2,8 @@ #if ((CV_MAJOR_VERSION == 2) && (CV_MINOR_VERSION >=4)) +#ifdef HAVE_OPENCV_FEATURES2D + #include #include @@ -14,3 +16,5 @@ public: }; #endif + +#endif diff --git a/src/HighGUI.cc b/src/HighGUI.cc index b61b1fa..139fe94 100644 --- a/src/HighGUI.cc +++ b/src/HighGUI.cc @@ -2,6 +2,8 @@ #include "OpenCV.h" #include "Matrix.h" +#ifdef HAVE_OPENCV_HIGHGUI + Nan::Persistent NamedWindow::constructor; void NamedWindow::Init(Local target) { @@ -82,3 +84,5 @@ NAN_METHOD(NamedWindow::BlockingWaitKey) { info.GetReturnValue().Set(Nan::New(res)); } + +#endif diff --git a/src/HighGUI.h b/src/HighGUI.h index d47bc4b..3994892 100644 --- a/src/HighGUI.h +++ b/src/HighGUI.h @@ -1,5 +1,7 @@ #include "OpenCV.h" +#ifdef HAVE_OPENCV_HIGHGUI + class NamedWindow: public Nan::ObjectWrap { public: std::string winname; @@ -17,3 +19,5 @@ public: ; }; + +#endif diff --git a/src/ImgProc.cc b/src/ImgProc.cc index f181683..4dc4efb 100644 --- a/src/ImgProc.cc +++ b/src/ImgProc.cc @@ -1,6 +1,8 @@ #include "ImgProc.h" #include "Matrix.h" +#ifdef HAVE_OPENCV_IMGPROC + void ImgProc::Init(Local target) { Nan::Persistent inner; Local obj = Nan::New(); @@ -233,3 +235,5 @@ NAN_METHOD(ImgProc::GetStructuringElement) { return; } } + +#endif diff --git a/src/ImgProc.h b/src/ImgProc.h index 8754fdd..ca83782 100644 --- a/src/ImgProc.h +++ b/src/ImgProc.h @@ -3,6 +3,8 @@ #include "OpenCV.h" +#ifdef HAVE_OPENCV_IMGPROC + /** * Implementation of imgproc.hpp functions */ @@ -17,3 +19,5 @@ public: }; #endif + +#endif diff --git a/src/OpenCV.h b/src/OpenCV.h index cc9a2b9..60739de 100755 --- a/src/OpenCV.h +++ b/src/OpenCV.h @@ -10,22 +10,41 @@ #endif +#include +#if !((((CV_MAJOR_VERSION <= 2) && (CV_MINOR_VERSION <= 4)) && (CV_MINOR_VERSION < 13)) || ((CV_MAJOR_VERSION >= 3) && (CV_MINOR_VERSION < 1))) + #define INCLUDE_AVAILABLE_MODULES_ONLY +#endif #include #include #include #include #include -#include +#include + +#if ((CV_MAJOR_VERSION <= 2) && (CV_MINOR_VERSION <= 4) && (CV_MINOR_VERSION < 10)) #include -#if CV_MAJOR_VERSION >= 3 -#include -#include -#include -#include +#else +#include #endif -#if ((CV_MAJOR_VERSION == 2) && (CV_MINOR_VERSION >=4) && (CV_SUBMINOR_VERSION>=4)) -#define HAVE_OPENCV_FACE + +#ifndef INCLUDE_AVAILABLE_MODULES_ONLY + #define HAVE_OPENCV_CALIB3D + #define HAVE_OPENCV_FEATURES2D + #define HAVE_OPENCV_FLANN + #define HAVE_OPENCV_HIGHGUI + // #define HAVE_OPENCV_IMGCODECS + #define HAVE_OPENCV_IMGPROC + #define HAVE_OPENCV_ML + #define HAVE_OPENCV_OBJDETECT + #define HAVE_OPENCV_PHOTO + #define HAVE_OPENCV_SHAPE + #define HAVE_OPENCV_STITCHING + #define HAVE_OPENCV_SUPERRES + #define HAVE_OPENCV_VIDEO + #define HAVE_OPENCV_VIDEOIO + #define HAVE_OPENCV_VIDEOSTAB + #define HAVE_OPENCV_VIZ #endif #include diff --git a/src/VideoCaptureWrap.cc b/src/VideoCaptureWrap.cc index 6b24d65..30113b7 100755 --- a/src/VideoCaptureWrap.cc +++ b/src/VideoCaptureWrap.cc @@ -4,6 +4,8 @@ #include +#ifdef HAVE_OPENCV_VIDEOIO + Nan::Persistent VideoCaptureWrap::constructor; struct videocapture_baton { @@ -311,3 +313,5 @@ NAN_METHOD(VideoCaptureWrap::Retrieve) { return; } + +#endif diff --git a/src/VideoCaptureWrap.h b/src/VideoCaptureWrap.h index a8a2dc2..bb7d11f 100755 --- a/src/VideoCaptureWrap.h +++ b/src/VideoCaptureWrap.h @@ -1,5 +1,7 @@ #include "OpenCV.h" +#ifdef HAVE_OPENCV_VIDEOIO + class VideoCaptureWrap: public Nan::ObjectWrap { public: cv::VideoCapture cap; @@ -36,3 +38,5 @@ public: // release the stream static NAN_METHOD(Release); }; + +#endif diff --git a/src/init.cc b/src/init.cc index ffbc286..453d076 100755 --- a/src/init.cc +++ b/src/init.cc @@ -24,23 +24,39 @@ extern "C" void init(Local target) { Point::Init(target); Matrix::Init(target); +#ifdef HAVE_OPENCV_OBJDETECT CascadeClassifierWrap::Init(target); +#endif +#ifdef HAVE_OPENCV_VIDEOIO VideoCaptureWrap::Init(target); VideoWriterWrap::Init(target); +#endif Contour::Init(target); +#ifdef HAVE_OPENCV_VIDEO TrackedObject::Init(target); +#endif +#ifdef HAVE_OPENCV_HIGHGUI NamedWindow::Init(target); +#endif Constants::Init(target); +#ifdef HAVE_OPENCV_CALIB3D Calib3D::Init(target); +#endif +#ifdef HAVE_OPENCV_IMGPROC ImgProc::Init(target); Histogram::Init(target); +#endif #if CV_MAJOR_VERSION < 3 StereoBM::Init(target); StereoSGBM::Init(target); StereoGC::Init(target); #if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >=4 - BackgroundSubtractorWrap::Init(target); - Features::Init(target); + #ifdef HAVE_OPENCV_VIDEO + BackgroundSubtractorWrap::Init(target); + #endif + #ifdef HAVE_OPENCV_FEATURES2D + Features::Init(target); + #endif LDAWrap::Init(target); #endif #endif From b7967c3293070842e1053ae2b1b854f81e49d1d0 Mon Sep 17 00:00:00 2001 From: Dan Schultzer Date: Sat, 16 Sep 2017 12:39:32 -0700 Subject: [PATCH 2/8] Fix new face recognizer setup --- src/FaceRecognizer.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/FaceRecognizer.cc b/src/FaceRecognizer.cc index 50b67c4..3393aed 100644 --- a/src/FaceRecognizer.cc +++ b/src/FaceRecognizer.cc @@ -8,9 +8,9 @@ #if CV_MAJOR_VERSION >= 3 namespace cv { using std::vector; - using cv::face::createEigenFaceRecognizer; - using cv::face::createFisherFaceRecognizer; - using cv::face::createLBPHFaceRecognizer; + using cv::face::EigenFaceRecognizer; + using cv::face::FisherFaceRecognizer; + using cv::face::LBPHFaceRecognizer; } #endif @@ -68,7 +68,7 @@ NAN_METHOD(FaceRecognizerWrap::New) { } // By default initialize LBPH - cv::Ptr f = cv::createLBPHFaceRecognizer(1, 8, 8, 8, 80.0); + cv::Ptr f = cv::LBPHFaceRecognizer::create(1, 8, 8, 8, 80.0); FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, LBPH); pt->Wrap(info.This()); @@ -91,7 +91,7 @@ NAN_METHOD(FaceRecognizerWrap::CreateLBPH) { DOUBLE_FROM_ARGS(threshold, 4) Local n = Nan::NewInstance(Nan::GetFunction(Nan::New(FaceRecognizerWrap::constructor)).ToLocalChecked()).ToLocalChecked(); - cv::Ptr f = cv::createLBPHFaceRecognizer(radius, + cv::Ptr f = cv::LBPHFaceRecognizer::create(radius, neighbors, grid_x, grid_y, threshold); FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, LBPH); pt->Wrap(n); @@ -109,7 +109,7 @@ NAN_METHOD(FaceRecognizerWrap::CreateEigen) { DOUBLE_FROM_ARGS(threshold, 1) Local n = Nan::NewInstance(Nan::GetFunction(Nan::New(FaceRecognizerWrap::constructor)).ToLocalChecked()).ToLocalChecked(); - cv::Ptr f = cv::createEigenFaceRecognizer(components, + cv::Ptr f = cv::EigenFaceRecognizer::create(components, threshold); FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, EIGEN); pt->Wrap(n); @@ -128,7 +128,7 @@ NAN_METHOD(FaceRecognizerWrap::CreateFisher) { Local n = Nan::NewInstance(Nan::GetFunction(Nan::New(FaceRecognizerWrap::constructor)).ToLocalChecked()).ToLocalChecked(); - cv::Ptr f = cv::createFisherFaceRecognizer(components, + cv::Ptr f = cv::FisherFaceRecognizer::create(components, threshold); FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, FISHER); pt->Wrap(n); @@ -378,7 +378,7 @@ NAN_METHOD(FaceRecognizerWrap::SaveSync) { JSTHROW("Save takes a filename") } std::string filename = std::string(*Nan::Utf8String(info[0]->ToString())); - self->rec->save(filename); + self->rec->write(filename); return; } @@ -388,7 +388,7 @@ NAN_METHOD(FaceRecognizerWrap::LoadSync) { JSTHROW("Load takes a filename") } std::string filename = std::string(*Nan::Utf8String(info[0]->ToString())); - self->rec->load(filename); + self->rec->read(filename); return; } From b8169e009b508567fcf71abfdb1bcdbe64994c95 Mon Sep 17 00:00:00 2001 From: Dan Schultzer Date: Sat, 16 Sep 2017 13:02:47 -0700 Subject: [PATCH 3/8] Remove VideoWriterWrap --- src/VideoWriterWrap.cc | 3 +++ src/VideoWriterWrap.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/VideoWriterWrap.cc b/src/VideoWriterWrap.cc index dcc0e1d..37fbcbc 100755 --- a/src/VideoWriterWrap.cc +++ b/src/VideoWriterWrap.cc @@ -4,6 +4,8 @@ #include +#ifdef HAVE_OPENCV_VIDEOIO + Nan::Persistent VideoWriterWrap::constructor; struct videowriter_baton { @@ -150,3 +152,4 @@ NAN_METHOD(VideoWriterWrap::WriteSync) { info.GetReturnValue().Set(Nan::Null()); } +#endif diff --git a/src/VideoWriterWrap.h b/src/VideoWriterWrap.h index 1023854..a17ac27 100755 --- a/src/VideoWriterWrap.h +++ b/src/VideoWriterWrap.h @@ -1,5 +1,7 @@ #include "OpenCV.h" +#ifdef HAVE_OPENCV_VIDEOIO + class VideoWriterWrap: public Nan::ObjectWrap { public: cv::VideoWriter writer; @@ -16,3 +18,5 @@ public: // release the stream static NAN_METHOD(Release); }; + +#endif From a58656270f849cd48a0d8d7f466cf058907948b9 Mon Sep 17 00:00:00 2001 From: Dan Schultzer Date: Sat, 16 Sep 2017 13:13:08 -0700 Subject: [PATCH 4/8] Disable CalcOpticalFlowPyrLK when no vid module --- src/Matrix.cc | 6 +++++- src/Matrix.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Matrix.cc b/src/Matrix.cc index e8ccfe3..099ffe2 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -83,7 +83,9 @@ void Matrix::Init(Local target) { Nan::SetPrototypeMethod(ctor, "drawContour", DrawContour); Nan::SetPrototypeMethod(ctor, "drawAllContours", DrawAllContours); Nan::SetPrototypeMethod(ctor, "goodFeaturesToTrack", GoodFeaturesToTrack); + #ifdef HAVE_OPENCV_VIDEO Nan::SetPrototypeMethod(ctor, "calcOpticalFlowPyrLK", CalcOpticalFlowPyrLK); + #endif Nan::SetPrototypeMethod(ctor, "houghLinesP", HoughLinesP); Nan::SetPrototypeMethod(ctor, "houghCircles", HoughCircles); Nan::SetPrototypeMethod(ctor, "inRange", inRange); @@ -651,7 +653,7 @@ NAN_METHOD(Matrix::PixelCol) { int height = self->mat.size().height; int x = info[0]->IntegerValue(); v8::Local < v8::Array > arr; - + if (self->mat.channels() == 4) { arr = Nan::New(height * 4); for (int y = 0; y < height; y++) { @@ -1697,6 +1699,7 @@ NAN_METHOD(Matrix::GoodFeaturesToTrack) { info.GetReturnValue().Set(arr); } +#ifdef HAVE_OPENCV_VIDEO NAN_METHOD(Matrix::CalcOpticalFlowPyrLK) { Nan::HandleScope scope; @@ -1773,6 +1776,7 @@ NAN_METHOD(Matrix::CalcOpticalFlowPyrLK) { info.GetReturnValue().Set(data); } +#endif NAN_METHOD(Matrix::HoughLinesP) { Nan::HandleScope scope; diff --git a/src/Matrix.h b/src/Matrix.h index 15799dd..5033c61 100755 --- a/src/Matrix.h +++ b/src/Matrix.h @@ -90,7 +90,9 @@ public: // Feature Detection JSFUNC(GoodFeaturesToTrack) + #ifdef HAVE_OPENCV_VIDEO JSFUNC(CalcOpticalFlowPyrLK) + #endif JSFUNC(HoughLinesP) JSFUNC(HoughCircles) From b67c96ee31fe7380b609e4cfa18afe671f02e690 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Thu, 2 Nov 2017 08:48:59 +0000 Subject: [PATCH 5/8] Matrix: Add aync to resize. If first argument is fn(err, img), then run async. Also add fx,fy arguments. call styles may be: Sync (modify existing image, new image is CV_32FC3) - same interface as before except added fx,fy im.resize( width, height ); im.resize( width, height, fx, fy ); im.resize( width, height, interpolation ); im.resize( width, height, fx, fy, interpolation ); Async (create new image, new image is not forced to CV_32FC3?) im.resize( fn, width, height ); im.resize( fn, width, height, fx, fy ); im.resize( fn, width, height, interpolation ); im.resize( fn, width, height, fx, fy, interpolation ); --- src/Matrix.cc | 145 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 128 insertions(+), 17 deletions(-) diff --git a/src/Matrix.cc b/src/Matrix.cc index 099ffe2..a9aeae3 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -1889,27 +1889,138 @@ cv::Rect* setRect(Local objRect, cv::Rect &result) { return &result; } + +class ResizeASyncWorker: public Nan::AsyncWorker { +public: + ResizeASyncWorker(Nan::Callback *callback, Matrix *image, cv::Size size, double fx, double fy, int interpolation) : + Nan::AsyncWorker(callback), + image(image), + size(size), + fx(fx), + fy(fy), + interpolation(interpolation), + success(0){ + } + + ~ResizeASyncWorker() { + } + + void Execute() { + try { + dest = new Matrix(); + cv::resize(image->mat, dest->mat, size, fx, fy, interpolation); + success = 1; + } catch(...){ + success = 0; + } + } + + void HandleOKCallback() { + Nan::HandleScope scope; + + if (success){ + Local im_to_return= Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); + Matrix *img = Nan::ObjectWrap::Unwrap(im_to_return); + img->mat = dest->mat; + delete dest; + + //delete dest; + + Local argv[] = { + Nan::Null(), // err + im_to_return //result + }; + + Nan::TryCatch try_catch; + callback->Call(2, argv); + if (try_catch.HasCaught()) { + Nan::FatalException(try_catch); + } + } else { + delete dest; + + Local argv[] = { + Nan::New("C++ exception").ToLocalChecked(), // err + Nan::Null() //result + }; + + Nan::TryCatch try_catch; + callback->Call(2, argv); + if (try_catch.HasCaught()) { + Nan::FatalException(try_catch); + } + } + } + +private: + Matrix *image; + Matrix *dest; + cv::Size size; + double fx; + double fy; + int interpolation; + int success; + +}; + + NAN_METHOD(Matrix::Resize) { - Nan::HandleScope scope; + SETUP_FUNCTION(Matrix) - int x = info[0]->Uint32Value(); - int y = info[1]->Uint32Value(); - /* - CV_INTER_NN =0, - CV_INTER_LINEAR =1, - CV_INTER_CUBIC =2, - CV_INTER_AREA =3, - CV_INTER_LANCZOS4 =4 - */ - int interpolation = (info.Length() < 3) ? (int)cv::INTER_LINEAR : info[2]->Uint32Value(); + if (info.Length() < 2) { + return Nan::ThrowError("Matrix.resize requires at least 2 argument2"); + } - Matrix *self = Nan::ObjectWrap::Unwrap(info.This()); - cv::Mat res = cv::Mat(x, y, CV_32FC3); - cv::resize(self->mat, res, cv::Size(x, y), 0, 0, interpolation); - ~self->mat; - self->mat = res; + // if we want async + int offset = 0; + if (info[0]->IsFunction()){ + offset = 1; + } - return; + if (info.Length() < 2+offset) { + return Nan::ThrowError("Matrix.resize requires at least x and y size argument2"); + } + + int x = info[offset+0]->Uint32Value(); + int y = info[offset+1]->Uint32Value(); + + cv::Size size(x, y); + + if (size.area() == 0) { + return Nan::ThrowError("Area of size must be > 0"); + } + + double fx = 0; + double fy = 0; + int interpolation = cv::INTER_LINEAR; + + // if 4 or more args, then expect fx, fy next + if (info.Length() >= 4+offset) { + DOUBLE_FROM_ARGS(fx, 2+offset) + DOUBLE_FROM_ARGS(fy, 3+offset) + } + + // if 3 args after possible function, expect interpolation + if (info.Length() == 3+offset) { + INT_FROM_ARGS(interpolation, 3+offset) + } + if (info.Length() == 5+offset) { + INT_FROM_ARGS(interpolation, 5+offset) + } + + // if async + if (offset){ + REQ_FUN_ARG(0, cb); + Nan::Callback *callback = new Nan::Callback(cb.As()); + Nan::AsyncQueueWorker(new ResizeASyncWorker(callback, self, size, fx, fy, interpolation)); + info.GetReturnValue().Set(Nan::Null()); + } else { + Matrix *self = Nan::ObjectWrap::Unwrap(info.This()); + cv::Mat res = cv::Mat(x, y, CV_32FC3); + cv::resize(self->mat, res, cv::Size(x, y), 0, 0, interpolation); + ~self->mat; + self->mat = res; + } } NAN_METHOD(Matrix::Rotate) { From 44f175632c4c4a67e9bb75b9ee7eb55789a89d37 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Thu, 2 Nov 2017 09:44:57 +0000 Subject: [PATCH 6/8] resize: move async fn to last argument --- src/Matrix.cc | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/Matrix.cc b/src/Matrix.cc index a9aeae3..962230a 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -1971,18 +1971,25 @@ NAN_METHOD(Matrix::Resize) { return Nan::ThrowError("Matrix.resize requires at least 2 argument2"); } - // if we want async - int offset = 0; - if (info[0]->IsFunction()){ - offset = 1; + //im.resize( width, height ); + //im.resize( width, height, fx, fy ); + //im.resize( width, height, interpolation ); + //im.resize( width, height, fx, fy, interpolation ); + // if fn is added on the end, makes it Async + + int numargs = info.Length(); + int isAsync = 0; + + if (info[numargs-1]->IsFunction()){ + isAsync = 1; } - if (info.Length() < 2+offset) { + if (info.Length() < 2+isAsync) { return Nan::ThrowError("Matrix.resize requires at least x and y size argument2"); } - int x = info[offset+0]->Uint32Value(); - int y = info[offset+1]->Uint32Value(); + int x = info[0]->Uint32Value(); + int y = info[1]->Uint32Value(); cv::Size size(x, y); @@ -1995,22 +2002,22 @@ NAN_METHOD(Matrix::Resize) { int interpolation = cv::INTER_LINEAR; // if 4 or more args, then expect fx, fy next - if (info.Length() >= 4+offset) { - DOUBLE_FROM_ARGS(fx, 2+offset) - DOUBLE_FROM_ARGS(fy, 3+offset) + if (numargs >= 4+isAsync) { + DOUBLE_FROM_ARGS(fx, 2) + DOUBLE_FROM_ARGS(fy, 3) + if (numargs == 5+isAsync) { + INT_FROM_ARGS(interpolation, 5) + } + } else { + // if 3 args after possible function, expect interpolation + if (numargs == 3+isAsync) { + INT_FROM_ARGS(interpolation, 3) + } } - // if 3 args after possible function, expect interpolation - if (info.Length() == 3+offset) { - INT_FROM_ARGS(interpolation, 3+offset) - } - if (info.Length() == 5+offset) { - INT_FROM_ARGS(interpolation, 5+offset) - } - // if async - if (offset){ - REQ_FUN_ARG(0, cb); + if (isAsync){ + REQ_FUN_ARG(numargs-1, cb); Nan::Callback *callback = new Nan::Callback(cb.As()); Nan::AsyncQueueWorker(new ResizeASyncWorker(callback, self, size, fx, fy, interpolation)); info.GetReturnValue().Set(Nan::Null()); From f2e1fc3e1ee775f378751454c942837fcf19a55a Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Thu, 2 Nov 2017 19:47:34 +0000 Subject: [PATCH 7/8] VideoCaptureWrap: Add setFPS - returns FPS read back. --- src/VideoCaptureWrap.cc | 16 ++++++++++++++++ src/VideoCaptureWrap.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/VideoCaptureWrap.cc b/src/VideoCaptureWrap.cc index 30113b7..d3e6c98 100755 --- a/src/VideoCaptureWrap.cc +++ b/src/VideoCaptureWrap.cc @@ -38,6 +38,7 @@ void VideoCaptureWrap::Init(Local target) { Nan::SetPrototypeMethod(ctor, "getFrameAt", GetFrameAt); Nan::SetPrototypeMethod(ctor, "getFrameCount", GetFrameCount); Nan::SetPrototypeMethod(ctor, "getFPS", GetFPS); + Nan::SetPrototypeMethod(ctor, "setFPS", SetFPS); Nan::SetPrototypeMethod(ctor, "release", Release); Nan::SetPrototypeMethod(ctor, "ReadSync", ReadSync); Nan::SetPrototypeMethod(ctor, "grab", Grab); @@ -127,6 +128,21 @@ NAN_METHOD(VideoCaptureWrap::GetFPS) { info.GetReturnValue().Set(Nan::New(fps)); } +NAN_METHOD(VideoCaptureWrap::SetFPS) { + Nan::HandleScope scope; + VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); + + if (info.Length() > 0) { + if (info[0]->IsNumber()) { + int fps = info[0]->IntegerValue(); + v->cap.set(CV_CAP_PROP_FPS, fps); + } + } + + int fps = int(v->cap.get(CV_CAP_PROP_FPS)); + + info.GetReturnValue().Set(Nan::New(fps)); +} NAN_METHOD(VideoCaptureWrap::GetHeight) { Nan::HandleScope scope; diff --git a/src/VideoCaptureWrap.h b/src/VideoCaptureWrap.h index bb7d11f..dc1c3da 100755 --- a/src/VideoCaptureWrap.h +++ b/src/VideoCaptureWrap.h @@ -32,6 +32,7 @@ public: static NAN_METHOD(GetFrameCount); static NAN_METHOD(GetFPS); + static NAN_METHOD(SetFPS); static NAN_METHOD(GetFrameAt); From 9e4f21444101352043ba873d0bf7e5caa8cc0788 Mon Sep 17 00:00:00 2001 From: Simon Hailes Date: Fri, 3 Nov 2017 08:34:59 +0000 Subject: [PATCH 8/8] Add resize example --- examples/async-resize.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 examples/async-resize.js diff --git a/examples/async-resize.js b/examples/async-resize.js new file mode 100644 index 0000000..70a1c7d --- /dev/null +++ b/examples/async-resize.js @@ -0,0 +1,34 @@ +var cv = require('../lib/opencv'); + +cv.readImage("./files/mona.png", function(err, im) { + if (err) throw err; + + var width = im.width(); + var height = im.height(); + if (width < 1 || height < 1) throw new Error('Image has no size'); + + console.log('Image loaded from ./files/mona.png at '+im.width()+'x'+im.height()); + + var AfterResize = function(err, img){ + if (err){ + console.log('Error in resize:' + err); + return; + } + img.save("./tmp/resize-async-image.png"); + console.log('Image saved to ./tmp/resize-async-image.png at '+img.width()+'x'+img.height()); + }; + + var newwidth = width*0.95; + var newheight = height*0.95; + + var Async = true; + if (Async){ + // note - generates a new image + im.resize(newwidth, newheight, AfterResize); + } else { + // sync - note - modifies the input image + im.resize(newwidth, newheight); + AfterResize(null, im); + } + +});