From 235510786b47f5fe7638a0f39b004942c9ae9172 Mon Sep 17 00:00:00 2001 From: Marc Weydert Date: Mon, 23 Jan 2023 14:56:25 +0100 Subject: [PATCH 1/3] Wrap reduceArgMin and reduceArgMax (cherry picked from commit 01f9e24339e4f20665934526bc6285e43106af8a) --- src/OpenCvSharp/Cv2/Cv2_core.cs | 50 +++++++++++++++++ .../NativeMethods/core/NativeMethods_core.cs | 6 +++ src/OpenCvSharpExtern/core.h | 14 +++++ test/OpenCvSharp.Tests/core/CoreTest.cs | 54 +++++++++++++++++++ 4 files changed, 124 insertions(+) diff --git a/src/OpenCvSharp/Cv2/Cv2_core.cs b/src/OpenCvSharp/Cv2/Cv2_core.cs index b4be71eaef..d1616b16ac 100644 --- a/src/OpenCvSharp/Cv2/Cv2_core.cs +++ b/src/OpenCvSharp/Cv2/Cv2_core.cs @@ -715,6 +715,56 @@ public static void Normalize(InputArray src, InputOutputArray dst, double alpha GC.KeepAlive(mask); } + /// + /// Finds indices of max elements along provided axis + /// + /// Input single-channel array + /// Output array of type CV_32SC1 with the same dimensionality as src, + /// except for axis being reduced - it should be set to 1. + /// Axis to reduce along + /// Whether to get the index of first or last occurrence of max + public static void ReduceArgMax(InputArray src, OutputArray dst, int axis, bool lastIndex = false) + { + if (src == null) + throw new ArgumentNullException(nameof(src)); + if (dst == null) + throw new ArgumentNullException(nameof(dst)); + src.ThrowIfDisposed(); + dst.ThrowIfNotReady(); + + NativeMethods.HandleException( + NativeMethods.core_reduceArgMax(src.CvPtr, dst.CvPtr, axis, lastIndex)); + + dst.Fix(); + GC.KeepAlive(src); + GC.KeepAlive(dst); + } + + /// + /// Finds indices of min elements along provided axis + /// + /// Input single-channel array + /// Output array of type CV_32SC1 with the same dimensionality as src, + /// except for axis being reduced - it should be set to 1. + /// Axis to reduce along + /// Whether to get the index of first or last occurrence of min + public static void ReduceArgMin(InputArray src, OutputArray dst, int axis, bool lastIndex = false) + { + if (src == null) + throw new ArgumentNullException(nameof(src)); + if (dst == null) + throw new ArgumentNullException(nameof(dst)); + src.ThrowIfDisposed(); + dst.ThrowIfNotReady(); + + NativeMethods.HandleException( + NativeMethods.core_reduceArgMin(src.CvPtr, dst.CvPtr, axis, lastIndex)); + + dst.Fix(); + GC.KeepAlive(src); + GC.KeepAlive(dst); + } + /// /// finds global minimum and maximum array elements and returns their values and their locations /// diff --git a/src/OpenCvSharp/Internal/PInvoke/NativeMethods/core/NativeMethods_core.cs b/src/OpenCvSharp/Internal/PInvoke/NativeMethods/core/NativeMethods_core.cs index d5b3010f48..a1f9a95cd5 100644 --- a/src/OpenCvSharp/Internal/PInvoke/NativeMethods/core/NativeMethods_core.cs +++ b/src/OpenCvSharp/Internal/PInvoke/NativeMethods/core/NativeMethods_core.cs @@ -167,6 +167,12 @@ public static extern ExceptionStatus core_batchDistance(IntPtr src1, IntPtr src2 public static extern ExceptionStatus core_normalize(IntPtr src, IntPtr dst, double alpha, double beta, int normType, int dtype, IntPtr mask); + [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern ExceptionStatus core_reduceArgMax(IntPtr src, IntPtr dst, int axis, bool lastIndex); + + [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern ExceptionStatus core_reduceArgMin(IntPtr src, IntPtr dst, int axis, bool lastIndex); + [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern ExceptionStatus core_minMaxLoc1(IntPtr src, out double minVal, out double maxVal); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] diff --git a/src/OpenCvSharpExtern/core.h b/src/OpenCvSharpExtern/core.h index dcd923ef67..6323d2c1b6 100644 --- a/src/OpenCvSharpExtern/core.h +++ b/src/OpenCvSharpExtern/core.h @@ -198,6 +198,20 @@ CVAPI(ExceptionStatus) core_normalize( END_WRAP } +CVAPI(ExceptionStatus) core_reduceArgMax(cv::_InputArray* src, cv::_OutputArray* dst, int axis, bool lastIndex) +{ + BEGIN_WRAP + cv::reduceArgMax(*src, *dst, axis, lastIndex); + END_WRAP +} + +CVAPI(ExceptionStatus) core_reduceArgMin(cv::_InputArray* src, cv::_OutputArray* dst, int axis, bool lastIndex) +{ + BEGIN_WRAP + cv::reduceArgMin(*src, *dst, axis, lastIndex); + END_WRAP +} + CVAPI(ExceptionStatus) core_minMaxLoc1(cv::_InputArray* src, double* minVal, double* maxVal) { BEGIN_WRAP diff --git a/test/OpenCvSharp.Tests/core/CoreTest.cs b/test/OpenCvSharp.Tests/core/CoreTest.cs index db1e261490..ea6f63acb2 100644 --- a/test/OpenCvSharp.Tests/core/CoreTest.cs +++ b/test/OpenCvSharp.Tests/core/CoreTest.cs @@ -437,4 +437,58 @@ public void NormVecd() var norm = Cv2.Norm(vec, NormTypes.L1); Assert.Equal(3.3333, norm, 9); } + + [Fact] + public void ReduceArgMax() + { + using var src = new Mat(2, 2, MatType.CV_8UC1, new byte[] { 1, 2, 3, 4 }); + using var dst = new Mat(); + + // Axis 0 + Cv2.ReduceArgMax(src, dst, axis: 0); + + Assert.Equal(MatType.CV_32SC1, dst.Type()); + Assert.Equal(1, dst.Rows); + Assert.Equal(2, dst.Cols); + + Assert.Equal(1, dst.At(0, 0)); + Assert.Equal(1, dst.At(0, 1)); + + // Axis 1 + Cv2.ReduceArgMax(src, dst, axis: 1); + + Assert.Equal(MatType.CV_32SC1, dst.Type()); + Assert.Equal(2, dst.Rows); + Assert.Equal(1, dst.Cols); + + Assert.Equal(1, dst.At(0, 0)); + Assert.Equal(1, dst.At(1, 0)); + } + + [Fact] + public void ReduceArgMin() + { + using var src = new Mat(2, 2, MatType.CV_8UC1, new byte[] { 1, 2, 3, 4 }); + using var dst = new Mat(); + + // Axis 0 + Cv2.ReduceArgMin(src, dst, axis: 0); + + Assert.Equal(MatType.CV_32SC1, dst.Type()); + Assert.Equal(1, dst.Rows); + Assert.Equal(2, dst.Cols); + + Assert.Equal(0, dst.At(0, 0)); + Assert.Equal(0, dst.At(0, 1)); + + // Axis 1 + Cv2.ReduceArgMin(src, dst, axis: 1); + + Assert.Equal(MatType.CV_32SC1, dst.Type()); + Assert.Equal(2, dst.Rows); + Assert.Equal(1, dst.Cols); + + Assert.Equal(0, dst.At(0, 0)); + Assert.Equal(0, dst.At(1, 0)); + } } From ad757e0dce23a350aad2924433665ed3df492ffe Mon Sep 17 00:00:00 2001 From: Marc Weydert Date: Wed, 25 Jan 2023 12:57:07 +0100 Subject: [PATCH 2/3] Mark boolean P/Invoke argument with MarshalAs and adapt unit tests --- .../NativeMethods/core/NativeMethods_core.cs | 4 +- test/OpenCvSharp.Tests/core/CoreTest.cs | 38 ++++--------------- 2 files changed, 10 insertions(+), 32 deletions(-) diff --git a/src/OpenCvSharp/Internal/PInvoke/NativeMethods/core/NativeMethods_core.cs b/src/OpenCvSharp/Internal/PInvoke/NativeMethods/core/NativeMethods_core.cs index a1f9a95cd5..0b603036cd 100644 --- a/src/OpenCvSharp/Internal/PInvoke/NativeMethods/core/NativeMethods_core.cs +++ b/src/OpenCvSharp/Internal/PInvoke/NativeMethods/core/NativeMethods_core.cs @@ -168,10 +168,10 @@ public static extern ExceptionStatus core_normalize(IntPtr src, IntPtr dst, doub int normType, int dtype, IntPtr mask); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern ExceptionStatus core_reduceArgMax(IntPtr src, IntPtr dst, int axis, bool lastIndex); + public static extern ExceptionStatus core_reduceArgMax(IntPtr src, IntPtr dst, int axis, [MarshalAs(UnmanagedType.U1)] bool lastIndex); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern ExceptionStatus core_reduceArgMin(IntPtr src, IntPtr dst, int axis, bool lastIndex); + public static extern ExceptionStatus core_reduceArgMin(IntPtr src, IntPtr dst, int axis, [MarshalAs(UnmanagedType.U1)] bool lastIndex); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern ExceptionStatus core_minMaxLoc1(IntPtr src, out double minVal, out double maxVal); diff --git a/test/OpenCvSharp.Tests/core/CoreTest.cs b/test/OpenCvSharp.Tests/core/CoreTest.cs index ea6f63acb2..2b931d10b4 100644 --- a/test/OpenCvSharp.Tests/core/CoreTest.cs +++ b/test/OpenCvSharp.Tests/core/CoreTest.cs @@ -441,54 +441,32 @@ public void NormVecd() [Fact] public void ReduceArgMax() { - using var src = new Mat(2, 2, MatType.CV_8UC1, new byte[] { 1, 2, 3, 4 }); + using var src = new Mat(2, 2, MatType.CV_8UC1, new byte[] { 1, 2, 1, 4 }); using var dst = new Mat(); - // Axis 0 - Cv2.ReduceArgMax(src, dst, axis: 0); + Cv2.ReduceArgMax(src, dst, axis: 0, lastIndex: true); Assert.Equal(MatType.CV_32SC1, dst.Type()); Assert.Equal(1, dst.Rows); Assert.Equal(2, dst.Cols); - Assert.Equal(1, dst.At(0, 0)); - Assert.Equal(1, dst.At(0, 1)); - - // Axis 1 - Cv2.ReduceArgMax(src, dst, axis: 1); - - Assert.Equal(MatType.CV_32SC1, dst.Type()); - Assert.Equal(2, dst.Rows); - Assert.Equal(1, dst.Cols); - - Assert.Equal(1, dst.At(0, 0)); - Assert.Equal(1, dst.At(1, 0)); + Assert.Equal(1, dst.At(0)); // max along 1st column [1; 1], taking the last occurence + Assert.Equal(1, dst.At(1)); // max along 2nd column [2; 4] } [Fact] public void ReduceArgMin() { - using var src = new Mat(2, 2, MatType.CV_8UC1, new byte[] { 1, 2, 3, 4 }); + using var src = new Mat(2, 2, MatType.CV_8UC1, new byte[] { 2, 1, 4, 4 }); using var dst = new Mat(); - // Axis 0 - Cv2.ReduceArgMin(src, dst, axis: 0); - - Assert.Equal(MatType.CV_32SC1, dst.Type()); - Assert.Equal(1, dst.Rows); - Assert.Equal(2, dst.Cols); - - Assert.Equal(0, dst.At(0, 0)); - Assert.Equal(0, dst.At(0, 1)); - - // Axis 1 - Cv2.ReduceArgMin(src, dst, axis: 1); + Cv2.ReduceArgMin(src, dst, axis: 1, lastIndex: false); Assert.Equal(MatType.CV_32SC1, dst.Type()); Assert.Equal(2, dst.Rows); Assert.Equal(1, dst.Cols); - Assert.Equal(0, dst.At(0, 0)); - Assert.Equal(0, dst.At(1, 0)); + Assert.Equal(1, dst.At(0)); // min along 1st row [2, 1] + Assert.Equal(0, dst.At(1)); // min along 2nd row [4, 4], taking the first occurence } } From 67bc0d12b5f6c7aa5947ae745ef3ac0879ea5687 Mon Sep 17 00:00:00 2001 From: Marc Weydert Date: Thu, 26 Jan 2023 08:01:51 +0100 Subject: [PATCH 3/3] Fix unit test assertions --- test/OpenCvSharp.Tests/core/CoreTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/OpenCvSharp.Tests/core/CoreTest.cs b/test/OpenCvSharp.Tests/core/CoreTest.cs index 2b931d10b4..2aa8d9556a 100644 --- a/test/OpenCvSharp.Tests/core/CoreTest.cs +++ b/test/OpenCvSharp.Tests/core/CoreTest.cs @@ -450,8 +450,8 @@ public void ReduceArgMax() Assert.Equal(1, dst.Rows); Assert.Equal(2, dst.Cols); - Assert.Equal(1, dst.At(0)); // max along 1st column [1; 1], taking the last occurence - Assert.Equal(1, dst.At(1)); // max along 2nd column [2; 4] + Assert.Equal(1, dst.At(0, 0)); // max along 1st column [1; 1], taking the last occurence + Assert.Equal(1, dst.At(0, 1)); // max along 2nd column [2; 4] } [Fact] @@ -466,7 +466,7 @@ public void ReduceArgMin() Assert.Equal(2, dst.Rows); Assert.Equal(1, dst.Cols); - Assert.Equal(1, dst.At(0)); // min along 1st row [2, 1] - Assert.Equal(0, dst.At(1)); // min along 2nd row [4, 4], taking the first occurence + Assert.Equal(1, dst.At(0, 0)); // min along 1st row [2, 1] + Assert.Equal(0, dst.At(1, 0)); // min along 2nd row [4, 4], taking the first occurence } }