diff --git a/README.md b/README.md index 8060758..37d61ef 100755 --- a/README.md +++ b/README.md @@ -172,29 +172,29 @@ See [relevant source code](src/Contours.cc) and [examples](examples/) ```javascript var contours = im.findContours; -# Count of contours in the Contours object +// Count of contours in the Contours object contours.size(); -# Count of corners(verticies) of contour `index` +// Count of corners(verticies) of contour `index` contours.cornerCount(index); -# Access vertex data of contours +// Access vertex data of contours for(var c = 0; c < contours.size(); ++c) { console.log("Contour " + c); for(var i = 0; i < contours.cornerCount(c); ++i) { var point = contours.point(c, i); - console.log("(" + point.x + "," + point.y + ")");" + console.log("(" + point.x + "," + point.y + ")"); } } -# Computations of contour `index` +// Computations of contour `index` contours.area(index); contours.arcLength(index, isClosed); contours.boundingRect(index); contours.minAreaRect(index); contours.isConvex(index); -# Destructively alter contour `index` +// Destructively alter contour `index` contours.approxPolyDP(index, epsilon, isClosed); contours.convexHull(index, clockwise); ``` diff --git a/package.json b/package.json index b699864..1761858 100755 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "dependencies": { "node-pre-gyp": "0.5.31", "buffers": "0.1.1", - "nan": "^1.3.0" + "nan": "1.4.3" }, "version": "1.0.0", "devDependencies": { diff --git a/src/Calib3D.cc b/src/Calib3D.cc new file mode 100644 index 0000000..f223fef --- /dev/null +++ b/src/Calib3D.cc @@ -0,0 +1,375 @@ +#include "Calib3D.h" +#include "Matrix.h" + +void Calib3D::Init(Handle target) +{ + Persistent inner; + Local obj = NanNew(); + NanAssignPersistent(inner, obj); + + NODE_SET_METHOD(obj, "findChessboardCorners", FindChessboardCorners); + NODE_SET_METHOD(obj, "drawChessboardCorners", DrawChessboardCorners); + NODE_SET_METHOD(obj, "calibrateCamera", CalibrateCamera); + NODE_SET_METHOD(obj, "solvePnP", SolvePnP); + NODE_SET_METHOD(obj, "getOptimalNewCameraMatrix", GetOptimalNewCameraMatrix); + + target->Set(NanNew("calib3d"), obj); +} + +// cv::findChessboardCorners +NAN_METHOD(Calib3D::FindChessboardCorners) +{ + NanEscapableScope(); + + try { + // Get the arguments from javascript + + // Arg 0 is the image + Matrix* m = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::Mat mat = m->mat; + + // Arg 1 is the pattern size + cv::Size patternSize; + if (args[1]->IsArray()) { + Local v8sz = args[1]->ToObject(); + + patternSize = cv::Size(v8sz->Get(0)->IntegerValue(), v8sz->Get(1)->IntegerValue()); + } else { + JSTHROW_TYPE("Must pass pattern size"); + } + + // Arg 2 would normally be the flags, ignoring this for now and using the default flags + + // Find the corners + std::vector corners; + bool found = cv::findChessboardCorners(mat, patternSize, corners); + + // Make the return value + Local ret = NanNew(); + ret->Set(NanNew("found"), NanNew(found)); + + Local cornersArray = NanNew(corners.size()); + for(unsigned int i = 0; i < corners.size(); i++) + { + Local point_data = NanNew(); + point_data->Set(NanNew("x"), NanNew(corners[i].x)); + point_data->Set(NanNew("y"), NanNew(corners[i].y)); + + cornersArray->Set(NanNew(i), point_data); + } + + ret->Set(NanNew("corners"), cornersArray); + + NanReturnValue(ret); + + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } + +}; + +// cv::drawChessboardCorners +NAN_METHOD(Calib3D::DrawChessboardCorners) +{ + NanEscapableScope(); + + try { + // Get the arguments + + // Arg 0 is the image + Matrix* m = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::Mat mat = m->mat; + + // Arg 1 is the pattern size + cv::Size patternSize; + if (args[1]->IsArray()) { + Local v8sz = args[1]->ToObject(); + + patternSize = cv::Size(v8sz->Get(0)->IntegerValue(), v8sz->Get(1)->IntegerValue()); + } else { + JSTHROW_TYPE("Must pass pattern size"); + } + + // Arg 2 is the corners array + std::vector corners; + if(args[2]->IsArray()) { + Local cornersArray = Local::Cast(args[2]); + + for(unsigned int i = 0; i < cornersArray->Length(); i++) + { + Local pt = cornersArray->Get(i)->ToObject(); + corners.push_back(cv::Point2f(pt->Get(NanNew("x"))->ToNumber()->Value(), + pt->Get(NanNew("y"))->ToNumber()->Value())); + } + } else { + JSTHROW_TYPE("Must pass corners array"); + } + + // Arg 3, pattern found boolean + bool patternWasFound = args[3]->ToBoolean()->Value(); + + // Draw the corners + cv::drawChessboardCorners(mat, patternSize, corners, patternWasFound); + + // Return the passed image, now with corners drawn on it + NanReturnValue(args[0]); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} + +// cv::calibrateCamera +NAN_METHOD(Calib3D::CalibrateCamera) +{ + NanEscapableScope(); + + try { + // Get the arguments + + // Arg 0, the array of object points, an array of arrays + std::vector > objectPoints; + if(args[0]->IsArray()) { + Local objectPointsArray = Local::Cast(args[0]); + + for(unsigned int i = 0; i < objectPointsArray->Length(); i++) + { + std::vector points; + + Local pointsArray = Local::Cast(objectPointsArray->Get(i)); + for(unsigned int j = 0; j < pointsArray->Length(); j++) + { + Local pt = pointsArray->Get(j)->ToObject(); + points.push_back(cv::Point3f(pt->Get(NanNew("x"))->ToNumber()->Value(), + pt->Get(NanNew("y"))->ToNumber()->Value(), + pt->Get(NanNew("z"))->ToNumber()->Value())); + } + + objectPoints.push_back(points); + } + } else { + JSTHROW_TYPE("Must pass array of object points for each frame") + } + + // Arg 1, the image points, another array of arrays =( + std::vector > imagePoints; + if(args[1]->IsArray()) { + Local imagePointsArray = Local::Cast(args[1]); + + for(unsigned int i = 0; i < imagePointsArray->Length(); i++) + { + std::vector points; + + Local pointsArray = Local::Cast(imagePointsArray->Get(i)); + for(unsigned int j = 0; j < pointsArray->Length(); j++) + { + Local pt = pointsArray->Get(j)->ToObject(); + points.push_back(cv::Point2f(pt->Get(NanNew("x"))->ToNumber()->Value(), + pt->Get(NanNew("y"))->ToNumber()->Value())); + } + + imagePoints.push_back(points); + } + } else { + JSTHROW_TYPE("Must pass array of object points for each frame") + } + + // Arg 2, the image size + cv::Size imageSize; + if (args[2]->IsArray()) { + Local v8sz = args[2]->ToObject(); + + imageSize = cv::Size(v8sz->Get(1)->IntegerValue(), v8sz->Get(0)->IntegerValue()); + } else { + JSTHROW_TYPE("Must pass pattern size"); + } + + // Arg 3, 4, input guesses for the camrea matrix and distortion coefficients, skipping for now + cv::Mat K, dist; + + // Arg 5, 6 flags and termination criteria, skipping for now + + // Calibrate the camera + std::vector rvecs, tvecs; + + double error = cv::calibrateCamera(objectPoints, imagePoints, imageSize, K, dist, rvecs, tvecs); + + // make the return values + Local ret = NanNew(); + + // Reprojection error + ret->Set(NanNew("reprojectionError"), NanNew(error)); + + // K + Local KMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *KMatrix = ObjectWrap::Unwrap(KMatrixWrap); + KMatrix->mat = K; + + ret->Set(NanNew("K"), KMatrixWrap); + + // dist + Local distMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *distMatrix = ObjectWrap::Unwrap(distMatrixWrap); + distMatrix->mat = dist; + + ret->Set(NanNew("distortion"), distMatrixWrap); + + // Per frame R and t, skiping for now + + // Return + NanReturnValue(ret); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} + +// cv::solvePnP +NAN_METHOD(Calib3D::SolvePnP) +{ + NanEscapableScope(); + + try { + // Get the arguments + + // Arg 0, the array of object points + std::vector objectPoints; + if(args[0]->IsArray()) { + Local objectPointsArray = Local::Cast(args[0]); + + for(unsigned int i = 0; i < objectPointsArray->Length(); i++) + { + Local pt = objectPointsArray->Get(i)->ToObject(); + objectPoints.push_back(cv::Point3f(pt->Get(NanNew("x"))->ToNumber()->Value(), + pt->Get(NanNew("y"))->ToNumber()->Value(), + pt->Get(NanNew("z"))->ToNumber()->Value())); + } + } else { + JSTHROW_TYPE("Must pass array of object points for each frame") + } + + // Arg 1, the image points + std::vector imagePoints; + if(args[1]->IsArray()) { + Local imagePointsArray = Local::Cast(args[1]); + + for(unsigned int i = 0; i < imagePointsArray->Length(); i++) + { + Local pt = imagePointsArray->Get(i)->ToObject(); + imagePoints.push_back(cv::Point2f(pt->Get(NanNew("x"))->ToNumber()->Value(), + pt->Get(NanNew("y"))->ToNumber()->Value())); + } + } else { + JSTHROW_TYPE("Must pass array of object points for each frame") + } + + // Arg 2, the camera matrix + Matrix* kWrap = ObjectWrap::Unwrap(args[2]->ToObject()); + cv::Mat K = kWrap->mat; + + // Arg 3, the distortion coefficients + Matrix* distWrap = ObjectWrap::Unwrap(args[3]->ToObject()); + cv::Mat dist = distWrap->mat; + + // Arg 4, use extrinsic guess, skipped for now + + // Arg 5, flags, skip for now + + // solve for r and t + cv::Mat rvec, tvec; + + cv::solvePnP(objectPoints, imagePoints, K, dist, rvec, tvec); + + // make the return values + Local ret = NanNew(); + + // rvec + Local rMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *rMatrix = ObjectWrap::Unwrap(rMatrixWrap); + rMatrix->mat = rvec; + + ret->Set(NanNew("rvec"), rMatrixWrap); + + // tvec + Local tMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *tMatrix = ObjectWrap::Unwrap(tMatrixWrap); + tMatrix->mat = tvec; + + ret->Set(NanNew("tvec"), tMatrixWrap); + + // Return + NanReturnValue(ret); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} + +// cv::solvePnP +NAN_METHOD(Calib3D::GetOptimalNewCameraMatrix) +{ + NanEscapableScope(); + + try { + // Get the arguments + + // Arg 0 is the original camera matrix + Matrix* m0 = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::Mat Kin = m0->mat; + + // Arg 1 is the distortion coefficients + Matrix* m1 = ObjectWrap::Unwrap(args[1]->ToObject()); + cv::Mat dist = m1->mat; + + // Arg 2, the image size + cv::Size imageSize; + if (args[2]->IsArray()) { + Local v8sz = args[2]->ToObject(); + + imageSize = cv::Size(v8sz->Get(1)->IntegerValue(), v8sz->Get(0)->IntegerValue()); + } else { + JSTHROW_TYPE("Must pass original image size"); + } + + // Arg 3 is the alpha free scaling parameter + double alpha = args[3]->ToNumber()->Value(); + + // Arg 4, the new image size + cv::Size newImageSize; + if (args[4]->IsArray()) { + Local v8sz = args[4]->ToObject(); + + newImageSize = cv::Size(v8sz->Get(1)->IntegerValue(), v8sz->Get(0)->IntegerValue()); + } else { + JSTHROW_TYPE("Must pass new image size"); + } + + // Arg 5, valid ROI, skip for now + // Arg 6, center principal point, skip for now + + // Get the optimal new camera matrix + cv::Mat Kout = cv::getOptimalNewCameraMatrix(Kin, dist, imageSize, alpha, newImageSize); + + // Wrap the output K + Local KMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *KMatrix = ObjectWrap::Unwrap(KMatrixWrap); + KMatrix->mat = Kout; + + // Return the new K matrix + NanReturnValue(KMatrixWrap); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} diff --git a/src/Calib3D.h b/src/Calib3D.h new file mode 100644 index 0000000..ab5669e --- /dev/null +++ b/src/Calib3D.h @@ -0,0 +1,23 @@ +#ifndef __NODE_CALIB3D_H +#define __NODE_CALIB3D_H + +#include "OpenCV.h" + +// Implementation of calib3d.hpp functions + +class Calib3D: public node::ObjectWrap { +public: + static void Init(Handle target); + + static NAN_METHOD(FindChessboardCorners); + + static NAN_METHOD(DrawChessboardCorners); + + static NAN_METHOD(CalibrateCamera); + + static NAN_METHOD(SolvePnP); + + static NAN_METHOD(GetOptimalNewCameraMatrix); +}; + +#endif diff --git a/src/Constants.cc b/src/Constants.cc index e5b3b68..1d9696b 100644 --- a/src/Constants.cc +++ b/src/Constants.cc @@ -4,6 +4,9 @@ #define CONST(C) \ obj->Set(NanNew(#C), NanNew(C)); +#define CONST_ENUM(C) \ + obj->Set(NanNew(#C), NanNew((int)(cv::C))); + void Constants::Init(Handle target) { Persistent inner; @@ -54,6 +57,12 @@ Constants::Init(Handle target) { CONST(CV_64FC3); CONST(CV_64FC4); + CONST_ENUM(INTER_NEAREST); + CONST_ENUM(INTER_LINEAR); + CONST_ENUM(INTER_AREA); + CONST_ENUM(INTER_CUBIC); + CONST_ENUM(INTER_LANCZOS4); + target->Set(NanNew("Constants"), obj); } diff --git a/src/ImgProc.cc b/src/ImgProc.cc new file mode 100644 index 0000000..d3210fd --- /dev/null +++ b/src/ImgProc.cc @@ -0,0 +1,169 @@ +#include "ImgProc.h" +#include "Matrix.h" + +void ImgProc::Init(Handle target) +{ + Persistent inner; + Local obj = NanNew(); + NanAssignPersistent(inner, obj); + + NODE_SET_METHOD(obj, "undistort", Undistort); + NODE_SET_METHOD(obj, "initUndistortRectifyMap", InitUndistortRectifyMap); + NODE_SET_METHOD(obj, "remap", Remap); + + target->Set(NanNew("imgproc"), obj); +} + +// cv::undistort +NAN_METHOD(ImgProc::Undistort) +{ + NanEscapableScope(); + + try { + // Get the arguments + + // Arg 0 is the image + Matrix* m0 = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::Mat inputImage = m0->mat; + + // Arg 1 is the camera matrix + Matrix* m1 = ObjectWrap::Unwrap(args[1]->ToObject()); + cv::Mat K = m1->mat; + + // Arg 2 is the distortion coefficents + Matrix* m2 = ObjectWrap::Unwrap(args[2]->ToObject()); + cv::Mat dist = m2->mat; + + // Make an mat to hold the result image + cv::Mat outputImage; + + // Undistort + cv::undistort(inputImage, outputImage, K, dist); + + // Wrap the output image + Local outMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *outMatrix = ObjectWrap::Unwrap(outMatrixWrap); + outMatrix->mat = outputImage; + + // Return the output image + NanReturnValue(outMatrixWrap); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} + +// cv::initUndistortRectifyMap +NAN_METHOD(ImgProc::InitUndistortRectifyMap) +{ + NanEscapableScope(); + + try { + + // Arg 0 is the camera matrix + Matrix* m0 = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::Mat K = m0->mat; + + // Arg 1 is the distortion coefficents + Matrix* m1 = ObjectWrap::Unwrap(args[1]->ToObject()); + cv::Mat dist = m1->mat; + + // Arg 2 is the recification transformation + Matrix* m2 = ObjectWrap::Unwrap(args[2]->ToObject()); + cv::Mat R = m2->mat; + + // Arg 3 is the new camera matrix + Matrix* m3 = ObjectWrap::Unwrap(args[3]->ToObject()); + cv::Mat newK = m3->mat; + + // Arg 4 is the image size + cv::Size imageSize; + if (args[4]->IsArray()) { + Local v8sz = args[4]->ToObject(); + + imageSize = cv::Size(v8sz->Get(1)->IntegerValue(), v8sz->Get(0)->IntegerValue()); + } else { + JSTHROW_TYPE("Must pass image size"); + } + + // Arg 5 is the first map type, skip for now + int m1type = args[5]->IntegerValue(); + + // Make matrices to hold the output maps + cv::Mat map1, map2; + + // Compute the rectification map + cv::initUndistortRectifyMap(K, dist, R, newK, imageSize, m1type, map1, map2); + + // Wrap the output maps + Local map1Wrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *map1Matrix = ObjectWrap::Unwrap(map1Wrap); + map1Matrix->mat = map1; + + Local map2Wrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *map2Matrix = ObjectWrap::Unwrap(map2Wrap); + map2Matrix->mat = map2; + + // Make a return object with the two maps + Local ret = NanNew(); + ret->Set(NanNew("map1"), map1Wrap); + ret->Set(NanNew("map2"), map2Wrap); + + // Return the maps + NanReturnValue(ret); + + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} + +// cv::remap +NAN_METHOD(ImgProc::Remap) +{ + NanEscapableScope(); + + try { + // Get the arguments + + // Arg 0 is the image + Matrix* m0 = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::Mat inputImage = m0->mat; + + // Arg 1 is the first map + Matrix* m1 = ObjectWrap::Unwrap(args[1]->ToObject()); + cv::Mat map1 = m1->mat; + + // Arg 2 is the second map + Matrix* m2 = ObjectWrap::Unwrap(args[2]->ToObject()); + cv::Mat map2 = m2->mat; + + // Arg 3 is the interpolation mode + int interpolation = args[3]->IntegerValue(); + + // Args 4, 5 border settings, skipping for now + + // Output image + cv::Mat outputImage; + + // Remap + cv::remap(inputImage, outputImage, map1, map2, interpolation); + + // Wrap the output image + Local outMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *outMatrix = ObjectWrap::Unwrap(outMatrixWrap); + outMatrix->mat = outputImage; + + // Return the image + NanReturnValue(outMatrixWrap); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} diff --git a/src/ImgProc.h b/src/ImgProc.h new file mode 100644 index 0000000..6d26458 --- /dev/null +++ b/src/ImgProc.h @@ -0,0 +1,19 @@ +#ifndef __NODE_IMGPROC_H +#define __NODE_IMGPROC_H + +#include "OpenCV.h" + +// Implementation of imgproc.hpp functions + +class ImgProc: public node::ObjectWrap { +public: + static void Init(Handle target); + + static NAN_METHOD(Undistort); + + static NAN_METHOD(InitUndistortRectifyMap); + + static NAN_METHOD(Remap); +}; + +#endif diff --git a/src/Matrix.cc b/src/Matrix.cc index 4978953..91faa07 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -7,7 +7,7 @@ v8::Persistent Matrix::constructor; cv::Scalar setColor(Local objColor); cv::Point setPoint(Local objPoint); -cv::Rect* setRect(Local objRect); +cv::Rect* setRect(Local objRect, cv::Rect &result); void Matrix::Init(Handle target) { @@ -32,6 +32,7 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(ctor, "height", Height); NODE_SET_PROTOTYPE_METHOD(ctor, "size", Size); NODE_SET_PROTOTYPE_METHOD(ctor, "clone", Clone); + NODE_SET_PROTOTYPE_METHOD(ctor, "crop", Crop); NODE_SET_PROTOTYPE_METHOD(ctor, "toBuffer", ToBuffer); NODE_SET_PROTOTYPE_METHOD(ctor, "toBufferAsync", ToBufferAsync); NODE_SET_PROTOTYPE_METHOD(ctor, "ellipse", Ellipse); @@ -68,6 +69,7 @@ Matrix::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(ctor, "drawAllContours", DrawAllContours); NODE_SET_PROTOTYPE_METHOD(ctor, "goodFeaturesToTrack", GoodFeaturesToTrack); NODE_SET_PROTOTYPE_METHOD(ctor, "houghLinesP", HoughLinesP); + NODE_SET_PROTOTYPE_METHOD(ctor, "houghCircles", HoughCircles); NODE_SET_PROTOTYPE_METHOD(ctor, "inRange", inRange); NODE_SET_PROTOTYPE_METHOD(ctor, "adjustROI", AdjustROI); NODE_SET_PROTOTYPE_METHOD(ctor, "locateROI", LocateROI); @@ -450,7 +452,7 @@ NAN_METHOD(Matrix::ToBuffer){ v8::Local globalObj = NanGetCurrentContext()->Global(); v8::Local bufferConstructor = v8::Local::Cast(globalObj->Get(NanNew("Buffer"))); - v8::Handle constructorArgs[3] = {buf, NanNew(vec.size()), NanNew(0)}; + v8::Handle constructorArgs[3] = {buf, NanNew((unsigned)vec.size()), NanNew(0)}; v8::Local actualBuffer = bufferConstructor->NewInstance(3, constructorArgs); NanReturnValue(actualBuffer); @@ -483,7 +485,7 @@ class AsyncToBufferWorker : public NanAsyncWorker { v8::Local globalObj = NanGetCurrentContext()->Global(); v8::Local bufferConstructor = v8::Local::Cast(globalObj->Get(NanNew("Buffer"))); - v8::Handle constructorArgs[3] = {buf, NanNew(res.size()), NanNew(0)}; + v8::Handle constructorArgs[3] = {buf, NanNew((unsigned)res.size()), NanNew(0)}; v8::Local actualBuffer = bufferConstructor->NewInstance(3, constructorArgs); @@ -1027,7 +1029,12 @@ NAN_METHOD(Matrix::BitwiseXor) { Matrix *src1 = ObjectWrap::Unwrap(args[0]->ToObject()); Matrix *src2 = ObjectWrap::Unwrap(args[1]->ToObject()); - cv::bitwise_xor(src1->mat, src2->mat, self->mat); + if(args.Length() == 3){ + Matrix *mask = ObjectWrap::Unwrap(args[2]->ToObject()); + cv::bitwise_xor(src1->mat, src2->mat, self->mat, mask->mat); + }else{ + cv::bitwise_xor(src1->mat, src2->mat, self->mat); + } NanReturnNull(); } @@ -1039,7 +1046,12 @@ NAN_METHOD(Matrix::BitwiseNot) { Matrix *dst = ObjectWrap::Unwrap(args[0]->ToObject()); - cv::bitwise_not(self->mat, dst->mat); + if(args.Length() == 2){ + Matrix *mask = ObjectWrap::Unwrap(args[1]->ToObject()); + cv::bitwise_not(self->mat, dst->mat, mask->mat); + }else{ + cv::bitwise_not(self->mat, dst->mat); + } NanReturnNull(); } @@ -1052,7 +1064,12 @@ NAN_METHOD(Matrix::BitwiseAnd) { Matrix *src1 = ObjectWrap::Unwrap(args[0]->ToObject()); Matrix *src2 = ObjectWrap::Unwrap(args[1]->ToObject()); - cv::bitwise_and(src1->mat, src2->mat, self->mat); + if(args.Length() == 3){ + Matrix *mask = ObjectWrap::Unwrap(args[2]->ToObject()); + cv::bitwise_and(src1->mat, src2->mat, self->mat, mask->mat); + }else{ + cv::bitwise_and(src1->mat, src2->mat, self->mat); + } NanReturnNull(); } @@ -1125,7 +1142,11 @@ NAN_METHOD(Matrix::FindContours) { if (args[1]->IsNumber()) chain = args[1]->IntegerValue(); } + Matrix *self = ObjectWrap::Unwrap(args.This()); Local conts_to_return= NanNew(Contour::constructor)->GetFunction()->NewInstance(); + Contour *contours = ObjectWrap::Unwrap(conts_to_return); + + cv::findContours(self->mat, contours->contours, contours->hierarchy, mode, chain); NanReturnValue(conts_to_return); @@ -1238,6 +1259,41 @@ NAN_METHOD(Matrix::HoughLinesP) { } +NAN_METHOD(Matrix::HoughCircles) { + NanScope(); + + Matrix *self = ObjectWrap::Unwrap(args.This()); + + double dp = args.Length() < 1 ? 1 : args[0]->NumberValue(); + double minDist = args.Length() < 2 ? 1 : args[1]->NumberValue(); + double higherThreshold = args.Length() < 3 ? 100 : args[2]->NumberValue(); + double accumulatorThreshold = args.Length() < 4 ? 100 : args[3]->NumberValue(); + int minRadius = args.Length() < 5 ? 0 : args[4]->Uint32Value(); + int maxRadius = args.Length() < 6 ? 0 : args[5]->Uint32Value(); + std::vector circles; + + cv::Mat gray; + + + equalizeHist(self->mat, gray); + + cv::HoughCircles(gray, circles, CV_HOUGH_GRADIENT, dp, minDist, higherThreshold, accumulatorThreshold, minRadius, maxRadius); + + v8::Local arr = NanNew(circles.size()); + + + for (unsigned int i=0; i < circles.size(); i++){ + v8::Local pt = NanNew(3); + pt->Set(0, NanNew((double) circles[i][0]));// center x + pt->Set(1, NanNew((double) circles[i][1]));// center y + pt->Set(2, NanNew((double) circles[i][2]));// radius + arr->Set(i, pt); + } + + NanReturnValue(arr); + +} + cv::Scalar setColor(Local objColor) { Local valB = objColor->Get(0); @@ -1254,7 +1310,7 @@ cv::Point setPoint(Local objPoint) { return cv::Point( objPoint->Get(0)->IntegerValue(), objPoint->Get(1)->IntegerValue() ); } -cv::Rect* setRect(Local objRect) { +cv::Rect* setRect(Local objRect, cv::Rect &result) { if(!objRect->IsArray() || !objRect->Get(0)->IsArray() || !objRect->Get(0)->IsArray() ){ printf("error"); @@ -1263,14 +1319,13 @@ cv::Rect* setRect(Local objRect) { Local point = objRect->Get(0)->ToObject(); Local size = objRect->Get(1)->ToObject(); - cv::Rect ret; - ret.x = point->Get(0)->IntegerValue(); - ret.y = point->Get(1)->IntegerValue(); - ret.width = size->Get(0)->IntegerValue(); - ret.height = size->Get(1)->IntegerValue(); + result.x = point->Get(0)->IntegerValue(); + result.y = point->Get(1)->IntegerValue(); + result.width = size->Get(0)->IntegerValue(); + result.height = size->Get(1)->IntegerValue(); - return (cv::Rect*) &ret; + return &result; } @@ -1658,10 +1713,11 @@ NAN_METHOD(Matrix::FloodFill){ Local obj = args[0]->ToObject(); + cv::Rect rect; int ret = cv::floodFill(self->mat, setPoint(obj->Get(NanNew("seedPoint"))->ToObject()) , setColor(obj->Get(NanNew("newColor"))->ToObject()) - , obj->Get(NanNew("rect"))->IsUndefined() ? 0 : setRect(obj->Get(NanNew("rect"))->ToObject()) + , obj->Get(NanNew("rect"))->IsUndefined() ? 0 : setRect(obj->Get(NanNew("rect"))->ToObject(), rect) , setColor(obj->Get(NanNew("loDiff"))->ToObject()) , setColor(obj->Get(NanNew("upDiff"))->ToObject()) , 4 ); diff --git a/src/Matrix.h b/src/Matrix.h index 535134f..f041bca 100755 --- a/src/Matrix.h +++ b/src/Matrix.h @@ -74,6 +74,7 @@ class Matrix: public node::ObjectWrap { // Feature Detection JSFUNC(GoodFeaturesToTrack) JSFUNC(HoughLinesP) + JSFUNC(HoughCircles) JSFUNC(Crop) diff --git a/src/OpenCV.cc b/src/OpenCV.cc index 4ed6c43..6ebdf01 100755 --- a/src/OpenCV.cc +++ b/src/OpenCV.cc @@ -5,48 +5,47 @@ void OpenCV::Init(Handle target) { NanScope(); - + // Version string. char out [21]; int n = sprintf(out, "%i.%i", CV_MAJOR_VERSION, CV_MINOR_VERSION); target->Set(NanNew("version"), NanNew(out, n)); NODE_SET_METHOD(target, "readImage", ReadImage); - -} +} NAN_METHOD(OpenCV::ReadImage) { NanEscapableScope(); try{ - + Local im_h = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); Matrix *img = ObjectWrap::Unwrap(im_h); - + cv::Mat mat; REQ_FUN_ARG(1, cb); - + if (args[0]->IsNumber() && args[1]->IsNumber()){ int width, height; width = args[0]->Uint32Value(); - height = args[1]->Uint32Value(); + height = args[1]->Uint32Value(); mat = *(new cv::Mat(width, height, CV_64FC1)); } else if (args[0]->IsString()) { - + std::string filename = std::string(*NanAsciiString(args[0]->ToString())); mat = cv::imread(filename); } else if (Buffer::HasInstance(args[0])){ uint8_t *buf = (uint8_t *) Buffer::Data(args[0]->ToObject()); unsigned len = Buffer::Length(args[0]->ToObject()); - + cv::Mat *mbuf = new cv::Mat(len, 1, CV_64FC1, buf); mat = cv::imdecode(*mbuf, -1); - + if (mat.empty()){ NanThrowTypeError("Error loading file"); } @@ -74,4 +73,4 @@ NAN_METHOD(OpenCV::ReadImage) { NanThrowError(err_msg); NanReturnUndefined(); } -}; +}; diff --git a/src/OpenCV.h b/src/OpenCV.h index ea1ca83..2dc32e5 100755 --- a/src/OpenCV.h +++ b/src/OpenCV.h @@ -55,4 +55,3 @@ class OpenCV: public node::ObjectWrap{ #endif - diff --git a/src/init.cc b/src/init.cc index eb8b79a..95eef1a 100755 --- a/src/init.cc +++ b/src/init.cc @@ -9,21 +9,24 @@ #include "HighGUI.h" #include "FaceRecognizer.h" #include "Constants.h" - +#include "Calib3D.h" +#include "ImgProc.h" extern "C" void init(Handle target) { NanScope(); OpenCV::Init(target); - + Point::Init(target); Matrix::Init(target); CascadeClassifierWrap::Init(target); VideoCaptureWrap::Init(target); Contour::Init(target); - TrackedObject::Init(target); + TrackedObject::Init(target); NamedWindow::Init(target); Constants::Init(target); + Calib3D::Init(target); + ImgProc::Init(target); #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4