From 4f45958ce5307a6cb0e842528b21771483a928c9 Mon Sep 17 00:00:00 2001 From: Michael Russo Date: Mon, 2 Oct 2023 23:16:15 +0000 Subject: [PATCH 1/4] Initial commit of more stereo bindings --- calib3d.cpp | 8 ++++++++ calib3d.go | 8 ++++++++ calib3d.h | 2 ++ calib3d_test.go | 4 ++++ 4 files changed, 22 insertions(+) diff --git a/calib3d.cpp b/calib3d.cpp index 8e3ce7de..458c3f98 100644 --- a/calib3d.cpp +++ b/calib3d.cpp @@ -84,3 +84,11 @@ Mat EstimateAffine2D(Point2fVector from, Point2fVector to) { Mat EstimateAffine2DWithParams(Point2fVector from, Point2fVector to, Mat inliers, int method, double ransacReprojThreshold, size_t maxIters, double confidence, size_t refineIters) { return new cv::Mat(cv::estimateAffine2D(*from, *to, *inliers, method, ransacReprojThreshold, maxIters, confidence, refineIters)); } + +void TriangulatePoints(Mat projMatr1, Mat projMatr2, Point2fVector projPoints1, Point2fVector projPoints2, Mat points4D) { + return cv::triangulatePoints(*projMatr1, *projMatr2, *projPoints1, *projPoints2, *points4D); +} + +void ConvertPointsFromHomogeneous(Mat src, Mat dst) { + return cv::convertPointsFromHomogeneous(*src, *dst); +} diff --git a/calib3d.go b/calib3d.go index 409efd39..d7519036 100644 --- a/calib3d.go +++ b/calib3d.go @@ -264,3 +264,11 @@ func EstimateAffine2D(from, to Point2fVector) Mat { func EstimateAffine2DWithParams(from Point2fVector, to Point2fVector, inliers Mat, method int, ransacReprojThreshold float64, maxIters uint, confidence float64, refineIters uint) Mat { return newMat(C.EstimateAffine2DWithParams(from.p, to.p, inliers.p, C.int(method), C.double(ransacReprojThreshold), C.size_t(maxIters), C.double(confidence), C.size_t(refineIters))) } + +func TriangulatePoints(projMatr1 Mat, projMatr2 Mat, projPoints1, projPoints2 Point2fVector, points4D *Mat) { + C.TriangulatePoints(projMatr1.Ptr(), projMatr2.Ptr(), projPoints1.p, projPoints2.p, points4D.Ptr()) +} + +func ConvertPointsFromHomogeneous(src Mat, dst *Mat) { + C.ConvertPointsFromHomogeneous(src.Ptr(), dst.Ptr()) +} diff --git a/calib3d.h b/calib3d.h index 9f2fed87..6a42423e 100644 --- a/calib3d.h +++ b/calib3d.h @@ -30,6 +30,8 @@ Mat EstimateAffinePartial2D(Point2fVector from, Point2fVector to); Mat EstimateAffinePartial2DWithParams(Point2fVector from, Point2fVector to, Mat inliers, int method, double ransacReprojThreshold, size_t maxIters, double confidence, size_t refineIters); Mat EstimateAffine2D(Point2fVector from, Point2fVector to); Mat EstimateAffine2DWithParams(Point2fVector from, Point2fVector to, Mat inliers, int method, double ransacReprojThreshold, size_t maxIters, double confidence, size_t refineIters); +void TriangulatePoints(Mat projMatr1, Mat projMatr2, Point2fVector projPoints1, Point2fVector projPoints2, Mat points4D); +void ConvertPointsFromHomogeneous(Mat src, Mat dst); #ifdef __cplusplus } #endif diff --git a/calib3d_test.go b/calib3d_test.go index a0cda2e2..93bb61d4 100644 --- a/calib3d_test.go +++ b/calib3d_test.go @@ -668,3 +668,7 @@ func TestEstimateAffine2DWithParams(t *testing.T) { t.Errorf("TestEstimateAffine2DWithParams(): unexpected rows = %v, want = %v", m.Rows(), 2) } } + +func TestTriangulatePoints(t *testing.T) { + +} From 2d28b9a0e740dc9d6c2258dbbe1579200f1f57f1 Mon Sep 17 00:00:00 2001 From: Michael Russo Date: Thu, 5 Oct 2023 17:13:00 +0000 Subject: [PATCH 2/4] Add additional signature for MinMaxLoc. --- core.cpp | 11 +++++++++++ core.go | 19 +++++++++++++++++++ core.h | 1 + 3 files changed, 31 insertions(+) diff --git a/core.cpp b/core.cpp index 64958414..fdff80a0 100644 --- a/core.cpp +++ b/core.cpp @@ -628,6 +628,17 @@ void Mat_MinMaxLoc(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc->y = cMaxLoc.y; } +void Mat_MinMaxLocWithMask(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc, Mat mask) { + cv::Point cMinLoc; + cv::Point cMaxLoc; + cv::minMaxLoc(*m, minVal, maxVal, &cMinLoc, &cMaxLoc, *mask); + + minLoc->x = cMinLoc.x; + minLoc->y = cMinLoc.y; + maxLoc->x = cMaxLoc.x; + maxLoc->y = cMaxLoc.y; +} + void Mat_MixChannels(struct Mats src, struct Mats dst, struct IntVector fromTo) { std::vector srcMats; diff --git a/core.go b/core.go index a95cdcb2..b359a4b9 100644 --- a/core.go +++ b/core.go @@ -1534,6 +1534,25 @@ func MinMaxLoc(input Mat) (minVal, maxVal float32, minLoc, maxLoc image.Point) { return float32(cMinVal), float32(cMaxVal), minLoc, maxLoc } +// MinMaxLocWithMask finds the global minimum and maximum in an array with a mask used to select a sub-array. +// +// For further details, please see: +// https://docs.opencv.org/trunk/d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707 +// +func MinMaxLocWithMask(input Mat, mask Mat) (minVal, maxVal float32, minLoc, maxLoc image.Point) { + var cMinVal C.double + var cMaxVal C.double + var cMinLoc C.struct_Point + var cMaxLoc C.struct_Point + + C.Mat_MinMaxLocWithMask(input.p, &cMinVal, &cMaxVal, &cMinLoc, &cMaxLoc, mask.p) + + minLoc = image.Pt(int(cMinLoc.x), int(cMinLoc.y)) + maxLoc = image.Pt(int(cMaxLoc.x), int(cMaxLoc.y)) + + return float32(cMinVal), float32(cMaxVal), minLoc, maxLoc +} + // Copies specified channels from input arrays to the specified channels of output arrays. // // For further details, please see: diff --git a/core.h b/core.h index 955c5ea1..e47a108f 100644 --- a/core.h +++ b/core.h @@ -405,6 +405,7 @@ void Mat_Merge(struct Mats mats, Mat dst); void Mat_Min(Mat src1, Mat src2, Mat dst); void Mat_MinMaxIdx(Mat m, double* minVal, double* maxVal, int* minIdx, int* maxIdx); void Mat_MinMaxLoc(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc); +void Mat_MinMaxLocWithMask(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc, Mat mask); void Mat_MixChannels(struct Mats src, struct Mats dst, struct IntVector fromTo); void Mat_MulSpectrums(Mat a, Mat b, Mat c, int flags); void Mat_Multiply(Mat src1, Mat src2, Mat dst); From 3685c03a97947cce89d4532d0b281c4da51844e0 Mon Sep 17 00:00:00 2001 From: Michael Russo Date: Mon, 16 Oct 2023 17:43:05 +0000 Subject: [PATCH 3/4] Add func comments and update readme. --- ROADMAP.md | 4 ++-- calib3d.go | 11 ++++++++++- calib3d_test.go | 4 ---- core.go | 5 ++--- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index b11e4b85..3a216094 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -133,7 +133,7 @@ Your pull requests will be greatly appreciated! - [ ] [checkChessboard](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - [ ] [composeRT](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - [ ] [computeCorrespondEpilines](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - - [ ] [convertPointsFromHomogeneous](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) + - [X] [convertPointsFromHomogeneous](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - [ ] [convertPointsHomogeneous](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - [ ] [convertPointsToHomogeneous](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - [ ] [correctMatches](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) @@ -175,7 +175,7 @@ Your pull requests will be greatly appreciated! - [ ] [stereoCalibrate](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - [ ] [stereoRectify](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - [ ] [stereoRectifyUncalibrated](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - - [ ] [triangulatePoints](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) + - [X] [triangulatePoints](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - [ ] [validateDisparity](https://docs.opencv.org/master/d9/d0c/group__calib3d.html) - [ ] **Fisheye - WORK STARTED** The following functions still need implementation: diff --git a/calib3d.go b/calib3d.go index d7519036..18988ae1 100644 --- a/calib3d.go +++ b/calib3d.go @@ -265,10 +265,19 @@ func EstimateAffine2DWithParams(from Point2fVector, to Point2fVector, inliers Ma return newMat(C.EstimateAffine2DWithParams(from.p, to.p, inliers.p, C.int(method), C.double(ransacReprojThreshold), C.size_t(maxIters), C.double(confidence), C.size_t(refineIters))) } -func TriangulatePoints(projMatr1 Mat, projMatr2 Mat, projPoints1, projPoints2 Point2fVector, points4D *Mat) { +// TriangulatePoints reconstructs 3-dimensional points (in homogeneous coordinates) +// by using their observations with a stereo camera. +// +// For further details, please see: +// https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#gad3fc9a0c82b08df034234979960b778c +func TriangulatePoints(projMatr1, projMatr2 Mat, projPoints1, projPoints2 Point2fVector, points4D *Mat) { C.TriangulatePoints(projMatr1.Ptr(), projMatr2.Ptr(), projPoints1.p, projPoints2.p, points4D.Ptr()) } +// ConvertPointsFromHomogeneous converts points from homogeneous to Euclidean space. +// +// For further details, please see: +// https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#gac42edda3a3a0f717979589fcd6ac0035 func ConvertPointsFromHomogeneous(src Mat, dst *Mat) { C.ConvertPointsFromHomogeneous(src.Ptr(), dst.Ptr()) } diff --git a/calib3d_test.go b/calib3d_test.go index 93bb61d4..a0cda2e2 100644 --- a/calib3d_test.go +++ b/calib3d_test.go @@ -668,7 +668,3 @@ func TestEstimateAffine2DWithParams(t *testing.T) { t.Errorf("TestEstimateAffine2DWithParams(): unexpected rows = %v, want = %v", m.Rows(), 2) } } - -func TestTriangulatePoints(t *testing.T) { - -} diff --git a/core.go b/core.go index b359a4b9..88f3e721 100644 --- a/core.go +++ b/core.go @@ -1537,9 +1537,8 @@ func MinMaxLoc(input Mat) (minVal, maxVal float32, minLoc, maxLoc image.Point) { // MinMaxLocWithMask finds the global minimum and maximum in an array with a mask used to select a sub-array. // // For further details, please see: -// https://docs.opencv.org/trunk/d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707 -// -func MinMaxLocWithMask(input Mat, mask Mat) (minVal, maxVal float32, minLoc, maxLoc image.Point) { +// https://docs.opencv.org/4.x/d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707 +func MinMaxLocWithMask(input, mask Mat) (minVal, maxVal float32, minLoc, maxLoc image.Point) { var cMinVal C.double var cMaxVal C.double var cMinLoc C.struct_Point From e16a1f3c2be2f13c1af71b1ea04e92bb38643198 Mon Sep 17 00:00:00 2001 From: Michael Russo Date: Tue, 17 Oct 2023 17:13:21 +0000 Subject: [PATCH 4/4] Add smoke tests. --- calib3d_test.go | 45 +++++++++++++++++++++++++++++++++++++++++ core_test.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/calib3d_test.go b/calib3d_test.go index a0cda2e2..2aa48ebf 100644 --- a/calib3d_test.go +++ b/calib3d_test.go @@ -668,3 +668,48 @@ func TestEstimateAffine2DWithParams(t *testing.T) { t.Errorf("TestEstimateAffine2DWithParams(): unexpected rows = %v, want = %v", m.Rows(), 2) } } + +func TestTriangulatePoints(t *testing.T) { + projMat1, projMat2 := NewMatWithSize(3, 4, MatTypeCV64F), NewMatWithSize(3, 4, MatTypeCV64F) + defer projMat1.Close() + defer projMat2.Close() + projPoints1, projPoints2 := NewPoint2fVectorFromPoints([]Point2f{{Y: 1.0, X: 2.0}}), NewPoint2fVectorFromPoints([]Point2f{{Y: 3.0, X: 4.0}}) + defer projPoints1.Close() + defer projPoints2.Close() + homogeneous := NewMat() + defer homogeneous.Close() + TriangulatePoints(projMat1, projMat2, projPoints1, projPoints2, &homogeneous) + if homogeneous.Empty() { + t.Errorf("TriangulatePoints(): output homogeneous mat is empty") + } +} + +func TestConvertPointsFromHomogeneous(t *testing.T) { + homogeneous := NewMatWithSize(1, 4, MatTypeCV32F) + defer homogeneous.Close() + homogeneous.SetFloatAt(0, 0, 1) + homogeneous.SetFloatAt(0, 1, 2) + homogeneous.SetFloatAt(0, 2, 4) + homogeneous.SetFloatAt(0, 3, 2) + euclidean := NewMat() + defer euclidean.Close() + ConvertPointsFromHomogeneous(homogeneous, &euclidean) + if euclidean.Empty() { + t.Fatalf("ConvertPointsFromHomogeneous(): output euclidean mat is empty") + } + ptsVector := NewPoint3fVectorFromMat(euclidean) + defer ptsVector.Close() + pts := ptsVector.ToPoints() + if len(pts) != 1 { + t.Fatalf("ConvertPointsFromHomogeneous(): euclidean mat converted to points is empty") + } + if pts[0].X != 0.5 { + t.Errorf("ConvertPointsFromHomogeneous(): euclidean X - got %v, want %v", pts[0].X, 0.5) + } + if pts[0].Y != 1 { + t.Errorf("ConvertPointsFromHomogeneous(): euclidean Y - got %v, want %v", pts[0].Y, 1) + } + if pts[0].Z != 2 { + t.Errorf("ConvertPointsFromHomogeneous(): euclidean Z - got %v, want %v", pts[0].Z, 2) + } +} diff --git a/core_test.go b/core_test.go index 4d03ed85..4f4fcca4 100644 --- a/core_test.go +++ b/core_test.go @@ -3142,3 +3142,57 @@ func TestSetThreadNumber(t *testing.T) { SetNumThreads(original) } + +func TestMinMaxLoc(t *testing.T) { + input := NewMatWithSize(2, 2, MatTypeCV32F) + defer input.Close() + input.SetFloatAt(0, 0, 1) + input.SetFloatAt(0, 1, 2) + input.SetFloatAt(1, 0, 3) + input.SetFloatAt(1, 1, 4) + minVal, maxVal, minLoc, maxLoc := MinMaxLoc(input) + + wantMinVal, wantMaxValue := float32(1.0), float32(4.0) + if minVal != wantMinVal { + t.Errorf("minVal got: %v, want %v", minVal, wantMinVal) + } + if maxVal != wantMaxValue { + t.Errorf("maxVal got: %v, want %v", maxVal, wantMaxValue) + } + wantMinLoc, wantMaxLoc := image.Point{Y: 0, X: 0}, image.Point{Y: 1, X: 1} + if minLoc != wantMinLoc { + t.Errorf("minLoc got: %v, want %v", minLoc, wantMinLoc) + } + if maxLoc != wantMaxLoc { + t.Errorf("maxLoc got: %v, want %v", maxLoc, wantMaxLoc) + } +} + +func TestMinMaxLocWithMask(t *testing.T) { + input := NewMatWithSize(2, 2, MatTypeCV32F) + defer input.Close() + input.SetFloatAt(0, 0, 1) + input.SetFloatAt(0, 1, 2) + input.SetFloatAt(1, 0, 3) + input.SetFloatAt(1, 1, 4) + mask := NewMatWithSize(2, 2, MatTypeCV8U) + defer mask.Close() + mask.SetUCharAt(1, 0, 1) + mask.SetUCharAt(1, 1, 1) + minVal, maxVal, minLoc, maxLoc := MinMaxLocWithMask(input, mask) + + wantMinVal, wantMaxValue := float32(3.0), float32(4.0) + if minVal != wantMinVal { + t.Errorf("minVal got: %v, want %v", minVal, wantMinVal) + } + if maxVal != wantMaxValue { + t.Errorf("maxVal got: %v, want %v", maxVal, wantMaxValue) + } + wantMinLoc, wantMaxLoc := image.Point{Y: 1, X: 0}, image.Point{Y: 1, X: 1} + if minLoc != wantMinLoc { + t.Errorf("minLoc got: %v, want %v", minLoc, wantMinLoc) + } + if maxLoc != wantMaxLoc { + t.Errorf("maxLoc got: %v, want %v", maxLoc, wantMaxLoc) + } +}