1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge pull request #24271 from Kumataro:fix24163

Fix to convert float32 to int32/uint32 with rounding to nearest (ties to even). #24271

Fix https://github.com/opencv/opencv/issues/24163

### 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

(carotene is BSD)
This commit is contained in:
Kumataro
2023-12-25 18:17:17 +09:00
committed by GitHub
parent d9d402916a
commit dba7186378
13 changed files with 323 additions and 164 deletions
@@ -1990,11 +1990,9 @@ inline v_int32x4 v_round(const v_float32x4& a)
#else
inline v_int32x4 v_round(const v_float32x4& a)
{
static const int32x4_t v_sign = vdupq_n_s32(1 << 31),
v_05 = vreinterpretq_s32_f32(vdupq_n_f32(0.5f));
int32x4_t v_addition = vorrq_s32(v_05, vandq_s32(v_sign, vreinterpretq_s32_f32(a.val)));
return v_int32x4(vcvtq_s32_f32(vaddq_f32(a.val, vreinterpretq_f32_s32(v_addition))));
// See https://github.com/opencv/opencv/pull/24271#issuecomment-1867318007
float32x4_t delta = vdupq_n_f32(12582912.0f);
return v_int32x4(vcvtq_s32_f32(vsubq_f32(vaddq_f32(a.val, delta), delta)));
}
#endif
inline v_int32x4 v_floor(const v_float32x4& a)
+50
View File
@@ -1570,4 +1570,54 @@ TEST(Core_Arithm, scalar_handling_19599) // https://github.com/opencv/opencv/is
EXPECT_EQ(1, c.rows);
}
// https://github.com/opencv/opencv/issues/24163
typedef tuple<perf::MatDepth,int,int,int> Arith_Regression24163Param;
typedef testing::TestWithParam<Arith_Regression24163Param> Core_Arith_Regression24163;
#if defined __riscv
TEST_P(Core_Arith_Regression24163, DISABLED_test_for_ties_to_even)
#else
TEST_P(Core_Arith_Regression24163, test_for_ties_to_even)
#endif
{
const int matDepth = get<0>(GetParam());
const int matHeight= get<1>(GetParam());
const int matWidth = 3; // Fixed
const int alpha = get<2>(GetParam());
const int beta = get<3>(GetParam());
// If alpha and/or beta are negative, and matDepth is unsigned, test is passed.
if( ( (alpha < 0) || (beta < 0) )
&&
( (matDepth != CV_8S) && (matDepth != CV_16S) && (matDepth != CV_32S) ) )
{
throw SkipTestException( cv::format("Test is skipped(matDepth is not signed, alpha = %d, beta = %d)", alpha, beta) );
}
const int matType = CV_MAKE_TYPE(matDepth, 1);
const Size matSize(matWidth, matHeight);
const Mat src1(matSize, matType, Scalar(alpha,alpha,alpha,alpha));
const Mat src2(matSize, matType, Scalar(beta, beta, beta, beta));
const Mat result = ( src1 + src2 ) / 2;
// Expected that default is FE_TONEAREST(Ties to Even).
const int mean = lrint( static_cast<double>(alpha + beta) / 2.0 );
const Mat expected(matSize, matType, Scalar(mean,mean,mean,mean));
// Compare result and extected.
ASSERT_EQ(expected.size(), result.size());
EXPECT_EQ(0, cvtest::norm(expected, result, NORM_INF)) <<
"result=" << std::endl << result << std::endl <<
"expected=" << std::endl << expected;
}
INSTANTIATE_TEST_CASE_P(/* */, Core_Arith_Regression24163,
testing::Combine(
testing::Values(perf::MatDepth(CV_8U), CV_8S, CV_16U, CV_16S, CV_32S), // MatType
testing::Values( 3, 4, 5, 6), // MatHeight
testing::Values(-2,-1, 0, 1, 2), // src1
testing::Values( -1, 0, 1 ) // src2
)
);
}} // namespace