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

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2026-05-25 16:29:45 +03:00
54 changed files with 523 additions and 414 deletions
+9 -3
View File
@@ -708,9 +708,15 @@ __CV_ENUM_FLAGS_BITWISE_XOR_EQ (EnumType, EnumType)
#endif
#if defined(__clang__) || defined(__GNUC__)
#define CV_DISABLE_UBSAN __attribute__((no_sanitize("undefined")))
#else
#define CV_DISABLE_UBSAN
# if defined(__has_attribute)
# if __has_attribute(no_sanitize)
# define CV_DISABLE_UBSAN __attribute__((no_sanitize("undefined")))
# endif
# endif
#endif
#ifndef CV_DISABLE_UBSAN
# define CV_DISABLE_UBSAN
#endif
/****************************************************************************************\
@@ -2620,23 +2620,25 @@ inline v_float32 v_matmul(const v_float32& v, const v_float32& mat0,
const v_float32& mat1, const v_float32& mat2,
const v_float32& mat3)
{
vfloat32m2_t res;
res = __riscv_vfmul_vf_f32m2(mat0, v_extract_n(v, 0), VTraits<v_float32>::vlanes());
res = __riscv_vfmacc_vf_f32m2(res, v_extract_n(v, 1), mat1, VTraits<v_float32>::vlanes());
res = __riscv_vfmacc_vf_f32m2(res, v_extract_n(v, 2), mat2, VTraits<v_float32>::vlanes());
res = __riscv_vfmacc_vf_f32m2(res, v_extract_n(v, 3), mat3, VTraits<v_float32>::vlanes());
return res;
const int vl = VTraits<v_float32>::vlanes();
vuint32m2_t idx = __riscv_vand(__riscv_vid_v_u32m2(vl), 0xfffffffc, vl);
v_float32 v0 = __riscv_vrgather(v, idx, vl);
v_float32 v1 = __riscv_vrgather(v, __riscv_vadd(idx, 1, vl), vl);
v_float32 v2 = __riscv_vrgather(v, __riscv_vadd(idx, 2, vl), vl);
v_float32 v3 = __riscv_vrgather(v, __riscv_vadd(idx, 3, vl), vl);
return v_fma(v0, mat0, v_fma(v1, mat1, v_fma(v2, mat2, v_mul(v3, mat3))));
}
// TODO: only 128 bit now.
inline v_float32 v_matmuladd(const v_float32& v, const v_float32& mat0,
const v_float32& mat1, const v_float32& mat2,
const v_float32& a)
{
vfloat32m2_t res = __riscv_vfmul_vf_f32m2(mat0, v_extract_n(v,0), VTraits<v_float32>::vlanes());
res = __riscv_vfmacc_vf_f32m2(res, v_extract_n(v,1), mat1, VTraits<v_float32>::vlanes());
res = __riscv_vfmacc_vf_f32m2(res, v_extract_n(v,2), mat2, VTraits<v_float32>::vlanes());
return __riscv_vfadd(res, a, VTraits<v_float32>::vlanes());
const int vl = VTraits<v_float32>::vlanes();
vuint32m2_t idx = __riscv_vand(__riscv_vid_v_u32m2(vl), 0xfffffffc, vl);
v_float32 v0 = __riscv_vrgather(v, idx, vl);
v_float32 v1 = __riscv_vrgather(v, __riscv_vadd(idx, 1, vl), vl);
v_float32 v2 = __riscv_vrgather(v, __riscv_vadd(idx, 2, vl), vl);
return v_fma(v0, mat0, v_fma(v1, mat1, v_fma(v2, mat2, a)));
}
inline void v_cleanup() {}
+19 -7
View File
@@ -1820,12 +1820,18 @@ public class CoreTest extends OpenCVTestCase {
assertGE(1e-6, Math.abs(Core.solvePoly(coeffs, roots)));
truth = new Mat(3, 1, CvType.CV_32FC2) {
List<Mat> rootsReIm = new ArrayList<Mat>();
Core.split(roots, rootsReIm);
Core.sort(rootsReIm.get(0), dst, Core.SORT_EVERY_COLUMN);
Mat truthRe = new Mat(3, 1, CvType.CV_32F) {
{
put(0, 0, 1, 0, 2, 0, 3, 0);
put(0, 0, 1, 2, 3);
}
};
assertMatEqual(truth, roots, EPS);
Mat truthIm = Mat.zeros(3, 1, CvType.CV_32F);
assertMatEqual(truthRe, dst, EPS);
assertMatEqual(truthIm, rootsReIm.get(1), EPS);
}
public void testSolvePolyMatMatInt() {
@@ -1836,14 +1842,20 @@ public class CoreTest extends OpenCVTestCase {
};
Mat roots = new Mat();
assertEquals(10.198039027185569, Core.solvePoly(coeffs, roots, 1));
assertGE(1e-6, Core.solvePoly(coeffs, roots, 10));
truth = new Mat(3, 1, CvType.CV_32FC2) {
List<Mat> rootsReIm = new ArrayList<Mat>();
Core.split(roots, rootsReIm);
Core.sort(rootsReIm.get(0), dst, Core.SORT_EVERY_COLUMN);
Mat truthRe = new Mat(3, 1, CvType.CV_32F) {
{
put(0, 0, 1, 0, -1, 2, -2, 12);
put(0, 0, 1, 2, 3);
}
};
assertMatEqual(truth, roots, EPS);
Mat truthIm = Mat.zeros(3, 1, CvType.CV_32F);
assertMatEqual(truthRe, dst, EPS);
assertMatEqual(truthIm, rootsReIm.get(1), EPS);
}
public void testSort() {
+34 -1
View File
@@ -1585,7 +1585,40 @@ double cv::solvePoly( InputArray _coeffs0, OutputArray _roots0, int maxIters )
break;
}
C p(1, 0), r(1, 1);
// Related issue: https://github.com/opencv/opencv/issues/23644,
// This the initialization scheme of "Initial approximations in Durand-Kerner's root finding method" by Guggenheimer.
// https://link.springer.com/article/10.1007/BF01935059
// We put the initial points equidistantly on a circle on the complex plane. This code computes the circle radius as in the paper.
Mat absCoeffs(n + 1, 1, CV_64F);
for( i = 0; i <= n; i++ )
absCoeffs.at<double>(i) = abs(coeffs[i]);
int nonZeroCoeffs = 0;
Mat u(n, 1, CV_64F, Scalar(0)), v(n, 1, CV_64F, Scalar(0));
for( i = 0; i <= n; i++ )
{
double coeff = absCoeffs.at<double>(i);
if( coeff > DBL_EPSILON )
{
if( i != n )
u.at<double>(i) = 2.0 * pow(coeff / absCoeffs.at<double>(n), 1.0 / (n - i));
if( i != 0 )
v.at<double>(i - 1) = 0.5 * pow(absCoeffs.at<double>(0) / coeff, 1.0 / i);
nonZeroCoeffs++;
}
}
double scale = 1;
if( nonZeroCoeffs > 2 )
{
Point maxU, minV;
minMaxLoc(u, nullptr, nullptr, nullptr, &maxU);
minMaxLoc(v, nullptr, nullptr, &minV);
u.at<double>(maxU) = 0;
v.at<double>(minV) = 0;
scale = (sum(u).val[0] + sum(v).val[0]) / (2 * nonZeroCoeffs - 2);
}
C p(scale, 0), r(cos(CV_2PI / n), sin(CV_2PI / n));
for( i = 0; i < n; i++ )
{
+1 -2
View File
@@ -1596,8 +1596,7 @@ static void
transform_32f( const float* src, float* dst, const float* m, int len, int scn, int dcn )
{
// Disabled for RISC-V Vector (scalable), because of:
// 1. v_matmuladd for RVV is 128-bit only but not scalable, this will fail the test `Core_Transform.accuracy`.
// 2. Both gcc and clang can autovectorize this, with better performance than using Universal intrinsic.
// 1. Both gcc and clang can autovectorize this, with better performance than using Universal intrinsic.
#if (CV_SIMD || CV_SIMD_SCALABLE) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(_M_ARM64EC) && !(CV_TRY_RVV && CV_RVV)
int x = 0;
if( scn == 3 && dcn == 3 )
+1 -1
View File
@@ -1283,7 +1283,7 @@ struct MaskedNormInf_SIMD<float, float> {
v_float32 acc = vx_setzero_f32();
for (; i <= len - vstep; i += vstep) {
v_uint32 m = v_reinterpret_as_u32(vx_load_expand(mask + i));
v_uint32 m = vx_load_expand_q(mask + i);
v_uint32 cmp = v_gt(m, vx_setzero_u32());
v_float32 s = vx_load(src + i);
s = v_abs(s);
+6 -8
View File
@@ -1570,9 +1570,8 @@ template<typename R> struct TheTest
R v = dataV, a = dataA, b = dataB, c = dataC, d = dataD;
Data<R> res = v_matmul(v, a, b, c, d);
// for (int i = 0; i < VTraits<R>::vlanes(); i += 4)
// {
int i = 0;
for (int i = 0; i < VTraits<R>::vlanes(); i += 4)
{
for (int j = i; j < i + 4; ++j)
{
SCOPED_TRACE(cv::format("i=%d j=%d", i, j));
@@ -1582,12 +1581,11 @@ template<typename R> struct TheTest
+ dataV[i + 3] * dataD[j];
EXPECT_COMPARE_EQ(val, res[j]);
}
// }
}
Data<R> resAdd = v_matmuladd(v, a, b, c, d);
// for (int i = 0; i < VTraits<R>::vlanes(); i += 4)
// {
i = 0;
for (int i = 0; i < VTraits<R>::vlanes(); i += 4)
{
for (int j = i; j < i + 4; ++j)
{
SCOPED_TRACE(cv::format("i=%d j=%d", i, j));
@@ -1597,7 +1595,7 @@ template<typename R> struct TheTest
+ dataD[j];
EXPECT_COMPARE_EQ(val, resAdd[j]);
}
// }
}
return *this;
}
+87
View File
@@ -1978,6 +1978,93 @@ TEST(Core_SolvePoly, regression_5599)
}
}
TEST(Core_SolvePoly, regression_23644)
{
// x^2 - 2x - 3 = 0, roots: 3, -1
cv::Mat coefs = (cv::Mat_<float>(1,3) << -3, -2, 1 );
cv::Mat r;
double prec;
prec = cv::solvePoly(coefs, r);
EXPECT_LE(prec, 1e-6);
EXPECT_EQ(2u, r.total());
ASSERT_EQ(CV_32FC2, r.type());
checkRoot<float>(r, 3, 0);
checkRoot<float>(r, -1, 0);
}
TEST(Core_SolvePoly, degree_2_polynomials)
{
cv::Mat_<float> coefs(1,3);
cv::Mat r;
double prec;
for (float c0 = -20; c0 <= 20; c0++)
{
coefs.at<float>(0) = c0;
for (float c1 = -20; c1 <= 20; c1++)
{
coefs.at<float>(1) = c1;
for (float c2 = -20; c2 <= 20; c2++)
{
coefs.at<float>(2) = c2;
prec = cv::solvePoly(coefs, r);
EXPECT_LE(prec, 1e-6);
}
}
}
}
TEST(Core_SolvePoly, degree_4_polynomials)
{
applyTestTag(CV_TEST_TAG_VERYLONG);
cv::Mat_<float> coefs(1,5);
cv::Mat r;
double prec;
for (float c0 = -10; c0 <= 10; c0++)
{
coefs.at<float>(0) = c0;
for (float c1 = -10; c1 <= 10; c1++)
{
coefs.at<float>(1) = c1;
for (float c2 = -10; c2 <= 10; c2++)
{
coefs.at<float>(2) = c2;
for (float c3 = -10; c3 <= 10; c3++)
{
coefs.at<float>(3) = c3;
for (float c4 = -10; c4 <= 10; c4++)
{
coefs.at<float>(4) = c4;
prec = cv::solvePoly(coefs, r);
EXPECT_LE(prec, 1e-3);
}
}
}
}
}
}
TEST(Core_SolvePoly, different_magnitudes_polynomials)
{
cv::Mat_<float> coefs(1,3);
cv::Mat r;
double prec;
for (float i = -10; i < 10; i++)
{
coefs.at<float>(0) = pow(2.f, i);
for (float j = -10; j < 10; j++)
{
coefs.at<float>(1) = pow(2.f, j);
for (float k = -10; k < 10; k++)
{
coefs.at<float>(2) = pow(2.f, k);
prec = cv::solvePoly(coefs, r);
EXPECT_LE(prec, 1e-6);
}
}
}
}
class Core_PhaseTest : public cvtest::BaseTest
{
int t;