From 9706924d3850ddba1db02560ab9ef6f1297b0857 Mon Sep 17 00:00:00 2001 From: higher Date: Mon, 26 Feb 2024 18:24:04 +0000 Subject: [PATCH 1/4] Changing return type of minIdx and maxIdx in MinMaxIdx to be a []int rather than int. The return arrays will have input.dims elements. Adding test to confirm function is working with nD case. --- core.cpp | 11 ++++++++++- core.go | 19 ++++++++++++++----- core_test.go | 42 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/core.cpp b/core.cpp index 7c9f141f..bf5da747 100644 --- a/core.cpp +++ b/core.cpp @@ -654,7 +654,16 @@ void Mat_Min(Mat src1, Mat src2, Mat dst) { } void Mat_MinMaxIdx(Mat m, double* minVal, double* maxVal, int* minIdx, int* maxIdx) { - cv::minMaxIdx(*m, minVal, maxVal, minIdx, maxIdx); + int cMinIdx[m->dims]; + int cMaxIdx[m->dims]; + cv::minMaxIdx(*m, minVal, maxVal, cMinIdx, cMaxIdx); + + for(unsigned int a = 0; a < sizeof(cMinIdx)/sizeof(cMinIdx[0]); a++) { + minIdx[a] = cMinIdx[a]; + } + for(unsigned int a = 0; a < sizeof(cMaxIdx)/sizeof(cMaxIdx[0]); a++) { + maxIdx[a] = cMaxIdx[a]; + } } void Mat_MinMaxLoc(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc) { diff --git a/core.go b/core.go index 70ebd302..5edf77ac 100644 --- a/core.go +++ b/core.go @@ -1512,15 +1512,24 @@ func Min(src1, src2 Mat, dst *Mat) { // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga7622c466c628a75d9ed008b42250a73f -func MinMaxIdx(input Mat) (minVal, maxVal float32, minIdx, maxIdx int) { +func MinMaxIdx(input Mat) (minVal, maxVal float32, minIdx, maxIdx []int) { var cMinVal C.double var cMaxVal C.double - var cMinIdx C.int - var cMaxIdx C.int - C.Mat_MinMaxIdx(input.p, &cMinVal, &cMaxVal, &cMinIdx, &cMaxIdx) + dims := len(input.Size()) + cMinIdx := make([]C.int, dims) + cMaxIdx := make([]C.int, dims) - return float32(cMinVal), float32(cMaxVal), int(minIdx), int(maxIdx) + C.Mat_MinMaxIdx(input.p, &cMinVal, &cMaxVal, &cMinIdx[0], &cMaxIdx[0]) + + for i := 0; i < dims; i++ { + minIdx = append(minIdx, int(cMinIdx[i])) + } + for i := 0; i < dims; i++ { + maxIdx = append(maxIdx, int(cMaxIdx[i])) + } + + return float32(cMinVal), float32(cMaxVal), minIdx, maxIdx } // MinMaxLoc finds the global minimum and maximum in an array. diff --git a/core_test.go b/core_test.go index cce5d3ff..f02af32c 100644 --- a/core_test.go +++ b/core_test.go @@ -2569,12 +2569,12 @@ func TestMatMin(t *testing.T) { } func TestMatMinMaxIdx(t *testing.T) { - src := NewMatWithSize(10, 10, MatTypeCV32F) + src := NewMatWithSize(10, 10, MatTypeCV32FC1) defer src.Close() src.SetFloatAt(3, 3, 17) src.SetFloatAt(4, 4, 16) - minVal, maxVal, _, _ := MinMaxIdx(src) + minVal, maxVal, minIdx, maxIdx := MinMaxIdx(src) if minVal != 0 { t.Error("TestMatMinMaxIdx minVal should be 0.") @@ -2582,6 +2582,44 @@ func TestMatMinMaxIdx(t *testing.T) { if maxVal != 17 { t.Errorf("TestMatMinMaxIdx maxVal should be 17, was %f", maxVal) } + if minIdx[0] != 0 || minIdx[1] != 0 { + t.Errorf("TestMatMinMaxIdx minIdx should be [0,0], was [%d,%d]", minIdx[0], minIdx[1]) + } + if maxIdx[0] != 3 || maxIdx[1] != 3 { + t.Errorf("TestMatMinMaxIdx maxIdx should be [3,3], was [%d,%d]", maxIdx[0], maxIdx[1]) + } +} + +func TestMatMinMaxIdx3d(t *testing.T) { + src := NewMatWithSizes([]int{3,3,3}, MatTypeCV32FC1) + defer src.Close() + src.SetFloatAt3(2, 1, 2, 2) + + minVal, maxVal, minIdx, maxIdx := MinMaxIdx(src) + if len(minIdx) != 3 { + t.Errorf("minIdx should have 3 dimensions. %d found", len(minIdx)) + } + + if len(maxIdx) != 3 { + t.Errorf("maxIdx should have 3 dimensions. %d found", len(maxIdx)) + } + + if minVal != 0 { + t.Errorf("TestMatMinMaxIdx3d minVal expected 0, got %f", minVal) + } + if maxVal != 2 { + t.Errorf("TestMatMinMaxIdx3d maxVal should be 2, was %f", maxVal) + } + + + if maxIdx[0] != 2 || maxIdx[1] != 1 || maxIdx[2] != 2 { + t.Errorf("TestMatMinMaxIdx3d maxIdx should be [2,1,2], was [%d,%d,%d]", maxIdx[0], maxIdx[1], maxIdx[2]) + } + + if minIdx[0] != 0 || minIdx[1] != 0 || minIdx[2] != 0 { + t.Errorf("TestMatMinMaxIdx3d minIdx should be [0,0,0], was [%d,%d,%d]", minIdx[0], minIdx[1], minIdx[2]) + } + } func TestMixChannels(t *testing.T) { From ee2e938913b46dfbe2e5d56e3266398750da00de Mon Sep 17 00:00:00 2001 From: higher Date: Tue, 27 Feb 2024 15:50:01 +0000 Subject: [PATCH 2/4] Changing return type of minIdx and maxIdx in MinMaxIdx to be a []int rather than int. The return arrays will have input.dims elements. Adding test to confirm function is working with nD case. --- core.cpp | 11 ++++++++++- core.go | 19 ++++++++++++++----- core_test.go | 41 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/core.cpp b/core.cpp index 7c9f141f..bf5da747 100644 --- a/core.cpp +++ b/core.cpp @@ -654,7 +654,16 @@ void Mat_Min(Mat src1, Mat src2, Mat dst) { } void Mat_MinMaxIdx(Mat m, double* minVal, double* maxVal, int* minIdx, int* maxIdx) { - cv::minMaxIdx(*m, minVal, maxVal, minIdx, maxIdx); + int cMinIdx[m->dims]; + int cMaxIdx[m->dims]; + cv::minMaxIdx(*m, minVal, maxVal, cMinIdx, cMaxIdx); + + for(unsigned int a = 0; a < sizeof(cMinIdx)/sizeof(cMinIdx[0]); a++) { + minIdx[a] = cMinIdx[a]; + } + for(unsigned int a = 0; a < sizeof(cMaxIdx)/sizeof(cMaxIdx[0]); a++) { + maxIdx[a] = cMaxIdx[a]; + } } void Mat_MinMaxLoc(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc) { diff --git a/core.go b/core.go index 70ebd302..5edf77ac 100644 --- a/core.go +++ b/core.go @@ -1512,15 +1512,24 @@ func Min(src1, src2 Mat, dst *Mat) { // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga7622c466c628a75d9ed008b42250a73f -func MinMaxIdx(input Mat) (minVal, maxVal float32, minIdx, maxIdx int) { +func MinMaxIdx(input Mat) (minVal, maxVal float32, minIdx, maxIdx []int) { var cMinVal C.double var cMaxVal C.double - var cMinIdx C.int - var cMaxIdx C.int - C.Mat_MinMaxIdx(input.p, &cMinVal, &cMaxVal, &cMinIdx, &cMaxIdx) + dims := len(input.Size()) + cMinIdx := make([]C.int, dims) + cMaxIdx := make([]C.int, dims) - return float32(cMinVal), float32(cMaxVal), int(minIdx), int(maxIdx) + C.Mat_MinMaxIdx(input.p, &cMinVal, &cMaxVal, &cMinIdx[0], &cMaxIdx[0]) + + for i := 0; i < dims; i++ { + minIdx = append(minIdx, int(cMinIdx[i])) + } + for i := 0; i < dims; i++ { + maxIdx = append(maxIdx, int(cMaxIdx[i])) + } + + return float32(cMinVal), float32(cMaxVal), minIdx, maxIdx } // MinMaxLoc finds the global minimum and maximum in an array. diff --git a/core_test.go b/core_test.go index cce5d3ff..9a4deeae 100644 --- a/core_test.go +++ b/core_test.go @@ -2569,12 +2569,12 @@ func TestMatMin(t *testing.T) { } func TestMatMinMaxIdx(t *testing.T) { - src := NewMatWithSize(10, 10, MatTypeCV32F) + src := NewMatWithSize(10, 10, MatTypeCV32FC1) defer src.Close() src.SetFloatAt(3, 3, 17) src.SetFloatAt(4, 4, 16) - minVal, maxVal, _, _ := MinMaxIdx(src) + minVal, maxVal, minIdx, maxIdx := MinMaxIdx(src) if minVal != 0 { t.Error("TestMatMinMaxIdx minVal should be 0.") @@ -2582,6 +2582,43 @@ func TestMatMinMaxIdx(t *testing.T) { if maxVal != 17 { t.Errorf("TestMatMinMaxIdx maxVal should be 17, was %f", maxVal) } + if minIdx[0] != 0 || minIdx[1] != 0 { + t.Errorf("TestMatMinMaxIdx minIdx should be [0,0], was [%d,%d]", minIdx[0], minIdx[1]) + } + if maxIdx[0] != 3 || maxIdx[1] != 3 { + t.Errorf("TestMatMinMaxIdx maxIdx should be [3,3], was [%d,%d]", maxIdx[0], maxIdx[1]) + } +} + +func TestMatMinMaxIdx3d(t *testing.T) { + src := NewMatWithSizes([]int{3,3,3}, MatTypeCV32FC1) + defer src.Close() + src.SetFloatAt3(2, 1, 2, 2) + + minVal, maxVal, minIdx, maxIdx := MinMaxIdx(src) + if len(minIdx) != 3 { + t.Errorf("minIdx should have 3 dimensions. %d found", len(minIdx)) + } + + if len(maxIdx) != 3 { + t.Errorf("maxIdx should have 3 dimensions. %d found", len(maxIdx)) + } + + if minVal != 0 { + t.Errorf("TestMatMinMaxIdx3d minVal expected 0, got %f", minVal) + } + if maxVal != 2 { + t.Errorf("TestMatMinMaxIdx3d maxVal should be 2, was %f", maxVal) + } + + + if maxIdx[0] != 2 || maxIdx[1] != 1 || maxIdx[2] != 2 { + t.Errorf("TestMatMinMaxIdx3d maxIdx should be [2,1,2], was [%d,%d,%d]", maxIdx[0], maxIdx[1], maxIdx[2]) + } + + if minIdx[0] != 0 || minIdx[1] != 0 || minIdx[2] != 0 { + t.Errorf("TestMatMinMaxIdx3d minIdx should be [0,0,0], was [%d,%d,%d]", minIdx[0], minIdx[1], minIdx[2]) + } } func TestMixChannels(t *testing.T) { From c74a7160791e81a47c5829fd64bc619b34b95f3a Mon Sep 17 00:00:00 2001 From: higher Date: Wed, 28 Feb 2024 16:11:07 +0000 Subject: [PATCH 3/4] Adjusting TestMatMinMaxIdx3d function to create a zero'd 3d matrix. Errors were occuring before because of a non-zero'd mat being created. Malloc'ing space for min and max index in MinMaxIdx rather than making array and passing in address to [0] index. --- core.cpp | 2 -- core.go | 27 ++++++++++++++++++++------- core_test.go | 10 +++++++++- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/core.cpp b/core.cpp index bf5da747..8a2e287a 100644 --- a/core.cpp +++ b/core.cpp @@ -660,8 +660,6 @@ void Mat_MinMaxIdx(Mat m, double* minVal, double* maxVal, int* minIdx, int* maxI for(unsigned int a = 0; a < sizeof(cMinIdx)/sizeof(cMinIdx[0]); a++) { minIdx[a] = cMinIdx[a]; - } - for(unsigned int a = 0; a < sizeof(cMaxIdx)/sizeof(cMaxIdx[0]); a++) { maxIdx[a] = cMaxIdx[a]; } } diff --git a/core.go b/core.go index 5edf77ac..d87a4121 100644 --- a/core.go +++ b/core.go @@ -1517,18 +1517,31 @@ func MinMaxIdx(input Mat) (minVal, maxVal float32, minIdx, maxIdx []int) { var cMaxVal C.double dims := len(input.Size()) - cMinIdx := make([]C.int, dims) - cMaxIdx := make([]C.int, dims) + cMinIdx := (*C.int)(C.malloc(C.size_t(C.sizeof_int * dims))) + cMaxIdx := (*C.int)(C.malloc(C.size_t(C.sizeof_int * dims))) + defer C.free(unsafe.Pointer(cMinIdx)) + defer C.free(unsafe.Pointer(cMaxIdx)) - C.Mat_MinMaxIdx(input.p, &cMinVal, &cMaxVal, &cMinIdx[0], &cMaxIdx[0]) + C.Mat_MinMaxIdx(input.p, &cMinVal, &cMaxVal, cMinIdx, cMaxIdx) - for i := 0; i < dims; i++ { - minIdx = append(minIdx, int(cMinIdx[i])) + h := &reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(cMinIdx)), + Len: dims, + Cap: dims, } - for i := 0; i < dims; i++ { - maxIdx = append(maxIdx, int(cMaxIdx[i])) + minIndex := *(*[]C.int)(unsafe.Pointer(h)) + + h = &reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(cMaxIdx)), + Len: dims, + Cap: dims, } + maxIndex := *(*[]C.int)(unsafe.Pointer(h)) + for i := 0; i < dims; i++ { + minIdx = append(minIdx, int(minIndex[i])) + maxIdx = append(maxIdx, int(maxIndex[i])) + } return float32(cMinVal), float32(cMaxVal), minIdx, maxIdx } diff --git a/core_test.go b/core_test.go index 9a4deeae..40611a25 100644 --- a/core_test.go +++ b/core_test.go @@ -2575,7 +2575,6 @@ func TestMatMinMaxIdx(t *testing.T) { src.SetFloatAt(4, 4, 16) minVal, maxVal, minIdx, maxIdx := MinMaxIdx(src) - if minVal != 0 { t.Error("TestMatMinMaxIdx minVal should be 0.") } @@ -2593,6 +2592,15 @@ func TestMatMinMaxIdx(t *testing.T) { func TestMatMinMaxIdx3d(t *testing.T) { src := NewMatWithSizes([]int{3,3,3}, MatTypeCV32FC1) defer src.Close() + + for x := 0; x < 3; x++ { + for y := 0; y < 3; y++ { + for z := 0; z < 3; z++ { + src.SetFloatAt3(x, y, z, 0) + } + } + } + src.SetFloatAt3(2, 1, 2, 2) minVal, maxVal, minIdx, maxIdx := MinMaxIdx(src) From 96d98692ed2997b28ab3b0cadf2f44ce075e77d6 Mon Sep 17 00:00:00 2001 From: higher Date: Sun, 3 Mar 2024 17:31:40 +0000 Subject: [PATCH 4/4] Removing specification of channels from matrix creation in test. --- core_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core_test.go b/core_test.go index 40611a25..d4b70252 100644 --- a/core_test.go +++ b/core_test.go @@ -2569,7 +2569,7 @@ func TestMatMin(t *testing.T) { } func TestMatMinMaxIdx(t *testing.T) { - src := NewMatWithSize(10, 10, MatTypeCV32FC1) + src := NewMatWithSize(10, 10, MatTypeCV32F) defer src.Close() src.SetFloatAt(3, 3, 17) src.SetFloatAt(4, 4, 16) @@ -2590,7 +2590,7 @@ func TestMatMinMaxIdx(t *testing.T) { } func TestMatMinMaxIdx3d(t *testing.T) { - src := NewMatWithSizes([]int{3,3,3}, MatTypeCV32FC1) + src := NewMatWithSizes([]int{3,3,3}, MatTypeCV32F) defer src.Close() for x := 0; x < 3; x++ {