mirror of
https://github.com/opencv/opencv.git
synced 2025-06-11 19:59:08 +08:00
Merge pull request #26400 from vpisarev:fix_fp16_cmp
Fixed FP16 mat comparison in tests #26400 make sure that if both compared FP16/BF16 values are bitwise-equal, assume their difference to be 0 (zero), just like in the case of FP32 and FP64, don't try to compare them as floating-point numbers, because they can be NaN's. **fixes** #24894 - [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
This commit is contained in:
parent
7a5f12c630
commit
853fa9dd40
@ -1369,6 +1369,77 @@ norm_(const _Tp* src1, const _Tp* src2, size_t total, int cn, int normType, doub
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename _Tp, typename _IntTp=_Tp> static double
|
||||
norm_flt_(const _Tp* src1, const _Tp* src2, size_t total, int cn, int normType, double startval, const uchar* mask)
|
||||
{
|
||||
size_t i;
|
||||
double result = startval;
|
||||
const _IntTp* isrc1 = reinterpret_cast<const _IntTp*>(src1);
|
||||
const _IntTp* isrc2 = reinterpret_cast<const _IntTp*>(src2);
|
||||
if( !mask )
|
||||
total *= cn;
|
||||
|
||||
if( normType == NORM_INF )
|
||||
{
|
||||
if( !mask )
|
||||
for( i = 0; i < total; i++ )
|
||||
{
|
||||
if (isrc1[i] != isrc2[i])
|
||||
result = std::max(result, std::abs((double)src1[i] - (double)src2[i]));
|
||||
}
|
||||
else
|
||||
for( int c = 0; c < cn; c++ )
|
||||
{
|
||||
for( i = 0; i < total; i++ )
|
||||
if( mask[i] && isrc1[i*cn + c] != isrc2[i*cn + c] )
|
||||
result = std::max(result, std::abs((double)src1[i*cn + c] - (double)src2[i*cn + c]));
|
||||
}
|
||||
}
|
||||
else if( normType == NORM_L1 )
|
||||
{
|
||||
if( !mask )
|
||||
for( i = 0; i < total; i++ )
|
||||
{
|
||||
if (isrc1[i] != isrc2[i])
|
||||
result += std::abs((double)src1[i] - (double)src2[i]);
|
||||
}
|
||||
else
|
||||
for( int c = 0; c < cn; c++ )
|
||||
{
|
||||
for( i = 0; i < total; i++ )
|
||||
if( mask[i] && isrc1[i*cn + c] != isrc2[i*cn + c] )
|
||||
result += std::abs((double)src1[i*cn + c] - (double)src2[i*cn + c]);
|
||||
}
|
||||
}
|
||||
else if( normType == NORM_L2 )
|
||||
{
|
||||
if( !mask )
|
||||
for( i = 0; i < total; i++ )
|
||||
{
|
||||
if (isrc1[i] != isrc2[i]) {
|
||||
double v = (double)src1[i] - (double)src2[i];
|
||||
result += v*v;
|
||||
}
|
||||
}
|
||||
else
|
||||
for( int c = 0; c < cn; c++ )
|
||||
{
|
||||
for( i = 0; i < total; i++ )
|
||||
if( mask[i] && isrc1[i*cn + c] != isrc2[i*cn + c] )
|
||||
{
|
||||
double v = (double)src1[i*cn + c] - (double)src2[i*cn + c];
|
||||
result += v*v;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Error(Error::StsBadArg, "Unexpected normType value in test");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
double norm(InputArray _src, int normType, InputArray _mask)
|
||||
{
|
||||
@ -1478,13 +1549,6 @@ double norm(InputArray _src, int normType, InputArray _mask)
|
||||
double norm(InputArray _src1, InputArray _src2, int normType, InputArray _mask)
|
||||
{
|
||||
Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat();
|
||||
if( src1.depth() == CV_16F || src1.depth() == CV_16BF )
|
||||
{
|
||||
Mat src1_32f, src2_32f;
|
||||
src1.convertTo(src1_32f, CV_32F);
|
||||
src2.convertTo(src2_32f, CV_32F);
|
||||
return cvtest::norm(src1_32f, src2_32f, normType, _mask);
|
||||
}
|
||||
|
||||
bool isRelative = (normType & NORM_RELATIVE) != 0;
|
||||
normType &= ~NORM_RELATIVE;
|
||||
@ -1569,16 +1633,16 @@ double norm(InputArray _src1, InputArray _src2, int normType, InputArray _mask)
|
||||
result = norm_((const int64*)sptr1, (const int64*)sptr2, total, cn, normType, result, mptr);
|
||||
break;
|
||||
case CV_32F:
|
||||
result = norm_((const float*)sptr1, (const float*)sptr2, total, cn, normType, result, mptr);
|
||||
result = norm_flt_<float, int>((const float*)sptr1, (const float*)sptr2, total, cn, normType, result, mptr);
|
||||
break;
|
||||
case CV_64F:
|
||||
result = norm_((const double*)sptr1, (const double*)sptr2, total, cn, normType, result, mptr);
|
||||
result = norm_flt_<double, int64>((const double*)sptr1, (const double*)sptr2, total, cn, normType, result, mptr);
|
||||
break;
|
||||
case CV_16F:
|
||||
result = norm_((const cv::hfloat*)sptr1, (const cv::hfloat*)sptr2, total, cn, normType, result, mptr);
|
||||
result = norm_flt_<cv::hfloat, short>((const cv::hfloat*)sptr1, (const cv::hfloat*)sptr2, total, cn, normType, result, mptr);
|
||||
break;
|
||||
case CV_16BF:
|
||||
result = norm_((const cv::bfloat*)sptr1, (const cv::bfloat*)sptr2, total, cn, normType, result, mptr);
|
||||
result = norm_flt_<cv::bfloat, short>((const cv::bfloat*)sptr1, (const cv::bfloat*)sptr2, total, cn, normType, result, mptr);
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsUnsupportedFormat, "");
|
||||
@ -2189,14 +2253,6 @@ int cmpEps( const Mat& arr_, const Mat& refarr_, double* _realmaxdiff,
|
||||
{
|
||||
Mat arr = arr_, refarr = refarr_;
|
||||
CV_Assert( arr.type() == refarr.type() && arr.size == refarr.size );
|
||||
if( arr.depth() == CV_16F || arr.depth() == CV_16BF )
|
||||
{
|
||||
Mat arr32f, refarr32f;
|
||||
arr.convertTo(arr32f, CV_32F);
|
||||
refarr.convertTo(refarr32f, CV_32F);
|
||||
arr = arr32f;
|
||||
refarr = refarr32f;
|
||||
}
|
||||
|
||||
int depth = refarr.depth();
|
||||
int ilevel = depth <= CV_32S || depth == CV_32U || depth == CV_64U || depth == CV_64S ? cvFloor(success_err_level) : 0;
|
||||
@ -2253,6 +2309,68 @@ int cmpEps( const Mat& arr_, const Mat& refarr_, double* _realmaxdiff,
|
||||
case CV_64U:
|
||||
realmaxdiff = cmpUlpsInt_((const uint64_t*)sptr1, (const uint64_t*)sptr2, total, ilevel, startidx, idx);
|
||||
break;
|
||||
case CV_16F:
|
||||
for( j = 0; j < total; j++ )
|
||||
{
|
||||
if( ((short*)sptr1)[j] == ((short*)sptr2)[j] )
|
||||
continue;
|
||||
double a_val = (float)((cv::hfloat*)sptr1)[j];
|
||||
double b_val = (float)((cv::hfloat*)sptr2)[j];
|
||||
double threshold;
|
||||
if( cvIsNaN(a_val) || cvIsInf(a_val) )
|
||||
{
|
||||
result = CMP_EPS_INVALID_TEST_DATA;
|
||||
idx = startidx + j;
|
||||
break;
|
||||
}
|
||||
if( cvIsNaN(b_val) || cvIsInf(b_val) )
|
||||
{
|
||||
result = CMP_EPS_INVALID_REF_DATA;
|
||||
idx = startidx + j;
|
||||
break;
|
||||
}
|
||||
a_val = fabs(a_val - b_val);
|
||||
threshold = element_wise_relative_error ? fabs(b_val) + 1 : maxval;
|
||||
if( a_val > threshold*success_err_level )
|
||||
{
|
||||
realmaxdiff = a_val/threshold;
|
||||
if( idx == 0 )
|
||||
idx = startidx + j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CV_16BF:
|
||||
for( j = 0; j < total; j++ )
|
||||
{
|
||||
if( ((short*)sptr1)[j] == ((short*)sptr2)[j] )
|
||||
continue;
|
||||
double a_val = (float)((cv::bfloat*)sptr1)[j];
|
||||
double b_val = (float)((cv::bfloat*)sptr2)[j];
|
||||
double threshold;
|
||||
if( cvIsNaN(a_val) || cvIsInf(a_val) )
|
||||
{
|
||||
result = CMP_EPS_INVALID_TEST_DATA;
|
||||
idx = startidx + j;
|
||||
break;
|
||||
}
|
||||
if( cvIsNaN(b_val) || cvIsInf(b_val) )
|
||||
{
|
||||
result = CMP_EPS_INVALID_REF_DATA;
|
||||
idx = startidx + j;
|
||||
break;
|
||||
}
|
||||
a_val = fabs(a_val - b_val);
|
||||
threshold = element_wise_relative_error ? fabs(b_val) + 1 : maxval;
|
||||
if( a_val > threshold*success_err_level )
|
||||
{
|
||||
realmaxdiff = a_val/threshold;
|
||||
if( idx == 0 )
|
||||
idx = startidx + j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CV_32F:
|
||||
for( j = 0; j < total; j++ )
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user