From 68a81888ec7406db7bf2c34cb382b3f2a185724b Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Mon, 7 Oct 2024 17:07:59 +0300 Subject: [PATCH] Merge pull request #26256 from vpisarev:expanded_tests_for_norm extended Norm tests to prove that cv::norm() already supports all the types. cv::norm() already provides enough functionality; just extended tests to prove it. See #24887 - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake --- modules/core/src/norm.cpp | 136 +++++++++++++++++++-- modules/core/test/ocl/test_arithm.cpp | 2 +- modules/ts/include/opencv2/ts/ocl_test.hpp | 1 + modules/ts/src/ts_func.cpp | 22 +++- 4 files changed, 142 insertions(+), 19 deletions(-) diff --git a/modules/core/src/norm.cpp b/modules/core/src/norm.cpp index b141c29ede..e2833e8e12 100644 --- a/modules/core/src/norm.cpp +++ b/modules/core/src/norm.cpp @@ -281,6 +281,61 @@ normL2_(const T* src, const uchar* mask, ST* _result, int len, int cn) return 0; } +static int +normInf_Bool(const uchar* src, const uchar* mask, int* _result, int len, int cn) +{ + int result = *_result; + if( !mask ) + { + for ( int i = 0; i < len*cn; i++ ) { + result = std::max(result, (int)(src[i] != 0)); + if (result != 0) + break; + } + } + else + { + for( int i = 0; i < len; i++, src += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + result = std::max(result, (int)(src[k] != 0)); + if (result != 0) + break; + } + } + *_result = result; + return 0; +} + +static int +normL1_Bool(const uchar* src, const uchar* mask, int* _result, int len, int cn) +{ + int result = *_result; + if( !mask ) + { + for ( int i = 0; i < len*cn; i++ ) + result += (int)(src[i] != 0); + } + else + { + for( int i = 0; i < len; i++, src += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + result += (int)(src[k] != 0); + } + } + *_result = result; + return 0; +} + +static int +normL2_Bool(const uchar* src, const uchar* mask, int* _result, int len, int cn) +{ + return normL1_Bool(src, mask, _result, len, cn); +} + template int normDiffInf_(const T* src1, const T* src2, const uchar* mask, ST* _result, int len, int cn) { @@ -347,6 +402,61 @@ normDiffL2_(const T* src1, const T* src2, const uchar* mask, ST* _result, int le return 0; } +static int +normDiffInf_Bool(const uchar* src1, const uchar* src2, const uchar* mask, int* _result, int len, int cn) +{ + int result = *_result; + if( !mask ) + { + for( int i = 0; i < len*cn; i++ ) { + result = std::max(result, (int)((src1[i] != 0) != (src2[i] != 0))); + if (result != 0) + break; + } + } + else + { + for( int i = 0; i < len; i++, src1 += cn, src2 += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + result = std::max(result, (int)((src1[k] != 0) != (src2[k] != 0))); + if (result != 0) + break; + } + } + *_result = result; + return 0; +} + +static int +normDiffL1_Bool(const uchar* src1, const uchar* src2, const uchar* mask, int* _result, int len, int cn) +{ + int result = *_result; + if( !mask ) + { + for( int i = 0; i < len*cn; i++ ) + result += (int)((src1[i] != 0) != (src2[i] != 0)); + } + else + { + for( int i = 0; i < len; i++, src1 += cn, src2 += cn ) + if( mask[i] ) + { + for( int k = 0; k < cn; k++ ) + result += (int)((src1[k] != 0) != (src2[k] != 0)); + } + } + *_result = result; + return 0; +} + +static int +normDiffL2_Bool(const uchar* src1, const uchar* src2, const uchar* mask, int* _result, int len, int cn) +{ + return normDiffL1_Bool(src1, src2, mask, _result, len, cn); +} + #define CV_DEF_NORM_FUNC(L, suffix, type, ntype) \ static int norm##L##_##suffix(const type* src, const uchar* mask, ntype* r, int len, int cn) \ { return norm##L##_(src, mask, r, len, cn); } \ @@ -389,7 +499,7 @@ static NormFunc getNormFunc(int normType, int depth) (NormFunc)normInf_64f, (NormFunc)GET_OPTIMIZED(normInf_16f), (NormFunc)GET_OPTIMIZED(normInf_16bf), - 0, + (NormFunc)normInf_Bool, (NormFunc)GET_OPTIMIZED(normInf_64u), (NormFunc)GET_OPTIMIZED(normInf_64s), (NormFunc)GET_OPTIMIZED(normInf_32u), @@ -405,7 +515,7 @@ static NormFunc getNormFunc(int normType, int depth) (NormFunc)normL1_64f, (NormFunc)GET_OPTIMIZED(normL1_16f), (NormFunc)GET_OPTIMIZED(normL1_16bf), - 0, + (NormFunc)normL1_Bool, (NormFunc)GET_OPTIMIZED(normL1_64u), (NormFunc)GET_OPTIMIZED(normL1_64s), (NormFunc)GET_OPTIMIZED(normL1_32u), @@ -421,7 +531,7 @@ static NormFunc getNormFunc(int normType, int depth) (NormFunc)normL2_64f, (NormFunc)GET_OPTIMIZED(normL2_16f), (NormFunc)GET_OPTIMIZED(normL2_16bf), - 0, + (NormFunc)normL2_Bool, (NormFunc)GET_OPTIMIZED(normL2_64u), (NormFunc)GET_OPTIMIZED(normL2_64s), (NormFunc)GET_OPTIMIZED(normL2_32u), @@ -446,7 +556,7 @@ static NormDiffFunc getNormDiffFunc(int normType, int depth) (NormDiffFunc)normDiffInf_64f, (NormDiffFunc)GET_OPTIMIZED(normDiffInf_16f), (NormDiffFunc)GET_OPTIMIZED(normDiffInf_16bf), - 0, + (NormDiffFunc)normDiffInf_Bool, (NormDiffFunc)GET_OPTIMIZED(normDiffInf_64u), (NormDiffFunc)GET_OPTIMIZED(normDiffInf_64s), (NormDiffFunc)GET_OPTIMIZED(normDiffInf_32u), @@ -462,7 +572,7 @@ static NormDiffFunc getNormDiffFunc(int normType, int depth) (NormDiffFunc)normDiffL1_64f, (NormDiffFunc)GET_OPTIMIZED(normDiffL1_16f), (NormDiffFunc)GET_OPTIMIZED(normDiffL1_16bf), - 0, + (NormDiffFunc)normDiffL1_Bool, (NormDiffFunc)GET_OPTIMIZED(normDiffL1_64u), (NormDiffFunc)GET_OPTIMIZED(normDiffL1_64s), (NormDiffFunc)GET_OPTIMIZED(normDiffL1_32u), @@ -478,7 +588,7 @@ static NormDiffFunc getNormDiffFunc(int normType, int depth) (NormDiffFunc)normDiffL2_64f, (NormDiffFunc)GET_OPTIMIZED(normDiffL2_16f), (NormDiffFunc)GET_OPTIMIZED(normDiffL2_16bf), - 0, + (NormDiffFunc)normDiffL2_Bool, (NormDiffFunc)GET_OPTIMIZED(normDiffL2_64u), (NormDiffFunc)GET_OPTIMIZED(normDiffL2_64s), (NormDiffFunc)GET_OPTIMIZED(normDiffL2_32u), @@ -788,13 +898,14 @@ double norm( InputArray _src, int normType, InputArray _mask ) CV_CheckLT((size_t)it.size, (size_t)INT_MAX, ""); bool is_fp16 = depth == CV_16F || depth == CV_16BF; - if ((normType == NORM_L1 && (depth <= CV_16S || is_fp16)) || - ((normType == NORM_L2 || normType == NORM_L2SQR) && (depth <= CV_8S || is_fp16))) + if ((normType == NORM_L1 && (depth <= CV_16S || depth == CV_Bool || is_fp16)) || + ((normType == NORM_L2 || normType == NORM_L2SQR) && (depth <= CV_8S || depth == CV_Bool || is_fp16))) { // special case to handle "integer" overflow in accumulator const size_t esz = src.elemSize(); const int total = (int)it.size; const int blockSize0 = (is_fp16 ? (1 << 10) : + depth == CV_Bool ? (1 << 30) : normType == NORM_L1 && depth <= CV_8S ? (1 << 23) : (1 << 15))/cn; const int blockSize = std::min(total, blockSize0); union { @@ -834,7 +945,7 @@ double norm( InputArray _src, int normType, InputArray _mask ) if( normType == NORM_INF ) { - if(depth <= CV_32S || depth == CV_32U) + if(depth <= CV_32S || depth == CV_32U || depth == CV_Bool) return result.u; if (depth == CV_32F || is_fp16) return result.f; @@ -1243,13 +1354,14 @@ double norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask bool is_fp16 = depth == CV_16F || depth == CV_16BF; - if ((normType == NORM_L1 && (depth <= CV_16S || is_fp16)) || - ((normType == NORM_L2 || normType == NORM_L2SQR) && (depth <= CV_8S || is_fp16))) + if ((normType == NORM_L1 && (depth <= CV_16S || depth == CV_Bool || is_fp16)) || + ((normType == NORM_L2 || normType == NORM_L2SQR) && (depth <= CV_8S || depth == CV_Bool || is_fp16))) { // special case to handle "integer" overflow in accumulator const size_t esz = src1.elemSize(); const int total = (int)it.size; const int blockSize0 = (is_fp16 ? (1 << 10) : + depth == CV_Bool ? (1 << 30) : normType == NORM_L1 && depth <= CV_8S ? (1 << 23) : (1 << 15))/cn; const int blockSize = std::min(total, blockSize0); union { @@ -1290,7 +1402,7 @@ double norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask if( normType == NORM_INF ) { - if (depth <= CV_32S || depth == CV_32U) + if (depth <= CV_32S || depth == CV_32U || depth == CV_Bool) return result.u; if (depth == CV_32F || is_fp16) return result.f; diff --git a/modules/core/test/ocl/test_arithm.cpp b/modules/core/test/ocl/test_arithm.cpp index 8ce11c30b3..9b7cfe18d5 100644 --- a/modules/core/test/ocl/test_arithm.cpp +++ b/modules/core/test/ocl/test_arithm.cpp @@ -2038,7 +2038,7 @@ OCL_INSTANTIATE_TEST_CASE_P(Arithm, Magnitude, Combine(::testing::Values(CV_32F, OCL_INSTANTIATE_TEST_CASE_P(Arithm, Flip, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, MinMaxIdx, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, MinMaxIdx_Mask, Combine(OCL_ALL_DEPTHS, ::testing::Values(Channels(1)), Bool())); -OCL_INSTANTIATE_TEST_CASE_P(Arithm, Norm, Combine(OCL_ALL_DEPTHS_16F, OCL_ALL_CHANNELS, Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Norm, Combine(OCL_ABSOLUTELY_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, Sqrt, Combine(::testing::Values(CV_32F, CV_64F), OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, Normalize, Combine(OCL_ALL_DEPTHS, Values(Channels(1)), Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, InRange, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool(), Bool())); diff --git a/modules/ts/include/opencv2/ts/ocl_test.hpp b/modules/ts/include/opencv2/ts/ocl_test.hpp index 4149962155..230ba86280 100644 --- a/modules/ts/include/opencv2/ts/ocl_test.hpp +++ b/modules/ts/include/opencv2/ts/ocl_test.hpp @@ -371,6 +371,7 @@ IMPLEMENT_PARAM_CLASS(Channels, int) #define OCL_ON(...) cv::ocl::setUseOpenCL(true); __VA_ARGS__ ; #define OCL_ALL_DEPTHS Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F) +#define OCL_ABSOLUTELY_ALL_DEPTHS Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32U, CV_64S, CV_64U, CV_16F, CV_16BF, CV_32F, CV_64F, CV_Bool) //, CV_16F, CV_16BF, CV_64U, CV_64S, CV_32U) #define OCL_ALL_DEPTHS_16F Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, CV_16F) #define OCL_ALL_CHANNELS Values(1, 2, 3, 4) diff --git a/modules/ts/src/ts_func.cpp b/modules/ts/src/ts_func.cpp index 7ead775fe3..69fa3353cb 100644 --- a/modules/ts/src/ts_func.cpp +++ b/modules/ts/src/ts_func.cpp @@ -86,9 +86,14 @@ double getMinVal(int depth) { depth = CV_MAT_DEPTH(depth); double val = depth == CV_8U ? 0 : depth == CV_8S ? SCHAR_MIN : depth == CV_16U ? 0 : - depth == CV_16S ? SHRT_MIN : depth == CV_32S ? INT_MIN : - depth == CV_32F ? -FLT_MAX : depth == CV_64F ? -DBL_MAX : - depth == CV_16F ? -65504 + depth == CV_16S ? SHRT_MIN : depth == CV_32S ? INT_MIN : + depth == CV_32F ? -FLT_MAX : depth == CV_64F ? -DBL_MAX : + depth == CV_16F ? -65504 : + depth == CV_16BF ? -FLT_MAX : + depth == CV_32U ? 0 : + depth == CV_64U ? 0 : + depth == CV_64S ? (double)0x8000000000000000LL : + depth == CV_Bool ? 0 : -1; CV_Assert(val != -1); return val; @@ -98,9 +103,14 @@ double getMaxVal(int depth) { depth = CV_MAT_DEPTH(depth); double val = depth == CV_8U ? UCHAR_MAX : depth == CV_8S ? SCHAR_MAX : depth == CV_16U ? USHRT_MAX : - depth == CV_16S ? SHRT_MAX : depth == CV_32S ? INT_MAX : - depth == CV_32F ? FLT_MAX : depth == CV_64F ? DBL_MAX : - depth == CV_16F ? 65504 + depth == CV_16S ? SHRT_MAX : depth == CV_32S ? INT_MAX : + depth == CV_32F ? FLT_MAX : depth == CV_64F ? DBL_MAX : + depth == CV_16F ? 65504 : + depth == CV_16BF ? FLT_MAX : + depth == CV_32U ? UINT_MAX : + depth == CV_64U ? (double)0xFFFFFFFFFFFFFFFFULL : + depth == CV_64S ? (double)0x7fffffffffffffffLL : + depth == CV_Bool ? 1 : -1; CV_Assert(val != -1); return val;