diff --git a/.circleci/config.yml b/.circleci/config.yml index 29c772c73..dbce45322 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -126,9 +126,22 @@ jobs: LD_LIBRARY_PATH=. dotnet test OpenCvSharp.Tests.csproj -c Release -f netcoreapp3.0 --runtime ubuntu.16.04-x64 --logger "trx;LogFileName=test-results.trx" ls ls TestResults + cat /root/project/test/OpenCvSharp.Tests/TestResults/test-results.trx + + - run: + name: .trx to JUnit + when: always + command: | + dotnet tool install -g trx2junit + export PATH="$PATH:/root/.dotnet/tools" + trx2junit /root/project/test/OpenCvSharp.Tests/TestResults/*.trx - store_test_results: - path: /root/project/test/OpenCvSharp.Tests/TestResults/test-results.trx + path: /root/project/test/OpenCvSharp.Tests/TestResults/ + + - store_artifacts: + path: /root/project/test/OpenCvSharp.Tests/TestResults/ + destination: TestResults - save_cache: key: heavy_test_files_rev3 diff --git a/OpenCvSharp.sln b/OpenCvSharp.sln index daf7fa69b..9ef12c826 100644 --- a/OpenCvSharp.sln +++ b/OpenCvSharp.sln @@ -36,6 +36,10 @@ Global Debug|ARM = Debug|ARM Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 + FxCop|Any CPU = FxCop|Any CPU + FxCop|ARM = FxCop|ARM + FxCop|x64 = FxCop|x64 + FxCop|x86 = FxCop|x86 Release|Any CPU = Release|Any CPU Release|ARM = Release|ARM Release|x64 = Release|x64 @@ -54,6 +58,14 @@ Global {EB310923-197F-4E20-B123-3A3E7F1D5069}.Debug|x64.Build.0 = Debug|Any CPU {EB310923-197F-4E20-B123-3A3E7F1D5069}.Debug|x86.ActiveCfg = Debug|Any CPU {EB310923-197F-4E20-B123-3A3E7F1D5069}.Debug|x86.Build.0 = Debug|Any CPU + {EB310923-197F-4E20-B123-3A3E7F1D5069}.FxCop|Any CPU.ActiveCfg = Release|Any CPU + {EB310923-197F-4E20-B123-3A3E7F1D5069}.FxCop|Any CPU.Build.0 = Release|Any CPU + {EB310923-197F-4E20-B123-3A3E7F1D5069}.FxCop|ARM.ActiveCfg = Release|Any CPU + {EB310923-197F-4E20-B123-3A3E7F1D5069}.FxCop|ARM.Build.0 = Release|Any CPU + {EB310923-197F-4E20-B123-3A3E7F1D5069}.FxCop|x64.ActiveCfg = FxCop|Any CPU + {EB310923-197F-4E20-B123-3A3E7F1D5069}.FxCop|x64.Build.0 = FxCop|Any CPU + {EB310923-197F-4E20-B123-3A3E7F1D5069}.FxCop|x86.ActiveCfg = FxCop|Any CPU + {EB310923-197F-4E20-B123-3A3E7F1D5069}.FxCop|x86.Build.0 = FxCop|Any CPU {EB310923-197F-4E20-B123-3A3E7F1D5069}.Release|Any CPU.ActiveCfg = Release|Any CPU {EB310923-197F-4E20-B123-3A3E7F1D5069}.Release|Any CPU.Build.0 = Release|Any CPU {EB310923-197F-4E20-B123-3A3E7F1D5069}.Release|ARM.ActiveCfg = Release|Any CPU @@ -78,6 +90,14 @@ Global {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.Debug|x64.Build.0 = Debug|Any CPU {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.Debug|x86.ActiveCfg = Debug|Any CPU {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.Debug|x86.Build.0 = Debug|Any CPU + {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.FxCop|Any CPU.ActiveCfg = Release|Any CPU + {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.FxCop|Any CPU.Build.0 = Release|Any CPU + {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.FxCop|ARM.ActiveCfg = Release|Any CPU + {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.FxCop|ARM.Build.0 = Release|Any CPU + {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.FxCop|x64.ActiveCfg = Release|Any CPU + {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.FxCop|x64.Build.0 = Release|Any CPU + {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.FxCop|x86.ActiveCfg = Release|Any CPU + {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.FxCop|x86.Build.0 = Release|Any CPU {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.Release|Any CPU.ActiveCfg = Release|Any CPU {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.Release|Any CPU.Build.0 = Release|Any CPU {FFBBCF99-97F0-4F81-AAF6-8D851A8E1D2E}.Release|ARM.ActiveCfg = Release|Any CPU @@ -102,6 +122,14 @@ Global {82AFDA65-515E-4EC0-A415-77D8A6711508}.Debug|x64.Build.0 = Debug|Any CPU {82AFDA65-515E-4EC0-A415-77D8A6711508}.Debug|x86.ActiveCfg = Debug|Any CPU {82AFDA65-515E-4EC0-A415-77D8A6711508}.Debug|x86.Build.0 = Debug|Any CPU + {82AFDA65-515E-4EC0-A415-77D8A6711508}.FxCop|Any CPU.ActiveCfg = Release|Any CPU + {82AFDA65-515E-4EC0-A415-77D8A6711508}.FxCop|Any CPU.Build.0 = Release|Any CPU + {82AFDA65-515E-4EC0-A415-77D8A6711508}.FxCop|ARM.ActiveCfg = Release|Any CPU + {82AFDA65-515E-4EC0-A415-77D8A6711508}.FxCop|ARM.Build.0 = Release|Any CPU + {82AFDA65-515E-4EC0-A415-77D8A6711508}.FxCop|x64.ActiveCfg = Release|Any CPU + {82AFDA65-515E-4EC0-A415-77D8A6711508}.FxCop|x64.Build.0 = Release|Any CPU + {82AFDA65-515E-4EC0-A415-77D8A6711508}.FxCop|x86.ActiveCfg = Release|Any CPU + {82AFDA65-515E-4EC0-A415-77D8A6711508}.FxCop|x86.Build.0 = Release|Any CPU {82AFDA65-515E-4EC0-A415-77D8A6711508}.Release|Any CPU.ActiveCfg = Release|Any CPU {82AFDA65-515E-4EC0-A415-77D8A6711508}.Release|Any CPU.Build.0 = Release|Any CPU {82AFDA65-515E-4EC0-A415-77D8A6711508}.Release|ARM.ActiveCfg = Release|Any CPU @@ -126,6 +154,14 @@ Global {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.Debug|x64.Build.0 = Debug|Any CPU {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.Debug|x86.ActiveCfg = Debug|Any CPU {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.Debug|x86.Build.0 = Debug|Any CPU + {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.FxCop|Any CPU.ActiveCfg = Release|Any CPU + {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.FxCop|Any CPU.Build.0 = Release|Any CPU + {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.FxCop|ARM.ActiveCfg = Release|Any CPU + {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.FxCop|ARM.Build.0 = Release|Any CPU + {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.FxCop|x64.ActiveCfg = Release|Any CPU + {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.FxCop|x64.Build.0 = Release|Any CPU + {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.FxCop|x86.ActiveCfg = Release|Any CPU + {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.FxCop|x86.Build.0 = Release|Any CPU {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.Release|Any CPU.ActiveCfg = Release|Any CPU {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.Release|Any CPU.Build.0 = Release|Any CPU {B4B78BB2-1B7C-4CF2-BC72-43789EEDCE00}.Release|ARM.ActiveCfg = Release|Any CPU @@ -146,6 +182,13 @@ Global {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.Debug|ARM.ActiveCfg = Debug|Win32 {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.Debug|x64.ActiveCfg = Debug|x64 {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.Debug|x86.ActiveCfg = Debug|Win32 + {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.FxCop|Any CPU.ActiveCfg = Release|x64 + {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.FxCop|Any CPU.Build.0 = Release|x64 + {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.FxCop|ARM.ActiveCfg = Release|Win32 + {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.FxCop|x64.ActiveCfg = Release|x64 + {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.FxCop|x64.Build.0 = Release|x64 + {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.FxCop|x86.ActiveCfg = Release|Win32 + {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.FxCop|x86.Build.0 = Release|Win32 {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.Release|Any CPU.ActiveCfg = Release|x64 {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.Release|Any CPU.Build.0 = Release|x64 {8E7279F8-F801-4672-B42F-1ED2C68B16A4}.Release|ARM.ActiveCfg = Release|Win32 @@ -169,6 +212,14 @@ Global {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.Debug|x64.Build.0 = Debug|Any CPU {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.Debug|x86.ActiveCfg = Debug|Any CPU {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.Debug|x86.Build.0 = Debug|Any CPU + {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.FxCop|Any CPU.ActiveCfg = Release|Any CPU + {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.FxCop|Any CPU.Build.0 = Release|Any CPU + {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.FxCop|ARM.ActiveCfg = Release|Any CPU + {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.FxCop|ARM.Build.0 = Release|Any CPU + {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.FxCop|x64.ActiveCfg = Release|Any CPU + {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.FxCop|x64.Build.0 = Release|Any CPU + {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.FxCop|x86.ActiveCfg = Release|Any CPU + {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.FxCop|x86.Build.0 = Release|Any CPU {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.Release|Any CPU.ActiveCfg = Release|Any CPU {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.Release|Any CPU.Build.0 = Release|Any CPU {4232CB4A-DFE3-46CA-9503-C5F1798BAED3}.Release|ARM.ActiveCfg = Release|Any CPU @@ -193,6 +244,14 @@ Global {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.Debug|x64.Build.0 = Debug|Any CPU {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.Debug|x86.ActiveCfg = Debug|Any CPU {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.Debug|x86.Build.0 = Debug|Any CPU + {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.FxCop|Any CPU.ActiveCfg = Release|Any CPU + {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.FxCop|Any CPU.Build.0 = Release|Any CPU + {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.FxCop|ARM.ActiveCfg = Release|Any CPU + {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.FxCop|ARM.Build.0 = Release|Any CPU + {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.FxCop|x64.ActiveCfg = Release|Any CPU + {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.FxCop|x64.Build.0 = Release|Any CPU + {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.FxCop|x86.ActiveCfg = Release|Any CPU + {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.FxCop|x86.Build.0 = Release|Any CPU {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.Release|Any CPU.ActiveCfg = Release|Any CPU {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.Release|Any CPU.Build.0 = Release|Any CPU {E2C8C528-B7C7-40AF-BB7F-1147A41E2E23}.Release|ARM.ActiveCfg = Release|Any CPU @@ -217,6 +276,14 @@ Global {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.Debug|x64.Build.0 = Debug|Any CPU {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.Debug|x86.ActiveCfg = Debug|Any CPU {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.Debug|x86.Build.0 = Debug|Any CPU + {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.FxCop|Any CPU.ActiveCfg = Release|Any CPU + {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.FxCop|Any CPU.Build.0 = Release|Any CPU + {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.FxCop|ARM.ActiveCfg = Release|Any CPU + {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.FxCop|ARM.Build.0 = Release|Any CPU + {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.FxCop|x64.ActiveCfg = Release|Any CPU + {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.FxCop|x64.Build.0 = Release|Any CPU + {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.FxCop|x86.ActiveCfg = Release|Any CPU + {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.FxCop|x86.Build.0 = Release|Any CPU {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.Release|Any CPU.ActiveCfg = Release|Any CPU {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.Release|Any CPU.Build.0 = Release|Any CPU {CC19F9A5-01A7-4BDF-B34C-CF56F46A474A}.Release|ARM.ActiveCfg = Release|Any CPU @@ -240,6 +307,13 @@ Global {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.Debug|x64.Build.0 = Debug|x64 {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.Debug|x86.ActiveCfg = Debug|Win32 {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.Debug|x86.Build.0 = Debug|Win32 + {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.FxCop|Any CPU.ActiveCfg = Release|Win32 + {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.FxCop|ARM.ActiveCfg = Release|ARM + {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.FxCop|ARM.Build.0 = Release|ARM + {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.FxCop|x64.ActiveCfg = Release|x64 + {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.FxCop|x64.Build.0 = Release|x64 + {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.FxCop|x86.ActiveCfg = Release|Win32 + {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.FxCop|x86.Build.0 = Release|Win32 {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.Release|Any CPU.ActiveCfg = Release|Win32 {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.Release|ARM.ActiveCfg = Release|ARM {BD5471E5-7B55-5192-8DA4-042B66AF71AE}.Release|ARM.Build.0 = Release|ARM diff --git a/OpenCvSharp.sln.DotSettings b/OpenCvSharp.sln.DotSettings index f43529724..15089eca3 100644 --- a/OpenCvSharp.sln.DotSettings +++ b/OpenCvSharp.sln.DotSettings @@ -51,6 +51,7 @@ True True True + True True True diff --git a/src/OpenCvSharp.Extensions/CvExtensions.cs b/src/OpenCvSharp.Extensions/CvExtensions.cs index 510d61561..ab377e58a 100644 --- a/src/OpenCvSharp.Extensions/CvExtensions.cs +++ b/src/OpenCvSharp.Extensions/CvExtensions.cs @@ -62,7 +62,7 @@ public static class CvExtensions if (minLineLength <= 0) throw new ArgumentOutOfRangeException(nameof(minLineLength)); if (thetaMax < thetaMin) - throw new ArgumentException(); + throw new ArgumentException("thetaMax < thetaMin"); if (thetaMax > Math.PI) throw new ArgumentOutOfRangeException(nameof(thetaMax), "thetaMax <= pi"); if (thetaMin < 0) diff --git a/src/OpenCvSharp/OpenCvSharp.csproj b/src/OpenCvSharp/OpenCvSharp.csproj index d3c2c5476..93c5d09a5 100644 --- a/src/OpenCvSharp/OpenCvSharp.csproj +++ b/src/OpenCvSharp/OpenCvSharp.csproj @@ -12,12 +12,12 @@ false false false - Debug;Release;Release-JP + Debug;Release;Release-JP;FxCop 8 enable - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/OpenCvSharp/PInvoke/NativeMethods/NativeMethods_imgcodecs.cs b/src/OpenCvSharp/PInvoke/NativeMethods/NativeMethods_imgcodecs.cs index 377cf6578..f00e8b847 100644 --- a/src/OpenCvSharp/PInvoke/NativeMethods/NativeMethods_imgcodecs.cs +++ b/src/OpenCvSharp/PInvoke/NativeMethods/NativeMethods_imgcodecs.cs @@ -8,15 +8,15 @@ namespace OpenCvSharp { static partial class NativeMethods { - [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true, CharSet = CharSet.Ansi)] + [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true)] public static extern ExceptionStatus imgcodecs_imread( [MarshalAs(StringUnmanagedType)] string filename, int flags, out IntPtr returnValue); - [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true, CharSet = CharSet.Ansi)] + [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true)] public static extern ExceptionStatus imgcodecs_imreadmulti( [MarshalAs(StringUnmanagedType)] string filename, IntPtr mats, int flags, out int returnValue); - [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true, CharSet = CharSet.Ansi)] + [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true)] public static extern ExceptionStatus imgcodecs_imwrite( [MarshalAs(StringUnmanagedType)] string filename, IntPtr img, [In] int[] @params, int paramsLength, out int returnValue); @@ -36,15 +36,15 @@ static partial class NativeMethods public static extern ExceptionStatus imgcodecs_imdecode_InputArray( IntPtr buf, int flags, out IntPtr returnValue); - [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true, CharSet = CharSet.Ansi)] + [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true)] public static extern ExceptionStatus imgcodecs_imencode_vector( [MarshalAs(StringUnmanagedType)] string ext, IntPtr img, IntPtr buf, [In] int[] @params, int paramsLength, out int returnValue); - [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true, CharSet = CharSet.Ansi)] + [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true)] public static extern ExceptionStatus imgcodecs_haveImageReader( [MarshalAs(StringUnmanagedType)] string fileName, out int returnValue); - [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true, CharSet = CharSet.Ansi)] + [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true, ExactSpelling = true)] public static extern ExceptionStatus imgcodecs_haveImageWriter( [MarshalAs(StringUnmanagedType)] string fileName, out int returnValue); } diff --git a/src/OpenCvSharp/PInvoke/NativeMethods/dnn/NativeMethods_dnn.cs b/src/OpenCvSharp/PInvoke/NativeMethods/dnn/NativeMethods_dnn.cs index f0a0f9fcd..25c9c016a 100644 --- a/src/OpenCvSharp/PInvoke/NativeMethods/dnn/NativeMethods_dnn.cs +++ b/src/OpenCvSharp/PInvoke/NativeMethods/dnn/NativeMethods_dnn.cs @@ -14,40 +14,40 @@ static partial class NativeMethods { [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_readNetFromDarknet( - [MarshalAs(UnmanagedType.LPStr)] string cfgFile, [MarshalAs(UnmanagedType.LPStr)] string? darknetModel, out IntPtr returnValue); + [MarshalAs(StringUnmanagedType)] string cfgFile, [MarshalAs(UnmanagedType.LPStr)] string? darknetModel, out IntPtr returnValue); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_readNetFromCaffe( - [MarshalAs(UnmanagedType.LPStr)] string prototxt, [MarshalAs(UnmanagedType.LPStr)] string? caffeModel, out IntPtr returnValue); + [MarshalAs(StringUnmanagedType)] string prototxt, [MarshalAs(UnmanagedType.LPStr)] string? caffeModel, out IntPtr returnValue); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_readNetFromTensorflow( - [MarshalAs(UnmanagedType.LPStr)] string model, [MarshalAs(UnmanagedType.LPStr)] string? config, out IntPtr returnValue); + [MarshalAs(StringUnmanagedType)] string model, [MarshalAs(UnmanagedType.LPStr)] string? config, out IntPtr returnValue); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_readNetFromTorch( - [MarshalAs(UnmanagedType.LPStr)] string model, int isBinary, out IntPtr returnValue); + [MarshalAs(StringUnmanagedType)] string model, int isBinary, out IntPtr returnValue); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_readNet( - [MarshalAs(UnmanagedType.LPStr)] string model, [MarshalAs(UnmanagedType.LPStr)] string config, [MarshalAs(UnmanagedType.LPStr)] string framework, + [MarshalAs(StringUnmanagedType)] string model, [MarshalAs(UnmanagedType.LPStr)] string config, [MarshalAs(UnmanagedType.LPStr)] string framework, out IntPtr returnValue); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_readTorchBlob( - [MarshalAs(UnmanagedType.LPStr)] string filename, int isBinary, out IntPtr returnValue); + [MarshalAs(StringUnmanagedType)] string filename, int isBinary, out IntPtr returnValue); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_readNetFromModelOptimizer( - [MarshalAs(UnmanagedType.LPStr)] string xml, [MarshalAs(UnmanagedType.LPStr)] string bin, out IntPtr returnValue); + [MarshalAs(StringUnmanagedType)] string xml, [MarshalAs(UnmanagedType.LPStr)] string bin, out IntPtr returnValue); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_readNetFromONNX( - [MarshalAs(UnmanagedType.LPStr)] string onnxFile, out IntPtr returnValue); + [MarshalAs(StringUnmanagedType)] string onnxFile, out IntPtr returnValue); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_readTensorFromONNX( - [MarshalAs(UnmanagedType.LPStr)] string path, out IntPtr returnValue); + [MarshalAs(StringUnmanagedType)] string path, out IntPtr returnValue); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] @@ -60,11 +60,11 @@ static partial class NativeMethods [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_shrinkCaffeModel( - [MarshalAs(UnmanagedType.LPStr)] string src, [MarshalAs(UnmanagedType.LPStr)] string dst); + [MarshalAs(StringUnmanagedType)] string src, [MarshalAs(UnmanagedType.LPStr)] string dst); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_writeTextGraph( - [MarshalAs(UnmanagedType.LPStr)] string model, [MarshalAs(UnmanagedType.LPStr)] string output); + [MarshalAs(StringUnmanagedType)] string model, [MarshalAs(UnmanagedType.LPStr)] string output); [Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern ExceptionStatus dnn_NMSBoxes_Rect( diff --git a/test/OpenCvSharp.Tests/OpenCvSharp.Tests.csproj b/test/OpenCvSharp.Tests/OpenCvSharp.Tests.csproj index 1e7c4af69..53d968afe 100644 --- a/test/OpenCvSharp.Tests/OpenCvSharp.Tests.csproj +++ b/test/OpenCvSharp.Tests/OpenCvSharp.Tests.csproj @@ -45,6 +45,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + all @@ -53,6 +54,10 @@ + + + + $(DefineConstants);DOTNET_FRAMEWORK; diff --git a/test/OpenCvSharp.Tests/TestBase.cs b/test/OpenCvSharp.Tests/TestBase.cs index c218ec3a1..1bf7109b9 100644 --- a/test/OpenCvSharp.Tests/TestBase.cs +++ b/test/OpenCvSharp.Tests/TestBase.cs @@ -22,7 +22,13 @@ static TestBase() { ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; - httpClient = new HttpClient + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + + var handler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = delegate { return true; } + }; + httpClient = new HttpClient(handler) { Timeout = TimeSpan.FromMinutes(5) }; @@ -95,8 +101,8 @@ protected static byte[] DownloadBytes(Uri uri) { using var client = new MyWebClient(); return client.DownloadData(uri); - //var response = (await httpClient.GetAsync(url)).EnsureSuccessStatusCode(); - //return await response.Content.ReadAsByteArrayAsync(); + //var response = (httpClient.GetAsync(uri).Result).EnsureSuccessStatusCode(); + //return response.Content.ReadAsByteArrayAsync().Result; } private static byte[] DownloadAndCacheBytes(Uri uri, string fileName) diff --git a/test/OpenCvSharp.Tests/_data/image/abbey_road.jpg b/test/OpenCvSharp.Tests/_data/image/abbey_road.jpg new file mode 100644 index 000000000..76068d229 Binary files /dev/null and b/test/OpenCvSharp.Tests/_data/image/abbey_road.jpg differ diff --git a/test/OpenCvSharp.Tests/dnn/CaffeTest.cs b/test/OpenCvSharp.Tests/dnn/CaffeTest.cs index 8a4f064a9..9697a0485 100644 --- a/test/OpenCvSharp.Tests/dnn/CaffeTest.cs +++ b/test/OpenCvSharp.Tests/dnn/CaffeTest.cs @@ -8,9 +8,16 @@ namespace OpenCvSharp.Tests.Dnn { public class CaffeTest : TestBase - { + { + private static readonly object lockObj = new object(); + private readonly ITestOutputHelper testOutputHelper; + public CaffeTest(ITestOutputHelper testOutputHelper) + { + this.testOutputHelper = testOutputHelper; + } + // https://docs.opencv.org/3.3.0/d5/de7/tutorial_dnn_googlenet.html [Fact] public void LoadCaffeModel() @@ -47,6 +54,11 @@ public void LoadCaffeModel() Assert.Equal(812, classId); } + /// + /// Download model file + /// + /// + /// private static void PrepareModel(Uri uri, string fileName) { lock (lockObj) @@ -58,12 +70,6 @@ private static void PrepareModel(Uri uri, string fileName) } } } - private static readonly object lockObj = new object(); - - public CaffeTest(ITestOutputHelper testOutputHelper) - { - this.testOutputHelper = testOutputHelper; - } /// /// Find best class for the blob (i. e. class with maximal probability) diff --git a/test/OpenCvSharp.Tests/dnn/EastTextDetectionTest.cs b/test/OpenCvSharp.Tests/dnn/EastTextDetectionTest.cs new file mode 100644 index 000000000..3d6e0d8de --- /dev/null +++ b/test/OpenCvSharp.Tests/dnn/EastTextDetectionTest.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using ICSharpCode.SharpZipLib.GZip; +using ICSharpCode.SharpZipLib.Tar; +using OpenCvSharp.Dnn; +using Xunit; +using Xunit.Abstractions; + +namespace OpenCvSharp.Tests.Dnn +{ + /// + /// https://github.com/opencv/opencv/blob/master/samples/dnn/text_detection.cpp + /// + /// + /// + public class EastTextDetectionTest : TestBase + { + // https://github.com/opencv/opencv_extra/blob/322b475403899abc2411c4fbf68318afa77d3191/testdata/dnn/download_models.py#L302 + const string ModelUrl = "https://www.dropbox.com/s/r2ingd0l3zt8hxs/frozen_east_text_detection.tar.gz?dl=1"; + const string LocalRawModelPath = "_data/model/frozen_east_text_detection.tar.gz"; + const string LocalModelPath = "_data/model/frozen_east_text_detection.pb"; + + private static readonly object lockObj = new object(); + + private readonly ITestOutputHelper testOutputHelper; + + /// + /// Download model file + /// + /// + public EastTextDetectionTest(ITestOutputHelper testOutputHelper) + { + this.testOutputHelper = testOutputHelper ?? throw new ArgumentNullException(nameof(testOutputHelper)); + + testOutputHelper.WriteLine("Downloading EAST Model..."); + PrepareModel(new Uri(ModelUrl), LocalRawModelPath); + testOutputHelper.WriteLine("Done"); + Assert.True(File.Exists(LocalRawModelPath), $"'{LocalRawModelPath}' not found"); + + if (!File.Exists(LocalModelPath)) + { + var modelDirectory = Path.GetDirectoryName(LocalRawModelPath)!; + ExtractTarGz(LocalRawModelPath, modelDirectory); + } + + var fileInfo = new FileInfo(LocalModelPath); + Assert.True(fileInfo.Exists, $"'{LocalModelPath}' not found"); + Assert.True(fileInfo.Length > 90 * 1024 * 1024, $"Too small data ('{fileInfo.Length}' bytes)"); + } + + /// + /// Download model file if it does not exist on local disk + /// + /// + /// + private static void PrepareModel(Uri uri, string fileName) + { + lock (lockObj) + { + if (!File.Exists(fileName)) + { + var contents = DownloadBytes(uri); + File.WriteAllBytes(fileName, contents); + } + } + } + + /// + /// Simple full extract from a TGZ + /// https://github.com/icsharpcode/SharpZipLib/wiki/GZip-and-Tar-Samples + /// + /// + /// + private static void ExtractTarGz(string inputFile, string dstFolder) + { + using var inputStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read); + using var gzipStream = new GZipInputStream(inputStream); + using var tarArchive = TarArchive.CreateInputTarArchive(gzipStream); + tarArchive.ExtractContents(dstFolder); + } + + [Fact] + public void Load() + { + Assert.True(File.Exists(LocalModelPath), $"'{LocalModelPath}' not found"); + + using var net = CvDnn.ReadNet(LocalModelPath); + } + + [Fact] + public void NotSupportedUnicodeFileName() + { + Assert.True(File.Exists(LocalModelPath), $"'{LocalModelPath}' not found"); + + var unicodeFileName = Path.Combine(Path.GetDirectoryName(LocalModelPath)!, "🤣🍀.pb"); + if (!File.Exists(unicodeFileName)) + { + File.Copy(LocalModelPath, unicodeFileName, true); + } + + // Check that ArgumentException(unicode unmappable char) does not occur. + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var ex = Assert.Throws(() => + { + using var net = CvDnn.ReadNet(unicodeFileName); + }); + Assert.StartsWith("FAILED: fs.is_open(). Can't open", ex.Message, StringComparison.InvariantCulture); + Assert.Equal("cv::dnn::ReadProtoFromBinaryFile", ex.FuncName); + } + else + { + // No error + } + } + + /// + /// detect text from image. + /// + /// + /// Name of the image file. + /// The loader factory. + /// Scanned text. + [Theory] + [InlineData("_data/image/abbey_road.jpg")] + public void DetectAllText(string fileName) + { + const int InputWidth = 320; + const int InputHeight = 320; + const float ConfThreshold = 0.5f; + const float NmsThreshold = 0.4f; + + // Load network. + using (Net net = CvDnn.ReadNet(Path.GetFullPath(LocalModelPath))) + using (Mat img = new Mat(fileName)) + + // Prepare input image + using (var blob = CvDnn.BlobFromImage(img, 1.0, new Size(InputWidth, InputHeight), new Scalar(123.68, 116.78, 103.94), true, false)) + { + // Forward Pass + // Now that we have prepared the input, we will pass it through the network. There are two outputs of the network. + // One specifies the geometry of the Text-box and the other specifies the confidence score of the detected box. + // These are given by the layers : + // feature_fusion/concat_3 + // feature_fusion/Conv_7/Sigmoid + var outputBlobNames = new string[] { "feature_fusion/Conv_7/Sigmoid", "feature_fusion/concat_3" }; + var outputBlobs = outputBlobNames.Select(_ => new Mat()).ToArray(); + + net.SetInput(blob); + net.Forward(outputBlobs, outputBlobNames); + Mat scores = outputBlobs[0]; + Mat geometry = outputBlobs[1]; + + // Decode predicted bounding boxes (decode the positions of the text boxes along with their orientation) + Decode(scores, geometry, ConfThreshold, out var boxes, out var confidences); + + // Apply non-maximum suppression procedure for filtering out the false positives and get the final predictions + CvDnn.NMSBoxes(boxes, confidences, ConfThreshold, NmsThreshold, out var indices); + + // Render detections. + Point2f ratio = new Point2f((float)img.Cols / InputWidth, (float)img.Rows / InputHeight); + for (var i = 0; i < indices.Length; ++i) + { + RotatedRect box = boxes[indices[i]]; + + Point2f[] vertices = box.Points(); + + for (int j = 0; j < 4; ++j) + { + vertices[j].X *= ratio.X; + vertices[j].Y *= ratio.Y; + } + + for (int j = 0; j < 4; ++j) + { + Cv2.Line(img, (int)vertices[j].X, (int)vertices[j].Y, (int)vertices[(j + 1) % 4].X, (int)vertices[(j + 1) % 4].Y, new Scalar(0, 255, 0), 3); + } + } + + ShowImagesWhenDebugMode(img); + } + } + + private unsafe void Decode(Mat scores, Mat geometry, float confThreshold, out IList boxes, out IList confidences) + { + boxes = new List(); + confidences = new List(); + + if ((scores == null || scores.Dims != 4 || scores.Size(0) != 1 || scores.Size(1) != 1) || + (geometry == null || geometry.Dims != 4 || geometry.Size(0) != 1 || geometry.Size(1) != 5) || + (scores.Size(2) != geometry.Size(2) || scores.Size(3) != geometry.Size(3))) + { + return; + } + + int height = scores.Size(2); + int width = scores.Size(3); + + for (int y = 0; y < height; ++y) + { + var scoresData = new ReadOnlySpan((void*)scores.Ptr(0, 0, y), height); + var x0Data = new ReadOnlySpan((void*)geometry.Ptr(0, 0, y), height); + var x1Data = new ReadOnlySpan((void*)geometry.Ptr(0, 1, y), height); + var x2Data = new ReadOnlySpan((void*)geometry.Ptr(0, 2, y), height); + var x3Data = new ReadOnlySpan((void*)geometry.Ptr(0, 3, y), height); + var anglesData = new ReadOnlySpan((void*)geometry.Ptr(0, 4, y), height); + + for (int x = 0; x < width; ++x) + { + var score = scoresData[x]; + if (score >= confThreshold) + { + float offsetX = x * 4.0f; + float offsetY = y * 4.0f; + float angle = anglesData[x]; + float cosA = (float)Math.Cos(angle); + float sinA = (float)Math.Sin(angle); + float x0 = x0Data[x]; + float x1 = x1Data[x]; + float x2 = x2Data[x]; + float x3 = x3Data[x]; + float h = x0 + x2; + float w = x1 + x3; + Point2f offset = new Point2f(offsetX + (cosA * x1) + (sinA * x2), offsetY - (sinA * x1) + (cosA * x2)); + Point2f p1 = new Point2f((-sinA * h) + offset.X, (-cosA * h) + offset.Y); + Point2f p3 = new Point2f((-cosA * w) + offset.X, (sinA * w) + offset.Y); + RotatedRect r = new RotatedRect(new Point2f(0.5f * (p1.X + p3.X), 0.5f * (p1.Y + p3.Y)), new Size2f(w, h), (float)(-angle * 180.0f / Math.PI)); + boxes.Add(r); + confidences.Add(score); + } + } + } + } + } +} diff --git a/test/OpenCvSharp.Tests/imgcodecs/ImgCodecsTest.cs b/test/OpenCvSharp.Tests/imgcodecs/ImgCodecsTest.cs index e4b2b7679..430a48295 100644 --- a/test/OpenCvSharp.Tests/imgcodecs/ImgCodecsTest.cs +++ b/test/OpenCvSharp.Tests/imgcodecs/ImgCodecsTest.cs @@ -50,27 +50,31 @@ public void ImReadDoesNotSupportGif() [Fact] public void ImReadUnicodeFileName() { - // TODO - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return; + // https://github.com/opencv/opencv/issues/4242 const string fileName = "_data/image/imread♥♡😀😄.png"; + const string fileNameTemp = "_data/image/imread_test_image.png"; // Check whether the path is valid + // ReSharper disable once ReturnValueOfPureMethodIsNotUsed Path.GetFullPath(fileName); { using var bitmap = new Bitmap(10, 10, PixelFormat.Format24bppRgb); using var graphics = Graphics.FromImage(bitmap); graphics.Clear(Color.Red); - bitmap.Save(fileName, ImageFormat.Png); + bitmap.Save(fileNameTemp, ImageFormat.Png); } + File.Move(fileNameTemp, fileName); Assert.True(File.Exists(fileName), $"File '{fileName}' not found"); using var image = Cv2.ImRead(fileName, ImreadModes.Color); Assert.NotNull(image); - Assert.True(image.Empty()); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + Assert.True(image.Empty()); // TODO + else + Assert.False(image.Empty()); } [Theory] @@ -94,12 +98,19 @@ public void ImWrite(string ext) } } - [Fact(Skip = "no output")] + //[Fact(Skip = "no output")] + [Fact] public void ImWriteUnicodeFileName() { + // https://github.com/opencv/opencv/issues/4242 + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return; // TODO + const string fileName = "_data/image/imwrite♥♡😀😄.png"; // Check whether the path is valid + // ReSharper disable once ReturnValueOfPureMethodIsNotUsed Path.GetFullPath(fileName); using (var mat = new Mat(10, 20, MatType.CV_8UC3, Scalar.Blue)) @@ -110,7 +121,9 @@ public void ImWriteUnicodeFileName() // TODO fail Assert.True(File.Exists(fileName), $"File '{fileName}' not found"); - using (var bitmap = new Bitmap(fileName)) + const string asciiFileName = "_data/image/imwrite_unicode_test.png"; + File.Move(fileName, asciiFileName); + using (var bitmap = new Bitmap(asciiFileName)) { Assert.Equal(10, bitmap.Height); Assert.Equal(20, bitmap.Width); diff --git a/test/OpenCvSharp.Tests/quality/QualityGMSDTest.cs b/test/OpenCvSharp.Tests/quality/QualityGMSDTest.cs index 9d9e9839a..b46c6cf7d 100644 --- a/test/OpenCvSharp.Tests/quality/QualityGMSDTest.cs +++ b/test/OpenCvSharp.Tests/quality/QualityGMSDTest.cs @@ -17,7 +17,7 @@ public void Compute() var value = psnr.Compute(targetImage); Assert.Equal(0.0616, value[0], 4); Assert.Equal(0.0711, value[1], 4); - Assert.Equal(0.05983, value[2], 6); + Assert.Equal(0.05983, value[2], 5); } } @@ -32,7 +32,7 @@ public void StaticCompute() var value = QualityGMSD.Compute(refImage, targetImage, null); Assert.Equal(0.0616, value[0], 4); Assert.Equal(0.0711, value[1], 4); - Assert.Equal(0.05983, value[2], 6); + Assert.Equal(0.05983, value[2], 5); } } }