1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Extended several core functions to support new types (#24962)

* started adding support for new types (16f, 16bf, 32u, 64u, 64s) to arithmetic functions

* fixed several tests; refactored and extended sum(), extended inRange().

* extended countNonZero(), mean(), meanStdDev(), minMaxIdx(), norm() and sum() to support new types (F16, BF16, U32, U64, S64)

* put missing CV_DEPTH_MAX to some function dispatcher tables
* extended findnonzero, hasnonzero with the new types support

* extended mixChannels() to support new types

* minor fix

* fixed a few compile errors on Linux and a few failures in core tests

* fixed a few more warnings and test failures

* trying to fix the remaining warnings and test failures. The test `MulTestGPU.MathOpTest` was disabled - not clear whether to set tolerance - it's not bit-exact operation, as possibly assumed by the test, due to the use of scale and possibly limited accuracy of the intermediate floating-point calculations.

* found that in the current snapshot G-API produces incorrect results in Mul, Div and AddWeighted (at least when using OpenCL on Windows x64 or MacOS x64). Disabled the respective tests.
This commit is contained in:
Vadim Pisarevsky
2024-02-11 10:42:41 +03:00
committed by GitHub
parent f05ef64df8
commit 1d18aba587
45 changed files with 3286 additions and 4706 deletions
+105 -41
View File
@@ -104,7 +104,12 @@ static const _OutputArray::DepthMask baseArithmTypeMask =
_OutputArray::DEPTH_MASK_16S |
_OutputArray::DEPTH_MASK_32S |
_OutputArray::DEPTH_MASK_32F |
_OutputArray::DEPTH_MASK_64F);
_OutputArray::DEPTH_MASK_64F |
_OutputArray::DEPTH_MASK_16F |
_OutputArray::DEPTH_MASK_16BF |
_OutputArray::DEPTH_MASK_32U |
_OutputArray::DEPTH_MASK_64U |
_OutputArray::DEPTH_MASK_64S );
struct BaseArithmOp : public BaseElemWiseOp
{
@@ -134,6 +139,11 @@ struct BaseAddOp : public BaseArithmOp
else
cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, dst, src[0].type());
}
double getMaxErr(int depth)
{
return depth == CV_16BF ? 1e-2 : depth == CV_16F ? 1e-3 : depth == CV_32F ? 1e-4 : depth == CV_64F ? 1e-12 : 2;
}
};
@@ -198,7 +208,7 @@ struct ScaleAddOp : public BaseAddOp
}
double getMaxErr(int depth)
{
return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-4 : 1e-12;
return depth == CV_16BF ? 1e-2 : depth == CV_16F ? 1e-3 : depth == CV_32F ? 1e-4 : depth == CV_64F ? 1e-12 : 2;
}
};
@@ -212,7 +222,7 @@ struct AddWeightedOp : public BaseAddOp
}
double getMaxErr(int depth)
{
return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-10;
return depth == CV_64F ? 1e-9 : BaseAddOp::getMaxErr(depth);
}
};
@@ -234,10 +244,6 @@ struct MulOp : public BaseArithmOp
{
cvtest::multiply(src[0], src[1], dst, alpha);
}
double getMaxErr(int depth)
{
return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
}
};
struct DivOp : public BaseArithmOp
@@ -251,10 +257,6 @@ struct DivOp : public BaseArithmOp
{
cvtest::divide(src[0], src[1], dst, alpha);
}
double getMaxErr(int depth)
{
return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
}
};
struct RecipOp : public BaseArithmOp
@@ -268,10 +270,6 @@ struct RecipOp : public BaseArithmOp
{
cvtest::divide(Mat(), src[0], dst, alpha);
}
double getMaxErr(int depth)
{
return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
}
};
struct AbsDiffOp : public BaseAddOp
@@ -466,7 +464,7 @@ struct CmpSOp : public BaseArithmOp
{
BaseElemWiseOp::generateScalars(depth, rng);
cmpop = rng.uniform(0, 6);
if( depth < CV_32F )
if( depth != CV_16F && depth != CV_16BF && depth != CV_32F && depth != CV_64F )
gamma[0] = cvRound(gamma[0]);
}
void op(const vector<Mat>& src, Mat& dst, const Mat&)
@@ -532,27 +530,29 @@ struct SetOp : public BaseElemWiseOp
}
};
template<typename _Tp, typename _WTp> static void
template<typename _Tp, typename _WTp=_Tp> static void
inRangeS_(const _Tp* src, const _WTp* a, const _WTp* b, uchar* dst, size_t total, int cn)
{
size_t i;
int c;
for( i = 0; i < total; i++ )
{
_Tp val = src[i*cn];
_WTp val = (_WTp)src[i*cn];
dst[i] = (a[0] <= val && val <= b[0]) ? uchar(255) : 0;
}
for( c = 1; c < cn; c++ )
{
for( i = 0; i < total; i++ )
{
_Tp val = src[i*cn + c];
_WTp val = (_WTp)src[i*cn + c];
dst[i] = a[c] <= val && val <= b[c] ? dst[i] : 0;
}
}
}
template<typename _Tp> static void inRange_(const _Tp* src, const _Tp* a, const _Tp* b, uchar* dst, size_t total, int cn)
template<typename _Tp, typename _WTp=_Tp> static void
inRange_(const _Tp* src, const _Tp* a, const _Tp* b,
uchar* dst, size_t total, int cn)
{
size_t i;
int c;
@@ -607,15 +607,32 @@ static void inRange(const Mat& src, const Mat& lb, const Mat& rb, Mat& dst)
case CV_16S:
inRange_((const short*)sptr, (const short*)aptr, (const short*)bptr, dptr, total, cn);
break;
case CV_32U:
inRange_((const unsigned*)sptr, (const unsigned*)aptr, (const unsigned*)bptr, dptr, total, cn);
break;
case CV_32S:
inRange_((const int*)sptr, (const int*)aptr, (const int*)bptr, dptr, total, cn);
break;
case CV_64U:
inRange_((const uint64*)sptr, (const uint64*)aptr, (const uint64*)bptr, dptr, total, cn);
break;
case CV_64S:
inRange_((const int64*)sptr, (const int64*)aptr, (const int64*)bptr, dptr, total, cn);
break;
case CV_32F:
inRange_((const float*)sptr, (const float*)aptr, (const float*)bptr, dptr, total, cn);
break;
case CV_64F:
inRange_((const double*)sptr, (const double*)aptr, (const double*)bptr, dptr, total, cn);
break;
case CV_16F:
inRange_<cv::float16_t, float>((const cv::float16_t*)sptr, (const cv::float16_t*)aptr,
(const cv::float16_t*)bptr, dptr, total, cn);
break;
case CV_16BF:
inRange_<cv::bfloat16_t, float>((const cv::bfloat16_t*)sptr, (const cv::bfloat16_t*)aptr,
(const cv::bfloat16_t*)bptr, dptr, total, cn);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
@@ -632,8 +649,9 @@ static void inRangeS(const Mat& src, const Scalar& lb, const Scalar& rb, Mat& ds
size_t total = planes[0].total();
size_t i, nplanes = it.nplanes;
int depth = src.depth(), cn = src.channels();
union { double d[4]; float f[4]; int i[4];} lbuf, rbuf;
int wtype = CV_MAKETYPE(depth <= CV_32S ? CV_32S : depth, cn);
union { double d[4]; float f[4]; int i[4]; unsigned u[4]; int64 L[4]; uint64 UL[4]; } lbuf, rbuf;
int wtype = CV_MAKETYPE((depth <= CV_32S ? CV_32S :
depth == CV_16F || depth == CV_16BF || depth == CV_32F ? CV_32F : depth), cn);
scalarToRawData(lb, lbuf.d, wtype, cn);
scalarToRawData(rb, rbuf.d, wtype, cn);
@@ -656,15 +674,30 @@ static void inRangeS(const Mat& src, const Scalar& lb, const Scalar& rb, Mat& ds
case CV_16S:
inRangeS_((const short*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
break;
case CV_32U:
inRangeS_((const unsigned*)sptr, lbuf.u, rbuf.u, dptr, total, cn);
break;
case CV_32S:
inRangeS_((const int*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
break;
case CV_64U:
inRangeS_((const uint64*)sptr, lbuf.UL, rbuf.UL, dptr, total, cn);
break;
case CV_64S:
inRangeS_((const int64*)sptr, lbuf.L, rbuf.L, dptr, total, cn);
break;
case CV_32F:
inRangeS_((const float*)sptr, lbuf.f, rbuf.f, dptr, total, cn);
break;
case CV_64F:
inRangeS_((const double*)sptr, lbuf.d, rbuf.d, dptr, total, cn);
break;
case CV_16F:
inRangeS_((const cv::float16_t*)sptr, lbuf.f, rbuf.f, dptr, total, cn);
break;
case CV_16BF:
inRangeS_((const cv::bfloat16_t*)sptr, lbuf.f, rbuf.f, dptr, total, cn);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
@@ -1318,9 +1351,9 @@ struct SumOp : public BaseArithmOp
dst.create(1, 1, CV_64FC4);
dst.at<Scalar>(0,0) = cvtest::mean(src[0])*(double)src[0].total();
}
double getMaxErr(int)
double getMaxErr(int depth)
{
return 1e-5;
return depth == CV_16F || depth == CV_16BF ? 1e-3 : 1e-5;
}
};
@@ -1441,9 +1474,10 @@ struct NormOp : public BaseArithmOp
void generateScalars(int, RNG& /*rng*/)
{
}
double getMaxErr(int)
double getMaxErr(int depth)
{
return 1e-6;
return normType == NORM_INF && depth <= CV_32S ? 0 :
depth == CV_16F || depth == CV_16BF ? 1e-5 : 1e-6;
}
int normType;
};
@@ -1604,10 +1638,15 @@ TEST_P(ElemWiseTest, accuracy)
}
op->generateScalars(depth, rng);
/*printf("testIdx=%d, depth=%d, channels=%d, have_mask=%d\n", testIdx, depth, src[0].channels(), (int)haveMask);
if (testIdx == 22)
printf(">>>\n");*/
op->refop(src, dst0, mask);
op->op(src, dst, mask);
double maxErr = op->getMaxErr(depth);
ASSERT_PRED_FORMAT2(cvtest::MatComparator(maxErr, op->context), dst0, dst) << "\nsrc[0] ~ " <<
cvtest::MatInfo(!src.empty() ? src[0] : Mat()) << "\ntestCase #" << testIdx << "\n";
}
@@ -2067,6 +2106,31 @@ TEST(Core_FindNonZero, regression)
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_32U );
pts.resize(pts.size()*3);
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_64U );
pts.resize(pts.size()*2);
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_64S );
pts.resize(pts.size()*5);
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_16F );
pts.resize(pts.size()*3);
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_16BF );
pts.resize(pts.size()*4);
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_32F );
pts.resize(pts.size()*5);
findNonZero(img, pts);
@@ -2207,7 +2271,7 @@ TEST(Compare, regression_16F_do_not_crash)
cv::Mat mat1(2, 2, CV_16F, cv::Scalar(1));
cv::Mat mat2(2, 2, CV_16F, cv::Scalar(2));
cv::Mat dst;
EXPECT_THROW(cv::compare(mat1, mat2, dst, cv::CMP_EQ), cv::Exception);
EXPECT_NO_THROW(cv::compare(mat1, mat2, dst, cv::CMP_EQ));
}
@@ -3034,30 +3098,30 @@ INSTANTIATE_TEST_CASE_P(Core_FiniteMask, FiniteMaskFixture, ::testing::Combine(:
///////////////////////////////////////////////////////////////////////////////////
typedef testing::TestWithParam<perf::MatDepth> NonZeroNotSupportedMatDepth;
typedef testing::TestWithParam<perf::MatDepth> NonZeroSupportedMatDepth;
TEST_P(NonZeroNotSupportedMatDepth, findNonZero)
TEST_P(NonZeroSupportedMatDepth, findNonZero)
{
cv::Mat src = cv::Mat(16,16, CV_MAKETYPE(GetParam(), 1));
vector<Point> pts;
EXPECT_THROW( findNonZero(src, pts), cv::Exception);
EXPECT_NO_THROW(findNonZero(src, pts));
}
TEST_P(NonZeroNotSupportedMatDepth, countNonZero)
TEST_P(NonZeroSupportedMatDepth, countNonZero)
{
cv::Mat src = cv::Mat(16,16, CV_MAKETYPE(GetParam(), 1));
EXPECT_THROW( countNonZero(src), cv::Exception);
EXPECT_NO_THROW(countNonZero(src));
}
TEST_P(NonZeroNotSupportedMatDepth, hasNonZero)
TEST_P(NonZeroSupportedMatDepth, hasNonZero)
{
cv::Mat src = cv::Mat(16,16, CV_MAKETYPE(GetParam(), 1));
EXPECT_THROW( hasNonZero(src), cv::Exception);
EXPECT_NO_THROW(hasNonZero(src));
}
INSTANTIATE_TEST_CASE_P(
NonZero,
NonZeroNotSupportedMatDepth,
NonZeroSupportedMatDepth,
testing::Values(perf::MatDepth(CV_16F), CV_16BF, CV_Bool, CV_64U, CV_64S, CV_32U)
);
@@ -3079,27 +3143,27 @@ INSTANTIATE_TEST_CASE_P(
);
///////////////////////////////////////////////////////////////////////////////////
typedef testing::TestWithParam<perf::MatDepth> MinMaxNotSupportedMatDepth;
typedef testing::TestWithParam<perf::MatDepth> MinMaxSupportedMatDepth;
TEST_P(MinMaxNotSupportedMatDepth, minMaxLoc)
TEST_P(MinMaxSupportedMatDepth, minMaxLoc)
{
cv::Mat src = cv::Mat(16,16, CV_MAKETYPE(GetParam(), 1));
double minV=0.0, maxV=0.0;
Point minLoc, maxLoc;
EXPECT_THROW( cv::minMaxLoc(src, &minV, &maxV, &minLoc, &maxLoc), cv::Exception);
EXPECT_NO_THROW(cv::minMaxLoc(src, &minV, &maxV, &minLoc, &maxLoc));
}
TEST_P(MinMaxNotSupportedMatDepth, minMaxIdx)
TEST_P(MinMaxSupportedMatDepth, minMaxIdx)
{
cv::Mat src = cv::Mat(16,16, CV_MAKETYPE(GetParam(), 1));
double minV=0.0, maxV=0.0;
int minIdx=0, maxIdx=0;
EXPECT_THROW( cv::minMaxIdx(src, &minV, &maxV, &minIdx, &maxIdx), cv::Exception);
EXPECT_NO_THROW(cv::minMaxIdx(src, &minV, &maxV, &minIdx, &maxIdx));
}
INSTANTIATE_TEST_CASE_P(
MinMaxLoc,
MinMaxNotSupportedMatDepth,
MinMaxSupportedMatDepth,
testing::Values(perf::MatDepth(CV_16F), CV_16BF, CV_Bool, CV_64U, CV_64S, CV_32U)
);