From b4a04b112a4c3c128d592a42b98e3a84e2a00885 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Thu, 5 Feb 2015 12:19:44 -0500 Subject: [PATCH 01/13] Added stereo calibrate --- src/Calib3D.cc | 180 ++++++++++++++++++++++++++++++++++++++++++++++++- src/Calib3D.h | 2 + 2 files changed, 181 insertions(+), 1 deletion(-) diff --git a/src/Calib3D.cc b/src/Calib3D.cc index f223fef..62b56ca 100644 --- a/src/Calib3D.cc +++ b/src/Calib3D.cc @@ -12,6 +12,7 @@ void Calib3D::Init(Handle target) NODE_SET_METHOD(obj, "calibrateCamera", CalibrateCamera); NODE_SET_METHOD(obj, "solvePnP", SolvePnP); NODE_SET_METHOD(obj, "getOptimalNewCameraMatrix", GetOptimalNewCameraMatrix); + NODE_SET_METHOD(obj, "stereoCalibrate", StereoCalibrate); target->Set(NanNew("calib3d"), obj); } @@ -314,7 +315,7 @@ NAN_METHOD(Calib3D::SolvePnP) } } -// cv::solvePnP +// cv::getOptimalNewCameraMAtrix NAN_METHOD(Calib3D::GetOptimalNewCameraMatrix) { NanEscapableScope(); @@ -373,3 +374,180 @@ NAN_METHOD(Calib3D::GetOptimalNewCameraMatrix) NanReturnUndefined(); } } + +// cv::stereoCalibrate +NAN_METHOD(Calib3D::StereoCalibrate) +{ + 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 points1, another array of arrays =( + std::vector > imagePoints1; + 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())); + } + + imagePoints1.push_back(points); + } + } else { + JSTHROW_TYPE("Must pass array of object points for each frame") + } + + // Arg 2, the image points2, another array of arrays =( + std::vector > imagePoints2; + if(args[2]->IsArray()) { + Local imagePointsArray = Local::Cast(args[2]); + + 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())); + } + + imagePoints2.push_back(points); + } + } else { + JSTHROW_TYPE("Must pass array of object points for each frame") + } + + // Arg 3 is the image size (follows the PYTHON api not the C++ api since all following arguments are optional or outputs) + cv::Size imageSize; + if (args[3]->IsArray()) { + Local v8sz = args[3]->ToObject(); + + imageSize = cv::Size(v8sz->Get(1)->IntegerValue(), v8sz->Get(0)->IntegerValue()); + } else { + JSTHROW_TYPE("Must pass original image size"); + } + + // Arg 4,5,6,7 is the camera matrix and distortion coefficients (optional but must pass all 4 or none) + cv::Mat k1, d1, k2, d2; + if(args.Length() >= 8) + { + Matrix* mk1 = ObjectWrap::Unwrap(args[4]->ToObject()); + Matrix* md1 = ObjectWrap::Unwrap(args[5]->ToObject()); + Matrix* mk2 = ObjectWrap::Unwrap(args[6]->ToObject()); + Matrix* md2 = ObjectWrap::Unwrap(args[7]->ToObject()); + + k1 = mk1->mat; + d1 = md1->mat; + + k2 = mk2->mat; + d2 = md2->mat; + } + + // Last argument is flags, skipping for now + + // Output mats + cv::Mat R, t, E, F; + + // Do the stereo calibration + cv::stereoCalibrate(objectPoints, imagePoints1, imagePoints2, k1, d1, k2, d2, imageSize, R, t, E, F); + + // make the return value + Local ret = NanNew(); + + // Make the output arguments + + // k1 + Local K1MatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *K1Matrix = ObjectWrap::Unwrap(K1MatrixWrap); + K1Matrix->mat = k1; + + // d1 + Local d1MatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *d1Matrix = ObjectWrap::Unwrap(d1MatrixWrap); + d1Matrix->mat = d1; + + // k2 + Local K2MatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *K2Matrix = ObjectWrap::Unwrap(K2MatrixWrap); + K2Matrix->mat = k2; + + // d2 + Local d2MatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *d2Matrix = ObjectWrap::Unwrap(d2MatrixWrap); + d2Matrix->mat = d2; + + // R + Local RMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *RMatrix = ObjectWrap::Unwrap(RMatrixWrap); + RMatrix->mat = R; + + // t + Local tMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *tMatrix = ObjectWrap::Unwrap(tMatrixWrap); + tMatrix->mat = t; + + // E + Local EMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *EMatrix = ObjectWrap::Unwrap(EMatrixWrap); + EMatrix->mat = E; + + // F + Local FMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *FMatrix = ObjectWrap::Unwrap(FMatrixWrap); + FMatrix->mat = F; + + // Add to return object + ret->Set(NanNew("K1"), K1MatrixWrap); + ret->Set(NanNew("distortion1"), d1MatrixWrap); + ret->Set(NanNew("K2"), K2MatrixWrap); + ret->Set(NanNew("distortion2"), d2MatrixWrap); + ret->Set(NanNew("R"), RMatrixWrap); + ret->Set(NanNew("t"), tMatrixWrap); + ret->Set(NanNew("E"), EMatrixWrap); + ret->Set(NanNew("F"), FMatrixWrap); + + // Return + NanReturnValue(ret); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} diff --git a/src/Calib3D.h b/src/Calib3D.h index ab5669e..1f18894 100644 --- a/src/Calib3D.h +++ b/src/Calib3D.h @@ -18,6 +18,8 @@ public: static NAN_METHOD(SolvePnP); static NAN_METHOD(GetOptimalNewCameraMatrix); + + static NAN_METHOD(StereoCalibrate); }; #endif From eb4808cebda660394ab0b2eb2bb4ccb663b2e1e6 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Thu, 5 Feb 2015 14:09:52 -0500 Subject: [PATCH 02/13] Factored out commonly repeated code into functions --- src/Calib3D.cc | 417 ++++++++++++++++++------------------------------- 1 file changed, 156 insertions(+), 261 deletions(-) diff --git a/src/Calib3D.cc b/src/Calib3D.cc index 62b56ca..127cc67 100644 --- a/src/Calib3D.cc +++ b/src/Calib3D.cc @@ -1,6 +1,123 @@ #include "Calib3D.h" #include "Matrix.h" +inline Local matrixFromMat(cv::Mat &input) +{ + Local matrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *matrix = ObjectWrap::Unwrap(matrixWrap); + matrix->mat = input; + + return matrixWrap; +} + +inline cv::Mat matFromMatrix(Handle matrix) +{ + Matrix* m = ObjectWrap::Unwrap(matrix->ToObject()); + return m->mat; +} + +inline cv::Size sizeFromArray(Handle jsArray) +{ + cv::Size patternSize; + + if (jsArray->IsArray()) + { + Local v8sz = jsArray->ToObject(); + + patternSize = cv::Size(v8sz->Get(0)->IntegerValue(), v8sz->Get(1)->IntegerValue()); + } + else + { + JSTHROW_TYPE("Size is not a valid array"); + } + + return patternSize; +} + +inline std::vector points2fFromArray(Handle array) +{ + std::vector points; + if(array->IsArray()) + { + Local pointsArray = Local::Cast(array->ToObject()); + + for(unsigned int i = 0; i < pointsArray->Length(); i++) + { + Local pt = pointsArray->Get(i)->ToObject(); + points.push_back(cv::Point2f(pt->Get(NanNew("x"))->ToNumber()->Value(), + pt->Get(NanNew("y"))->ToNumber()->Value())); + } + } + else + { + JSTHROW_TYPE("Points not a valid array"); + } + + return points; +} + +inline std::vector points3fFromArray(Handle array) +{ + std::vector points; + if(array->IsArray()) { + Local pointsArray = Local::Cast(array->ToObject()); + + for(unsigned int i = 0; i < pointsArray->Length(); i++) + { + Local pt = pointsArray->Get(i)->ToObject(); + points.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") + } + + return points; +} + +inline std::vector > points2fFromArrayOfArrays(Handle array) +{ + std::vector > points; + if(array->IsArray()) + { + Local pointsArray = Local::Cast(array->ToObject()); + + for(unsigned int i = 0; i < pointsArray->Length(); i++) + { + points.push_back(points2fFromArray(pointsArray->Get(i))); + } + } + else + { + JSTHROW_TYPE("Must pass array of object points for each frame") + } + + return points; +} + +inline std::vector > points3fFromArrayOfArrays(Handle array) +{ + std::vector > points; + if(array->IsArray()) + { + Local pointsArray = Local::Cast(array->ToObject()); + + for(unsigned int i = 0; i < pointsArray->Length(); i++) + { + points.push_back(points3fFromArray(pointsArray->Get(i))); + } + } + else + { + JSTHROW_TYPE("Must pass array of object points for each frame") + } + + return points; +} + void Calib3D::Init(Handle target) { Persistent inner; @@ -26,18 +143,10 @@ NAN_METHOD(Calib3D::FindChessboardCorners) // Get the arguments from javascript // Arg 0 is the image - Matrix* m = ObjectWrap::Unwrap(args[0]->ToObject()); - cv::Mat mat = m->mat; + cv::Mat mat = matFromMatrix(args[0]); // 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"); - } + cv::Size patternSize = sizeFromArray(args[1]); // Arg 2 would normally be the flags, ignoring this for now and using the default flags @@ -81,33 +190,13 @@ NAN_METHOD(Calib3D::DrawChessboardCorners) // Get the arguments // Arg 0 is the image - Matrix* m = ObjectWrap::Unwrap(args[0]->ToObject()); - cv::Mat mat = m->mat; + cv::Mat mat = matFromMatrix(args[0]); // 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"); - } + cv::Size patternSize = sizeFromArray(args[1]); // 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"); - } + std::vector corners = points2fFromArray(args[2]); // Arg 3, pattern found boolean bool patternWasFound = args[3]->ToBoolean()->Value(); @@ -134,61 +223,13 @@ NAN_METHOD(Calib3D::CalibrateCamera) // 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]); + std::vector > objectPoints = points3fFromArrayOfArrays(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 1, the image points, another array of arrays + std::vector > imagePoints = points2fFromArrayOfArrays(args[1]); // 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"); - } + cv::Size imageSize = sizeFromArray(args[2]); // Arg 3, 4, input guesses for the camrea matrix and distortion coefficients, skipping for now cv::Mat K, dist; @@ -207,17 +248,11 @@ NAN_METHOD(Calib3D::CalibrateCamera) ret->Set(NanNew("reprojectionError"), NanNew(error)); // K - Local KMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *KMatrix = ObjectWrap::Unwrap(KMatrixWrap); - KMatrix->mat = K; - + Local KMatrixWrap = matrixFromMat(K); ret->Set(NanNew("K"), KMatrixWrap); // dist - Local distMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *distMatrix = ObjectWrap::Unwrap(distMatrixWrap); - distMatrix->mat = dist; - + Local distMatrixWrap = matrixFromMat(dist); ret->Set(NanNew("distortion"), distMatrixWrap); // Per frame R and t, skiping for now @@ -241,43 +276,16 @@ NAN_METHOD(Calib3D::SolvePnP) // 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") - } + std::vector objectPoints = points3fFromArray(args[0]); // 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") - } + std::vector imagePoints = points2fFromArray(args[1]); // Arg 2, the camera matrix - Matrix* kWrap = ObjectWrap::Unwrap(args[2]->ToObject()); - cv::Mat K = kWrap->mat; + cv::Mat K = matFromMatrix(args[2]); // Arg 3, the distortion coefficients - Matrix* distWrap = ObjectWrap::Unwrap(args[3]->ToObject()); - cv::Mat dist = distWrap->mat; + cv::Mat dist = matFromMatrix(args[3]); // Arg 4, use extrinsic guess, skipped for now @@ -292,17 +300,11 @@ NAN_METHOD(Calib3D::SolvePnP) Local ret = NanNew(); // rvec - Local rMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *rMatrix = ObjectWrap::Unwrap(rMatrixWrap); - rMatrix->mat = rvec; - + Local rMatrixWrap = matrixFromMat(rvec); ret->Set(NanNew("rvec"), rMatrixWrap); // tvec - Local tMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *tMatrix = ObjectWrap::Unwrap(tMatrixWrap); - tMatrix->mat = tvec; - + Local tMatrixWrap = matrixFromMat(tvec); ret->Set(NanNew("tvec"), tMatrixWrap); // Return @@ -324,35 +326,19 @@ NAN_METHOD(Calib3D::GetOptimalNewCameraMatrix) // Get the arguments // Arg 0 is the original camera matrix - Matrix* m0 = ObjectWrap::Unwrap(args[0]->ToObject()); - cv::Mat Kin = m0->mat; + cv::Mat Kin = matFromMatrix(args[0]); // Arg 1 is the distortion coefficients - Matrix* m1 = ObjectWrap::Unwrap(args[1]->ToObject()); - cv::Mat dist = m1->mat; + cv::Mat dist = matFromMatrix(args[1]); // 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"); - } + cv::Size imageSize = sizeFromArray(args[2]); // 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"); - } + cv::Size newImageSize = sizeFromArray(args[4]); // Arg 5, valid ROI, skip for now // Arg 6, center principal point, skip for now @@ -361,9 +347,7 @@ NAN_METHOD(Calib3D::GetOptimalNewCameraMatrix) 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; + Local KMatrixWrap = matrixFromMat(Kout); // Return the new K matrix NanReturnValue(KMatrixWrap); @@ -384,99 +368,26 @@ NAN_METHOD(Calib3D::StereoCalibrate) // 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]); + std::vector > objectPoints = points3fFromArrayOfArrays(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 points1, another array of arrays =( - std::vector > imagePoints1; - 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())); - } - - imagePoints1.push_back(points); - } - } else { - JSTHROW_TYPE("Must pass array of object points for each frame") - } + // Arg 1, the image points1, another array of arrays + std::vector > imagePoints1 = points2fFromArrayOfArrays(args[1]); // Arg 2, the image points2, another array of arrays =( - std::vector > imagePoints2; - if(args[2]->IsArray()) { - Local imagePointsArray = Local::Cast(args[2]); - - 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())); - } - - imagePoints2.push_back(points); - } - } else { - JSTHROW_TYPE("Must pass array of object points for each frame") - } + std::vector > imagePoints2 = points2fFromArrayOfArrays(args[2]); // Arg 3 is the image size (follows the PYTHON api not the C++ api since all following arguments are optional or outputs) - cv::Size imageSize; - if (args[3]->IsArray()) { - Local v8sz = args[3]->ToObject(); - - imageSize = cv::Size(v8sz->Get(1)->IntegerValue(), v8sz->Get(0)->IntegerValue()); - } else { - JSTHROW_TYPE("Must pass original image size"); - } + cv::Size imageSize = sizeFromArray(args[3]); // Arg 4,5,6,7 is the camera matrix and distortion coefficients (optional but must pass all 4 or none) cv::Mat k1, d1, k2, d2; if(args.Length() >= 8) { - Matrix* mk1 = ObjectWrap::Unwrap(args[4]->ToObject()); - Matrix* md1 = ObjectWrap::Unwrap(args[5]->ToObject()); - Matrix* mk2 = ObjectWrap::Unwrap(args[6]->ToObject()); - Matrix* md2 = ObjectWrap::Unwrap(args[7]->ToObject()); + k1 = matFromMatrix(args[4]); + d1 = matFromMatrix(args[5]); - k1 = mk1->mat; - d1 = md1->mat; - - k2 = mk2->mat; - d2 = md2->mat; + k2 = matFromMatrix(args[6]); + d2 = matFromMatrix(args[7]); } // Last argument is flags, skipping for now @@ -493,44 +404,28 @@ NAN_METHOD(Calib3D::StereoCalibrate) // Make the output arguments // k1 - Local K1MatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *K1Matrix = ObjectWrap::Unwrap(K1MatrixWrap); - K1Matrix->mat = k1; + Local K1MatrixWrap = matrixFromMat(k1); // d1 - Local d1MatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *d1Matrix = ObjectWrap::Unwrap(d1MatrixWrap); - d1Matrix->mat = d1; + Local d1MatrixWrap = matrixFromMat(d1); // k2 - Local K2MatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *K2Matrix = ObjectWrap::Unwrap(K2MatrixWrap); - K2Matrix->mat = k2; + Local K2MatrixWrap = matrixFromMat(k2); // d2 - Local d2MatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *d2Matrix = ObjectWrap::Unwrap(d2MatrixWrap); - d2Matrix->mat = d2; + Local d2MatrixWrap = matrixFromMat(d2); // R - Local RMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *RMatrix = ObjectWrap::Unwrap(RMatrixWrap); - RMatrix->mat = R; + Local RMatrixWrap = matrixFromMat(R); // t - Local tMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *tMatrix = ObjectWrap::Unwrap(tMatrixWrap); - tMatrix->mat = t; + Local tMatrixWrap = matrixFromMat(t); // E - Local EMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *EMatrix = ObjectWrap::Unwrap(EMatrixWrap); - EMatrix->mat = E; + Local EMatrixWrap = matrixFromMat(E); // F - Local FMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); - Matrix *FMatrix = ObjectWrap::Unwrap(FMatrixWrap); - FMatrix->mat = F; + Local FMatrixWrap = matrixFromMat(F); // Add to return object ret->Set(NanNew("K1"), K1MatrixWrap); From 31eab0e8c6733056a04f6b36f15f61b930bcbae1 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Thu, 5 Feb 2015 14:19:46 -0500 Subject: [PATCH 03/13] Added stereoRectify --- src/Calib3D.cc | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/Calib3D.h | 2 ++ 2 files changed, 63 insertions(+) diff --git a/src/Calib3D.cc b/src/Calib3D.cc index 127cc67..67d9927 100644 --- a/src/Calib3D.cc +++ b/src/Calib3D.cc @@ -130,6 +130,7 @@ void Calib3D::Init(Handle target) NODE_SET_METHOD(obj, "solvePnP", SolvePnP); NODE_SET_METHOD(obj, "getOptimalNewCameraMatrix", GetOptimalNewCameraMatrix); NODE_SET_METHOD(obj, "stereoCalibrate", StereoCalibrate); + NODE_SET_METHOD(obj, "stereoRectify", StereoRectify); target->Set(NanNew("calib3d"), obj); } @@ -446,3 +447,63 @@ NAN_METHOD(Calib3D::StereoCalibrate) NanReturnUndefined(); } } + +// cv::stereoCalibrate +NAN_METHOD(Calib3D::StereoRectify) +{ + NanEscapableScope(); + + try { + // Get the arguments + + // Arg0, the first camera matrix + cv::Mat K1 = matFromMatrix(args[0]); + + // Arg1, the first distortion coefficients + cv::Mat d1 = matFromMatrix(args[1]); + + // Arg3, the second camera matrix + cv::Mat K2 = matFromMatrix(args[3]); + + // Arg4, the second distortion coefficients + cv::Mat d2 = matFromMatrix(args[4]); + + // Arg5, the image size + cv::Size imageSize = sizeFromArray(args[5]); + + // arg6, the intercamera rotation matrix + cv::Mat R = matFromMatrix(args[6]); + + // Arg7, the intercamera translation vector + cv::Mat t = matFromMatrix(args[7]); + + // Arg8, flags, skipping for now + + // Arg9, freescaling paremeter, skipping for now + + // Arg10, new image size, skipping for now to fix at original image size + + // Make output matrics + cv::Mat R1, R2, P1, P2, Q; + + // Do the stereo rectification + cv::stereoRectify(K1, d1, K2, d2, imageSize, R, t, R1, R2, P1, P2, Q); + + // Make the return object + Local ret = NanNew(); + + ret->Set(NanNew("R1"), matrixFromMat(R1)); + ret->Set(NanNew("R2"), matrixFromMat(R2)); + ret->Set(NanNew("P1"), matrixFromMat(P1)); + ret->Set(NanNew("P2"), matrixFromMat(P2)); + ret->Set(NanNew("Q"), matrixFromMat(Q)); + + // Return the recification parameters + NanReturnValue(ret); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} diff --git a/src/Calib3D.h b/src/Calib3D.h index 1f18894..cf1d190 100644 --- a/src/Calib3D.h +++ b/src/Calib3D.h @@ -20,6 +20,8 @@ public: static NAN_METHOD(GetOptimalNewCameraMatrix); static NAN_METHOD(StereoCalibrate); + + static NAN_METHOD(StereoRectify); }; #endif From 51631b307ea0ce997909853f0c98abb630a991b1 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Thu, 5 Feb 2015 14:31:37 -0500 Subject: [PATCH 04/13] Added computeCorrespondEpilines --- src/Calib3D.cc | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- src/Calib3D.h | 2 ++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/Calib3D.cc b/src/Calib3D.cc index 67d9927..8d6a43f 100644 --- a/src/Calib3D.cc +++ b/src/Calib3D.cc @@ -131,6 +131,7 @@ void Calib3D::Init(Handle target) NODE_SET_METHOD(obj, "getOptimalNewCameraMatrix", GetOptimalNewCameraMatrix); NODE_SET_METHOD(obj, "stereoCalibrate", StereoCalibrate); NODE_SET_METHOD(obj, "stereoRectify", StereoRectify); + NODE_SET_METHOD(obj, "computeCorrespondEpilines", ComputeCorrespondEpilines); target->Set(NanNew("calib3d"), obj); } @@ -448,7 +449,7 @@ NAN_METHOD(Calib3D::StereoCalibrate) } } -// cv::stereoCalibrate +// cv::stereoRectify NAN_METHOD(Calib3D::StereoRectify) { NanEscapableScope(); @@ -500,7 +501,50 @@ NAN_METHOD(Calib3D::StereoRectify) // Return the recification parameters NanReturnValue(ret); - + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} + +// cv::stereoRectify +NAN_METHOD(Calib3D::StereoRectify) +{ + NanEscapableScope(); + + try { + // Get the arguments + + // Arg0, the image points + std::vector points = points2fFromArray(args[0]); + + // Arg1, the image index (1 or 2) + int whichImage = int(args[1]->ToNumber()->Value()); + + // Arg2, the fundamental matrix + cv::Mat F = matFromMatrix(args[2]); + + // compute the lines + std::vector lines; + cv::computeCorrespondEpilines(points, whichImage, F, lines); + + // Convert the lines to an array of objects (ax + by + c = 0) + Local linesArray = NanNew(lines.size()); + for(unsigned int i = 0; i < lines.size(); i++) + { + Local line_data = NanNew(); + line_data->Set(NanNew("a"), NanNew(corners[i][0])); + line_data->Set(NanNew("b"), NanNew(corners[i][1])); + line_data->Set(NanNew("c"), NanNew(corners[i][2])); + + linesArray->Set(NanNew(i), line_data); + } + + // Return the lines + NanReturnValue(linesArray); + } catch (cv::Exception &e) { const char *err_msg = e.what(); NanThrowError(err_msg); diff --git a/src/Calib3D.h b/src/Calib3D.h index cf1d190..9d5afbd 100644 --- a/src/Calib3D.h +++ b/src/Calib3D.h @@ -22,6 +22,8 @@ public: static NAN_METHOD(StereoCalibrate); static NAN_METHOD(StereoRectify); + + static NAN_METHOD(ComputeCorrespondEpilines); }; #endif From 17afbceabdda3d09f799907003d856b74fb21cba Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Thu, 5 Feb 2015 14:32:51 -0500 Subject: [PATCH 05/13] Fixed bug in function name --- src/Calib3D.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Calib3D.cc b/src/Calib3D.cc index 8d6a43f..e73a62a 100644 --- a/src/Calib3D.cc +++ b/src/Calib3D.cc @@ -509,8 +509,8 @@ NAN_METHOD(Calib3D::StereoRectify) } } -// cv::stereoRectify -NAN_METHOD(Calib3D::StereoRectify) +// cv::computeCorrespondEpilines +NAN_METHOD(Calib3D::ComputeCorrespondEpilines) { NanEscapableScope(); From 92a9369d69c6ad8262357cb1f5e451f1f0254f11 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Thu, 5 Feb 2015 14:37:36 -0500 Subject: [PATCH 06/13] Added reprojectImageTo3D --- src/Calib3D.cc | 36 ++++++++++++++++++++++++++++++++++++ src/Calib3D.h | 2 ++ 2 files changed, 38 insertions(+) diff --git a/src/Calib3D.cc b/src/Calib3D.cc index e73a62a..ebc4f80 100644 --- a/src/Calib3D.cc +++ b/src/Calib3D.cc @@ -132,6 +132,7 @@ void Calib3D::Init(Handle target) NODE_SET_METHOD(obj, "stereoCalibrate", StereoCalibrate); NODE_SET_METHOD(obj, "stereoRectify", StereoRectify); NODE_SET_METHOD(obj, "computeCorrespondEpilines", ComputeCorrespondEpilines); + NODE_SET_METHOD(obj, "reprojectImageTo3D", ReprojectImageTo3D); target->Set(NanNew("calib3d"), obj); } @@ -551,3 +552,38 @@ NAN_METHOD(Calib3D::ComputeCorrespondEpilines) NanReturnUndefined(); } } + +// cv::reprojectImageTo3D +NAN_METHOD(Calib3D::ReprojectImageTo3D) +{ + NanEscapableScope(); + + try { + // Get the arguments + + // Arg0, the disparity image + cv::Mat disparity = matFromMatrix(args[0]); + + // Arg1, the depth-to-disparity transformation Q + cv::Mat Q = matFromMatrix(args[1]); + + // Arg 2, handle missing values, skipped for now + + // Arg3, output bit depth, skipped for now + + // Compute the depth image + cv::Mat depthImage; + cv::reprojectImageTo3D(disparity, depthImage, Q); + + // Wrap the depth image + Local depthImageMatrix = matrixFromMat(depthImage); + + NanReturnValue(depthImageMatrix); + + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } +} diff --git a/src/Calib3D.h b/src/Calib3D.h index 9d5afbd..4f06505 100644 --- a/src/Calib3D.h +++ b/src/Calib3D.h @@ -24,6 +24,8 @@ public: static NAN_METHOD(StereoRectify); static NAN_METHOD(ComputeCorrespondEpilines); + + static NAN_METHOD(ReprojectImageTo3D); }; #endif From b1d77ab64ce80774570509dbedf58445bd334237 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Thu, 5 Feb 2015 14:39:22 -0500 Subject: [PATCH 07/13] Fixed naming error in computeCorrespondEpilines --- src/Calib3D.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Calib3D.cc b/src/Calib3D.cc index ebc4f80..4d1b12c 100644 --- a/src/Calib3D.cc +++ b/src/Calib3D.cc @@ -536,9 +536,9 @@ NAN_METHOD(Calib3D::ComputeCorrespondEpilines) for(unsigned int i = 0; i < lines.size(); i++) { Local line_data = NanNew(); - line_data->Set(NanNew("a"), NanNew(corners[i][0])); - line_data->Set(NanNew("b"), NanNew(corners[i][1])); - line_data->Set(NanNew("c"), NanNew(corners[i][2])); + line_data->Set(NanNew("a"), NanNew(lines[i][0])); + line_data->Set(NanNew("b"), NanNew(lines[i][1])); + line_data->Set(NanNew("c"), NanNew(lines[i][2])); linesArray->Set(NanNew(i), line_data); } From e7b3cab803e9f3a12057999e9af45b8a7dc78727 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Fri, 6 Feb 2015 10:27:20 -0500 Subject: [PATCH 08/13] Added Stereo block matching algorithm --- binding.gyp | 1 + src/Stereo.cc | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/Stereo.h | 19 ++++++++++ src/init.cc | 2 ++ 4 files changed, 121 insertions(+) create mode 100644 src/Stereo.cc create mode 100644 src/Stereo.h diff --git a/binding.gyp b/binding.gyp index 449c088..846b6b0 100755 --- a/binding.gyp +++ b/binding.gyp @@ -16,6 +16,7 @@ , "src/Constants.cc" , "src/Calib3D.cc" , "src/ImgProc.cc" + , "src/Stereo.cc" ] , 'libraries': [ ' StereoBM::constructor; + +void +StereoBM::Init(Handle target) { + NanScope(); + + Local ctor = NanNew(StereoBM::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("StereoBM")); + + NODE_SET_PROTOTYPE_METHOD(ctor, "compute", Compute); + + ctor->Set(NanNew("BASIC_PRESET"), NanNew((int)cv::StereoBM::BASIC_PRESET)); + ctor->Set(NanNew("FISH_EYE_PRESET"), NanNew((int)cv::StereoBM::FISH_EYE_PRESET)); + ctor->Set(NanNew("NARROW_PRESET"), NanNew((int)cv::StereoBM::NARROW_PRESET)); + + target->Set(NanNew("StereoBM"), ctor->GetFunction()); +} + +NAN_METHOD(StereoBM::New) { + NanScope(); + + if (args.This()->InternalFieldCount() == 0) + NanThrowTypeError("Cannot instantiate without new"); + + StereoBM *stereo; + + if (args.Length() == 0) + { + stereo = new StereoBM(); + } + else if (args.Length() == 1) + { + stereo = new StereoBM(args[0]->IntegerValue()); // preset + } + else if (args.Length() == 2) + { + stereo = new StereoBM(args[0]->IntegerValue(), args[1]->IntegerValue()); // preset, disparity search range + } + else + { + stereo = new StereoBM(args[0]->IntegerValue(), args[1]->IntegerValue(), args[2]->IntegerValue()); // preset, disparity search range, sum of absolute differences window size + } + + stereo->Wrap(args.Holder()); + NanReturnValue(args.Holder()); +} + +StereoBM::StereoBM(int preset, int ndisparities, int SADWindowSize) + : ObjectWrap(), stereo(preset, ndisparities, SADWindowSize) +{ + +} + +// TODO make this async +NAN_METHOD(StereoBM::Compute) +{ + SETUP_FUNCTION(StereoBM) + + try { + // Get the arguments + + // Arg 0, the 'left' image + Matrix* m0 = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::Mat left = m0->mat; + + // Arg 1, the 'right' image + Matrix* m1 = ObjectWrap::Unwrap(args[1]->ToObject()); + cv::Mat right = m1->mat; + + // Optional 3rd arg, the disparty depth + int type = CV_16S; + if(args.Length() > 2) + { + type = args[2]->IntegerValue(); + } + + // Compute stereo using the block matching algorithm + cv::Mat disparity; + self->stereo(left, right, disparity, type); + + // Wrap the returned disparity map + Local disparityWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *disp = ObjectWrap::Unwrap(disparityWrap); + disp->mat = disparity; + + NanReturnValue(disparityWrap); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } + +}; diff --git a/src/Stereo.h b/src/Stereo.h new file mode 100644 index 0000000..7149066 --- /dev/null +++ b/src/Stereo.h @@ -0,0 +1,19 @@ +#ifndef __NODE_STEREO_H +#define __NODE_STEREO_H + +#include "OpenCV.h" + +class StereoBM: public node::ObjectWrap { +public: + cv::StereoBM stereo; + + static Persistent constructor; + static void Init(Handle target); + static NAN_METHOD(New); + + StereoBM(int preset = cv::StereoBM::BASIC_PRESET, int ndisparities = 0, int SADWindowSize=21); + + JSFUNC(Compute); +}; + +#endif diff --git a/src/init.cc b/src/init.cc index 95eef1a..8cf0cec 100755 --- a/src/init.cc +++ b/src/init.cc @@ -11,6 +11,7 @@ #include "Constants.h" #include "Calib3D.h" #include "ImgProc.h" +#include "Stereo.h" extern "C" void init(Handle target) { @@ -27,6 +28,7 @@ init(Handle target) { Constants::Init(target); Calib3D::Init(target); ImgProc::Init(target); + StereoBM::Init(target); #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4 From 487ac8a13705d2877cbe1c2659d8399621d39eec Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Fri, 6 Feb 2015 11:06:58 -0500 Subject: [PATCH 09/13] Added semi-global block matching stereo --- src/Stereo.cc | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/Stereo.h | 24 +++++++++ src/init.cc | 1 + 3 files changed, 159 insertions(+) diff --git a/src/Stereo.cc b/src/Stereo.cc index 4cab060..454fb6a 100644 --- a/src/Stereo.cc +++ b/src/Stereo.cc @@ -1,6 +1,8 @@ #include "Stereo.h" #include "Matrix.h" +// Block matching + v8::Persistent StereoBM::constructor; void @@ -97,3 +99,135 @@ NAN_METHOD(StereoBM::Compute) } }; + +// Semi-Global Block matching + +v8::Persistent StereoSGBM::constructor; + +void +StereoSGBM::Init(Handle target) { + NanScope(); + + Local ctor = NanNew(StereoSGBM::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("StereoSGBM")); + + NODE_SET_PROTOTYPE_METHOD(ctor, "compute", Compute); + + target->Set(NanNew("StereoSGBM"), ctor->GetFunction()); +} + +NAN_METHOD(StereoSGBM::New) { + NanScope(); + + if (args.This()->InternalFieldCount() == 0) + NanThrowTypeError("Cannot instantiate without new"); + + StereoSGBM *stereo; + + if (args.Length() == 0) + { + stereo = new StereoSGBM(); + } + else + { + // If passing arguments, must pass the first 3 at least + if (args.Length() >= 3) + { + switch (args.Length()) + { + case 3: + stereo = new StereoSGBM(args[0]->IntegerValue(), args[1]->IntegerValue(), args[2]->IntegerValue()); + break; + + case 4: + stereo = new StereoSGBM(args[0]->IntegerValue(), args[1]->IntegerValue(), args[2]->IntegerValue(), args[3]->IntegerValue()); + break; + + case 5: + stereo = new StereoSGBM(args[0]->IntegerValue(), args[1]->IntegerValue(), args[2]->IntegerValue(), args[3]->IntegerValue(), args[4]->IntegerValue()); + break; + + case 6: + stereo = new StereoSGBM(args[0]->IntegerValue(), args[1]->IntegerValue(), args[2]->IntegerValue(), args[3]->IntegerValue(), args[4]->IntegerValue(), args[5]->IntegerValue()); + break; + + case 7: + stereo = new StereoSGBM(args[0]->IntegerValue(), args[1]->IntegerValue(), args[2]->IntegerValue(), args[3]->IntegerValue(), args[4]->IntegerValue(), args[5]->IntegerValue(), args[6]->IntegerValue()); + break; + + case 8: + stereo = new StereoSGBM(args[0]->IntegerValue(), args[1]->IntegerValue(), args[2]->IntegerValue(), args[3]->IntegerValue(), args[4]->IntegerValue(), args[5]->IntegerValue(), args[6]->IntegerValue(), args[7]->IntegerValue()); + break; + + case 9: + stereo = new StereoSGBM(args[0]->IntegerValue(), args[1]->IntegerValue(), args[2]->IntegerValue(), args[3]->IntegerValue(), args[4]->IntegerValue(), args[5]->IntegerValue(), args[6]->IntegerValue(), args[7]->IntegerValue(), args[8]->IntegerValue()); + break; + + case 10: + stereo = new StereoSGBM(args[0]->IntegerValue(), args[1]->IntegerValue(), args[2]->IntegerValue(), args[3]->IntegerValue(), args[4]->IntegerValue(), args[5]->IntegerValue(), args[6]->IntegerValue(), args[7]->IntegerValue(), args[8]->IntegerValue(), args[9]->IntegerValue()); + break; + + default: + stereo = new StereoSGBM(args[0]->IntegerValue(), args[1]->IntegerValue(), args[2]->IntegerValue(), args[3]->IntegerValue(), args[4]->IntegerValue(), args[5]->IntegerValue(), args[6]->IntegerValue(), args[7]->IntegerValue(), args[8]->IntegerValue(), args[9]->IntegerValue(), args[10]->ToBoolean()->Value()); + break; + } + } + else + { + NanThrowError("If overriding default settings, must pass minDisparity, numDisparities, and SADWindowSize"); + NanReturnUndefined(); + } + } + + stereo->Wrap(args.Holder()); + NanReturnValue(args.Holder()); +} + +StereoSGBM::StereoSGBM() + : ObjectWrap(), stereo() +{ + +} + +StereoSGBM::StereoSGBM(int minDisparity, int ndisparities, int SADWindowSize, int p1, int p2, int disp12MaxDiff, int preFilterCap, int uniquenessRatio, int speckleWindowSize, int speckleRange, bool fullDP) + : ObjectWrap(), stereo(minDisparity, ndisparities, SADWindowSize, p1, p2, disp12MaxDiff, preFilterCap, uniquenessRatio, speckleWindowSize, speckleRange, fullDP) +{ + +} + +// TODO make this async +NAN_METHOD(StereoSGBM::Compute) +{ + SETUP_FUNCTION(StereoSGBM) + + try { + // Get the arguments + + // Arg 0, the 'left' image + Matrix* m0 = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::Mat left = m0->mat; + + // Arg 1, the 'right' image + Matrix* m1 = ObjectWrap::Unwrap(args[1]->ToObject()); + cv::Mat right = m1->mat; + + // Compute stereo using the block matching algorithm + cv::Mat disparity; + self->stereo(left, right, disparity); + + // Wrap the returned disparity map + Local disparityWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *disp = ObjectWrap::Unwrap(disparityWrap); + disp->mat = disparity; + + NanReturnValue(disparityWrap); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } + +}; diff --git a/src/Stereo.h b/src/Stereo.h index 7149066..c144989 100644 --- a/src/Stereo.h +++ b/src/Stereo.h @@ -16,4 +16,28 @@ public: JSFUNC(Compute); }; +class StereoSGBM: public node::ObjectWrap { +public: + cv::StereoSGBM stereo; + + static Persistent constructor; + static void Init(Handle target); + static NAN_METHOD(New); + + StereoSGBM(); + StereoSGBM(int minDisparity, + int ndisparities, + int SADWindowSize, + int p1 = 0, + int p2 = 0, + int disp12MaxDiff = 0, + int preFilterCap = 0, + int uniquenessRatio = 0, + int speckleWindowSize = 0, + int speckleRange = 0, + bool fullDP = false); + + JSFUNC(Compute); +}; + #endif diff --git a/src/init.cc b/src/init.cc index 8cf0cec..af7c474 100755 --- a/src/init.cc +++ b/src/init.cc @@ -29,6 +29,7 @@ init(Handle target) { Calib3D::Init(target); ImgProc::Init(target); StereoBM::Init(target); + StereoSGBM::Init(target); #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4 From d0400ec5aed2f29398551da797737727ac3ddda4 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Mon, 9 Feb 2015 18:19:00 -0500 Subject: [PATCH 10/13] Added graph-cut stereo algorithm --- src/Stereo.cc | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/Stereo.h | 15 +++++++++ 2 files changed, 105 insertions(+) diff --git a/src/Stereo.cc b/src/Stereo.cc index 454fb6a..54da7af 100644 --- a/src/Stereo.cc +++ b/src/Stereo.cc @@ -1,5 +1,6 @@ #include "Stereo.h" #include "Matrix.h" +#include // Block matching @@ -231,3 +232,92 @@ NAN_METHOD(StereoSGBM::Compute) } }; + +// Graph cut + +v8::Persistent StereoGC::constructor; + +void +StereoGC::Init(Handle target) { + NanScope(); + + Local ctor = NanNew(StereoGC::New); + NanAssignPersistent(constructor, ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(NanNew("StereoGC")); + + NODE_SET_PROTOTYPE_METHOD(ctor, "compute", Compute); + + target->Set(NanNew("StereoGC"), ctor->GetFunction()); +} + +NAN_METHOD(StereoGC::New) { + NanScope(); + + if (args.This()->InternalFieldCount() == 0) + NanThrowTypeError("Cannot instantiate without new"); + + StereoGC *stereo; + + if (args.Length() == 0) + { + stereo = new StereoGC(); + } + else if (args.Length() == 1) + { + stereo = new StereoGC(args[0]->IntegerValue()); // numberOfDisparities + } + else + { + stereo = new StereoGC(args[0]->IntegerValue(), args[1]->IntegerValue()); // max iterations + } + + stereo->Wrap(args.Holder()); + NanReturnValue(args.Holder()); +} + +StereoGC::StereoGC(int numberOfDisparities, int maxIters) +: ObjectWrap() +{ + stereo = cvCreateStereoGCState(numberOfDisparities, maxIters); +} + +// TODO make this async +NAN_METHOD(StereoGC::Compute) +{ + SETUP_FUNCTION(StereoGC) + + try { + // Get the arguments + + // Arg 0, the 'left' image + Matrix* m0 = ObjectWrap::Unwrap(args[0]->ToObject()); + cv::Mat left = m0->mat; + + // Arg 1, the 'right' image + Matrix* m1 = ObjectWrap::Unwrap(args[1]->ToObject()); + cv::Mat right = m1->mat; + + // Compute stereo using the block matching algorithm + CvMat left_leg = left, right_leg = right; + CvMat *disp_left = cvCreateMat(left.rows, left.cols, CV_16S), *disp_right = cvCreateMat(right.rows, right.cols, CV_16S); + cvFindStereoCorrespondenceGC(&left_leg, &right_leg, disp_left, disp_right, self->stereo, 0); + + cv::Mat disp16 = disp_left; + cv::Mat disparity(disp16.rows, disp16.cols, CV_8U); + disp16.convertTo(disparity, CV_8U, -16); + + // Wrap the returned disparity map + Local disparityWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance(); + Matrix *disp = ObjectWrap::Unwrap(disparityWrap); + disp->mat = disparity; + + NanReturnValue(disparityWrap); + + } catch (cv::Exception &e) { + const char *err_msg = e.what(); + NanThrowError(err_msg); + NanReturnUndefined(); + } + +}; diff --git a/src/Stereo.h b/src/Stereo.h index c144989..569a6d6 100644 --- a/src/Stereo.h +++ b/src/Stereo.h @@ -40,4 +40,19 @@ public: JSFUNC(Compute); }; +struct CvStereoGCState; + +class StereoGC: public node::ObjectWrap { +public: + CvStereoGCState *stereo; + + static Persistent constructor; + static void Init(Handle target); + static NAN_METHOD(New); + + StereoGC(int numberOfDisparities = 16, int maxIterations = 2); + + JSFUNC(Compute); +}; + #endif From bce394f7751b37987173c8772ef2b8c5d4a80d28 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Thu, 12 Feb 2015 14:17:58 -0500 Subject: [PATCH 11/13] Init StereoGC class --- src/init.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/init.cc b/src/init.cc index af7c474..a107061 100755 --- a/src/init.cc +++ b/src/init.cc @@ -30,6 +30,7 @@ init(Handle target) { ImgProc::Init(target); StereoBM::Init(target); StereoSGBM::Init(target); + StereoGC::Init(target); #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4 From f60b41ec32e3fb7e140d16ecd37ade8916b817b2 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Fri, 13 Feb 2015 12:05:58 -0500 Subject: [PATCH 12/13] Fixed naming error in reprojectImageTo3d --- src/Calib3D.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Calib3D.cc b/src/Calib3D.cc index 4d1b12c..8595e7b 100644 --- a/src/Calib3D.cc +++ b/src/Calib3D.cc @@ -132,7 +132,7 @@ void Calib3D::Init(Handle target) NODE_SET_METHOD(obj, "stereoCalibrate", StereoCalibrate); NODE_SET_METHOD(obj, "stereoRectify", StereoRectify); NODE_SET_METHOD(obj, "computeCorrespondEpilines", ComputeCorrespondEpilines); - NODE_SET_METHOD(obj, "reprojectImageTo3D", ReprojectImageTo3D); + NODE_SET_METHOD(obj, "reprojectImageTo3d", ReprojectImageTo3D); target->Set(NanNew("calib3d"), obj); } From 14fed8c12b833d34b7094d8e54b660f2022ff750 Mon Sep 17 00:00:00 2001 From: Max Ehrlich Date: Fri, 13 Feb 2015 12:11:18 -0500 Subject: [PATCH 13/13] Fixed a bug causing argments to be read incorrectly in stereoRectify --- src/Calib3D.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Calib3D.cc b/src/Calib3D.cc index 8595e7b..600a788 100644 --- a/src/Calib3D.cc +++ b/src/Calib3D.cc @@ -464,20 +464,20 @@ NAN_METHOD(Calib3D::StereoRectify) // Arg1, the first distortion coefficients cv::Mat d1 = matFromMatrix(args[1]); - // Arg3, the second camera matrix - cv::Mat K2 = matFromMatrix(args[3]); + // Arg2, the second camera matrix + cv::Mat K2 = matFromMatrix(args[2]); - // Arg4, the second distortion coefficients - cv::Mat d2 = matFromMatrix(args[4]); + // Arg3, the second distortion coefficients + cv::Mat d2 = matFromMatrix(args[3]); - // Arg5, the image size - cv::Size imageSize = sizeFromArray(args[5]); + // Arg4, the image size + cv::Size imageSize = sizeFromArray(args[4]); - // arg6, the intercamera rotation matrix - cv::Mat R = matFromMatrix(args[6]); + // arg5, the intercamera rotation matrix + cv::Mat R = matFromMatrix(args[5]); - // Arg7, the intercamera translation vector - cv::Mat t = matFromMatrix(args[7]); + // Arg6, the intercamera translation vector + cv::Mat t = matFromMatrix(args[6]); // Arg8, flags, skipping for now