Merge pull request #495 from madshall/master

CalcOpticalFlowPyrLK added and GoodFeaturesToTrack fixed
This commit is contained in:
Peter Braden 2017-03-09 18:21:59 +01:00 committed by GitHub
commit 7d0631ba3e
5 changed files with 155 additions and 1 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ examples/*.avi
examples/tmp/* examples/tmp/*
vagrant/.vagrant vagrant/.vagrant
coverage/ coverage/
.idea

67
examples/optical-flow.js Executable file
View File

@ -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();
});

View File

@ -101,6 +101,9 @@ void Constants::Init(Local<Object> target) {
CONST_INT(CV_DIST_MASK_5); CONST_INT(CV_DIST_MASK_5);
CONST_INT(CV_DIST_MASK_PRECISE); CONST_INT(CV_DIST_MASK_PRECISE);
target->Set(Nan::New("TERM_CRITERIA_EPS").ToLocalChecked(), Nan::New<Integer>((int)cv::TermCriteria::EPS));
target->Set(Nan::New("TERM_CRITERIA_COUNT").ToLocalChecked(), Nan::New<Integer>((int)cv::TermCriteria::COUNT));
target->Set(Nan::New("Constants").ToLocalChecked(), obj); target->Set(Nan::New("Constants").ToLocalChecked(), obj);
} }

View File

@ -82,6 +82,7 @@ void Matrix::Init(Local<Object> target) {
Nan::SetPrototypeMethod(ctor, "drawContour", DrawContour); Nan::SetPrototypeMethod(ctor, "drawContour", DrawContour);
Nan::SetPrototypeMethod(ctor, "drawAllContours", DrawAllContours); Nan::SetPrototypeMethod(ctor, "drawAllContours", DrawAllContours);
Nan::SetPrototypeMethod(ctor, "goodFeaturesToTrack", GoodFeaturesToTrack); Nan::SetPrototypeMethod(ctor, "goodFeaturesToTrack", GoodFeaturesToTrack);
Nan::SetPrototypeMethod(ctor, "calcOpticalFlowPyrLK", CalcOpticalFlowPyrLK);
Nan::SetPrototypeMethod(ctor, "houghLinesP", HoughLinesP); Nan::SetPrototypeMethod(ctor, "houghLinesP", HoughLinesP);
Nan::SetPrototypeMethod(ctor, "houghCircles", HoughCircles); Nan::SetPrototypeMethod(ctor, "houghCircles", HoughCircles);
Nan::SetPrototypeMethod(ctor, "inRange", inRange); Nan::SetPrototypeMethod(ctor, "inRange", inRange);
@ -1596,13 +1597,17 @@ NAN_METHOD(Matrix::GoodFeaturesToTrack) {
Nan::HandleScope scope; Nan::HandleScope scope;
Matrix *self = Nan::ObjectWrap::Unwrap<Matrix>(info.This()); Matrix *self = Nan::ObjectWrap::Unwrap<Matrix>(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<cv::Point2f> corners; std::vector<cv::Point2f> corners;
cv::Mat gray; cv::Mat gray;
cvtColor(self->mat, gray, CV_BGR2GRAY); cvtColor(self->mat, gray, CV_BGR2GRAY);
equalizeHist(gray, gray); equalizeHist(gray, gray);
cv::goodFeaturesToTrack(gray, corners, 500, 0.01, 10); cv::goodFeaturesToTrack(gray, corners, maxCorners, qualityLevel, minDistance);
v8::Local<v8::Array> arr = Nan::New<Array>(corners.size()); v8::Local<v8::Array> arr = Nan::New<Array>(corners.size());
for (unsigned int i=0; i<corners.size(); i++) { for (unsigned int i=0; i<corners.size(); i++) {
@ -1615,6 +1620,83 @@ NAN_METHOD(Matrix::GoodFeaturesToTrack) {
info.GetReturnValue().Set(arr); info.GetReturnValue().Set(arr);
} }
NAN_METHOD(Matrix::CalcOpticalFlowPyrLK) {
Nan::HandleScope scope;
Matrix *self = Nan::ObjectWrap::Unwrap<Matrix>(info.This());
Matrix *newMatrix = Nan::ObjectWrap::Unwrap<Matrix>(info[0]->ToObject());
Local<Array> points = Local<Array>::Cast(info[1]->ToObject());
std::vector<cv::Point2f> old_points;
for (unsigned int i=0; i<points->Length(); i++) {
Local<Object> 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<Object> 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<Object> 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<cv::Point2f> new_points;
std::vector<uchar> status;
std::vector<float> err;
cv::calcOpticalFlowPyrLK(old_gray, new_gray, old_points, new_points, status, err, winSize, maxLevel, criteria, flags, minEigThreshold);
v8::Local<v8::Array> old_arr = Nan::New<Array>(old_points.size());
v8::Local<v8::Array> new_arr = Nan::New<Array>(new_points.size());
v8::Local<v8::Array> found = Nan::New<Array>(status.size());
for (unsigned int i=0; i<old_points.size(); i++) {
v8::Local<v8::Array> pt = Nan::New<Array>(2);
pt->Set(0, Nan::New<Number>((double) old_points[i].x));
pt->Set(1, Nan::New<Number>((double) old_points[i].y));
old_arr->Set(i, pt);
}
for (unsigned int i=0; i<new_points.size(); i++) {
v8::Local<v8::Array> pt = Nan::New<Array>(2);
pt->Set(0, Nan::New<Number>((double) new_points[i].x));
pt->Set(1, Nan::New<Number>((double) new_points[i].y));
new_arr->Set(i, pt);
}
for (unsigned int i=0; i<status.size(); i++) {
v8::Local<v8::Integer> pt = Nan::New<Integer>((int)status[i]);
found->Set(i, pt);
}
Local<Object> data = Nan::New<Object>();
data->Set(Nan::New<String>("old_points").ToLocalChecked(), old_arr);
data->Set(Nan::New<String>("new_points").ToLocalChecked(), new_arr);
data->Set(Nan::New<String>("found").ToLocalChecked(), found);
info.GetReturnValue().Set(data);
}
NAN_METHOD(Matrix::HoughLinesP) { NAN_METHOD(Matrix::HoughLinesP) {
Nan::HandleScope scope; Nan::HandleScope scope;

View File

@ -89,6 +89,7 @@ public:
// Feature Detection // Feature Detection
JSFUNC(GoodFeaturesToTrack) JSFUNC(GoodFeaturesToTrack)
JSFUNC(CalcOpticalFlowPyrLK)
JSFUNC(HoughLinesP) JSFUNC(HoughLinesP)
JSFUNC(HoughCircles) JSFUNC(HoughCircles)