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

Merge pull request #23098 from savuor:nanMask

finiteMask() and doubles for patchNaNs() #23098

Related to #22826
Connected PR in extra: [#1037@extra](https://github.com/opencv/opencv_extra/pull/1037)

### TODOs:
- [ ] Vectorize `finiteMask()` for 64FC3 and 64FC4

### Changes

This PR:
* adds a new function `finiteMask()`
* extends `patchNaNs()` by CV_64F support
* moves `patchNaNs()` and `finiteMask()` to a separate file

**NOTE:** now the function is called `finiteMask()` as discussed with the OpenCV core team

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [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:
Rostislav Vasilikhin
2023-11-09 08:32:47 +01:00
committed by GitHub
parent 34f34f6227
commit 53aad98a1a
15 changed files with 1190 additions and 138 deletions
+125 -7
View File
@@ -1699,8 +1699,36 @@ OCL_TEST_P(ScaleAdd, Mat)
//////////////////////////////// PatchNans ////////////////////////////////////////////////
PARAM_TEST_CASE(PatchNaNs, Channels, bool)
template<typename _Tp>
_Tp randomNan(RNG& rng);
template<>
float randomNan(RNG& rng)
{
uint32_t r = rng.next();
Cv32suf v;
v.u = r;
// exp & set a bit to avoid zero mantissa
v.u = v.u | 0x7f800001;
return v.f;
}
template<>
double randomNan(RNG& rng)
{
uint32_t r0 = rng.next();
uint32_t r1 = rng.next();
Cv64suf v;
v.u = (uint64_t(r0) << 32) | uint64_t(r1);
// exp &set a bit to avoid zero mantissa
v.u = v.u | 0x7ff0000000000001;
return v.f;
}
PARAM_TEST_CASE(PatchNaNs, MatDepth, Channels, bool)
{
int ftype;
int cn;
bool use_roi;
double value;
@@ -1709,13 +1737,14 @@ PARAM_TEST_CASE(PatchNaNs, Channels, bool)
virtual void SetUp()
{
cn = GET_PARAM(0);
use_roi = GET_PARAM(1);
ftype = GET_PARAM(0);
cn = GET_PARAM(1);
use_roi = GET_PARAM(2);
}
void generateTestData()
{
const int type = CV_MAKE_TYPE(CV_32F, cn);
const int type = CV_MAKE_TYPE(ftype, cn);
Size roiSize = randomSize(1, 10);
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
@@ -1725,9 +1754,19 @@ PARAM_TEST_CASE(PatchNaNs, Channels, bool)
roiSize.width *= cn;
for (int y = 0; y < roiSize.height; ++y)
{
float * const ptr = src_roi.ptr<float>(y);
float *const ptrf = src_roi.ptr<float >(y);
double *const ptrd = src_roi.ptr<double>(y);
for (int x = 0; x < roiSize.width; ++x)
ptr[x] = randomInt(-1, 1) == 0 ? std::numeric_limits<float>::quiet_NaN() : ptr[x];
{
if (ftype == CV_32F)
{
ptrf[x] = randomInt(-1, 1) == 0 ? randomNan<float >(rng) : ptrf[x];
}
else if (ftype == CV_64F)
{
ptrd[x] = randomInt(-1, 1) == 0 ? randomNan<double>(rng) : ptrd[x];
}
}
}
value = randomDouble(-100, 100);
@@ -1754,6 +1793,84 @@ OCL_TEST_P(PatchNaNs, Mat)
}
}
//////////////////////////////// finiteMask /////////////////////////////////////////////
PARAM_TEST_CASE(FiniteMask, MatDepth, Channels, bool)
{
int ftype;
int cn;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(src);
TEST_DECLARE_OUTPUT_PARAMETER(mask);
virtual void SetUp()
{
ftype = GET_PARAM(0);
cn = GET_PARAM(1);
use_roi = GET_PARAM(2);
}
void generateTestData()
{
const int type = CV_MAKE_TYPE(ftype, cn);
Size roiSize = randomSize(1, MAX_VALUE);
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(src, src_roi, roiSize, srcBorder, type, -40, 40);
randomSubMat(mask, mask_roi, roiSize, srcBorder, CV_8UC1, 5, 16);
// generating NaNs
const softfloat fpinf = softfloat ::inf();
const softfloat fninf = softfloat ::inf().setSign(true);
const softdouble dpinf = softdouble::inf();
const softdouble dninf = softdouble::inf().setSign(true);
for (int y = 0; y < roiSize.height; ++y)
{
float *const ptrf = src_roi.ptr<float >(y);
double *const ptrd = src_roi.ptr<double>(y);
for (int x = 0; x < roiSize.width * cn; ++x)
{
int rem = randomInt(0, 10);
if (ftype == CV_32F)
{
ptrf[x] = rem < 4 ? randomNan<float >(rng) :
rem == 5 ? (float )((x + y)%2 ? fpinf : fninf) : ptrf[x];
}
else if (ftype == CV_64F)
{
ptrd[x] = rem < 4 ? randomNan<double>(rng) :
rem == 5 ? (double)((x + y)%2 ? dpinf : dninf) : ptrd[x];
}
}
}
UMAT_UPLOAD_INPUT_PARAMETER(src);
UMAT_UPLOAD_OUTPUT_PARAMETER(mask);
}
void Near()
{
OCL_EXPECT_MATS_NEAR(mask, 0);
}
};
OCL_TEST_P(FiniteMask, Mat)
{
for (int j = 0; j < test_loop_times; j++)
{
generateTestData();
OCL_OFF(cv::finiteMask(src_roi, mask_roi));
OCL_ON(cv::finiteMask(usrc_roi, umask_roi));
Near();
}
}
//////////////////////////////// Psnr ////////////////////////////////////////////////
typedef ArithmTestBase Psnr;
@@ -1928,7 +2045,8 @@ OCL_INSTANTIATE_TEST_CASE_P(Arithm, InRange, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHA
OCL_INSTANTIATE_TEST_CASE_P(Arithm, ConvertScaleAbs, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Arithm, ConvertFp16, Combine(OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Arithm, ScaleAdd, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Arithm, PatchNaNs, Combine(OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Arithm, PatchNaNs, Combine(::testing::Values(CV_32F, CV_64F), OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Arithm, FiniteMask, Combine(::testing::Values(CV_32F, CV_64F), OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Arithm, Psnr, Combine(::testing::Values((MatDepth)CV_8U), OCL_ALL_CHANNELS, Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Arithm, UMatDot, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));