diff --git a/.gitignore b/.gitignore index 382b1ae..5639a1e 100755 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ examples/*.avi examples/tmp/* vagrant/.vagrant coverage/ +.idea diff --git a/examples/optical-flow.js b/examples/optical-flow.js new file mode 100755 index 0000000..3e2f48b --- /dev/null +++ b/examples/optical-flow.js @@ -0,0 +1,67 @@ +var cv = require('../lib/opencv'); +var path = require('path'); + +var cap = new cv.VideoCapture(path.join(__dirname, 'files', 'motion.mov')); + +// Parameters for lucas kanade optical flow +var lk_params = { + winSize: [15, 15], + maxLevel: 2, + criteria: [cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 30, 0.03] +}; + +feature_params = { + maxCorners: 100, + qualityLevel: 0.1, + minDistance: 10 +}; + +// Create some random colors +var color = [255, 0, 0]; + +/* +var window = new cv.NamedWindow('Video', 0); +*/ + +// Take first frame and find corners in it +cap.read(function(err, firstFrame) { + if (err) throw err; + + var old_frame = firstFrame; + + // Create a mask image for drawing purposes + function read() { + var out = old_frame.copy(); + cap.read(function(err, newFrame) { + if (err) throw err; + + var frameSize = newFrame.size(); + + if ( frameSize[0] > 0 && frameSize[1] > 0) { + var goodFeatures = old_frame.goodFeaturesToTrack(feature_params.maxCorners, feature_params.qualityLevel, feature_params.minDistance); + + // calculate optical flow + var flow = old_frame.calcOpticalFlowPyrLK(newFrame, goodFeatures, lk_params.winSize, lk_params.maxLevel, lk_params.criteria); + + // Select good points + + // draw the tracks + for(var i = 0; i < flow.old_points.length; i++){ + if(flow.found[i]){ + out.line(flow.old_points[i], flow.new_points[i], color); + } + } + +/* + window.show(out); + window.blockingWaitKey(0, 50); +*/ + + old_frame = newFrame.copy(); + read(); + } + }); + } + + read(); +}); \ No newline at end of file diff --git a/src/Constants.cc b/src/Constants.cc index d6f0ff1..b2ab548 100644 --- a/src/Constants.cc +++ b/src/Constants.cc @@ -101,6 +101,9 @@ void Constants::Init(Local target) { CONST_INT(CV_DIST_MASK_5); CONST_INT(CV_DIST_MASK_PRECISE); + target->Set(Nan::New("TERM_CRITERIA_EPS").ToLocalChecked(), Nan::New((int)cv::TermCriteria::EPS)); + target->Set(Nan::New("TERM_CRITERIA_COUNT").ToLocalChecked(), Nan::New((int)cv::TermCriteria::COUNT)); + target->Set(Nan::New("Constants").ToLocalChecked(), obj); } diff --git a/src/Matrix.cc b/src/Matrix.cc index f0134aa..cda5221 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -82,6 +82,7 @@ void Matrix::Init(Local target) { Nan::SetPrototypeMethod(ctor, "drawContour", DrawContour); Nan::SetPrototypeMethod(ctor, "drawAllContours", DrawAllContours); Nan::SetPrototypeMethod(ctor, "goodFeaturesToTrack", GoodFeaturesToTrack); + Nan::SetPrototypeMethod(ctor, "calcOpticalFlowPyrLK", CalcOpticalFlowPyrLK); Nan::SetPrototypeMethod(ctor, "houghLinesP", HoughLinesP); Nan::SetPrototypeMethod(ctor, "houghCircles", HoughCircles); Nan::SetPrototypeMethod(ctor, "inRange", inRange); @@ -1596,13 +1597,17 @@ NAN_METHOD(Matrix::GoodFeaturesToTrack) { Nan::HandleScope scope; Matrix *self = Nan::ObjectWrap::Unwrap(info.This()); + int maxCorners = info.Length() >= 1 ? info[0]->IntegerValue() : 500; + double qualityLevel = info.Length() >= 2 ? (double) info[1]->NumberValue() : 0.01; + double minDistance = info.Length() >= 3 ? (double) info[2]->NumberValue() : 10; + std::vector corners; cv::Mat gray; cvtColor(self->mat, gray, CV_BGR2GRAY); equalizeHist(gray, gray); - cv::goodFeaturesToTrack(gray, corners, 500, 0.01, 10); + cv::goodFeaturesToTrack(gray, corners, maxCorners, qualityLevel, minDistance); v8::Local arr = Nan::New(corners.size()); for (unsigned int i=0; i(info.This()); + Matrix *newMatrix = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); + Local points = Local::Cast(info[1]->ToObject()); + std::vector old_points; + + for (unsigned int i=0; iLength(); i++) { + Local pt = points->Get(i)->ToObject(); + old_points.push_back(cv::Point2f(pt->Get(0)->NumberValue(), pt->Get(1)->NumberValue())); + } + + cv::Size winSize; + if (info.Length() >= 3 && info[2]->IsArray()) { + Local winSizeObj = info[2]->ToObject(); + winSize = cv::Size(winSizeObj->Get(0)->IntegerValue(), winSizeObj->Get(1)->IntegerValue()); + } else { + winSize = cv::Size(21, 21); + } + + int maxLevel = info.Length() >= 4 ? info[3]->IntegerValue() : 3; + + cv::TermCriteria criteria; + if (info.Length() >= 5 && info[4]->IsArray()) { + Local criteriaObj = info[4]->ToObject(); + criteria = cv::TermCriteria(criteriaObj->Get(0)->IntegerValue(), criteriaObj->Get(1)->IntegerValue(), (double) criteriaObj->Get(2)->NumberValue()); + } else { + criteria = cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 30, 0.01); + } + + int flags = info.Length() >= 6 ? info[5]->IntegerValue() : 0; + double minEigThreshold = info.Length() >= 7 ? info[6]->NumberValue() : 1e-4; + + cv::Mat old_gray; + cv::cvtColor(self->mat, old_gray, CV_BGR2GRAY); + + cv::Mat new_gray; + cv::cvtColor(newMatrix->mat, new_gray, CV_BGR2GRAY); + + std::vector new_points; + std::vector status; + std::vector err; + + cv::calcOpticalFlowPyrLK(old_gray, new_gray, old_points, new_points, status, err, winSize, maxLevel, criteria, flags, minEigThreshold); + + v8::Local old_arr = Nan::New(old_points.size()); + v8::Local new_arr = Nan::New(new_points.size()); + v8::Local found = Nan::New(status.size()); + + for (unsigned int i=0; i pt = Nan::New(2); + pt->Set(0, Nan::New((double) old_points[i].x)); + pt->Set(1, Nan::New((double) old_points[i].y)); + old_arr->Set(i, pt); + } + + for (unsigned int i=0; i pt = Nan::New(2); + pt->Set(0, Nan::New((double) new_points[i].x)); + pt->Set(1, Nan::New((double) new_points[i].y)); + new_arr->Set(i, pt); + } + + for (unsigned int i=0; i pt = Nan::New((int)status[i]); + found->Set(i, pt); + } + + Local data = Nan::New(); + data->Set(Nan::New("old_points").ToLocalChecked(), old_arr); + data->Set(Nan::New("new_points").ToLocalChecked(), new_arr); + data->Set(Nan::New("found").ToLocalChecked(), found); + + info.GetReturnValue().Set(data); +} + NAN_METHOD(Matrix::HoughLinesP) { Nan::HandleScope scope; diff --git a/src/Matrix.h b/src/Matrix.h index b672879..c9a9875 100755 --- a/src/Matrix.h +++ b/src/Matrix.h @@ -89,6 +89,7 @@ public: // Feature Detection JSFUNC(GoodFeaturesToTrack) + JSFUNC(CalcOpticalFlowPyrLK) JSFUNC(HoughLinesP) JSFUNC(HoughCircles)