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

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2026-02-11 13:54:39 +03:00
committed by Alexander Smorkalov
468 changed files with 16647 additions and 11284 deletions
@@ -239,6 +239,10 @@ struct VZeroUpperGuard {
#elif defined(__ARM_NEON)
# include <arm_neon.h>
# define CV_NEON 1
#ifdef __ARM_FEATURE_SVE
# include<arm_sve.h>
# define CV_SVE 1
#endif
#elif defined(__VSX__) && defined(__PPC64__) && defined(__LITTLE_ENDIAN__)
# include <altivec.h>
# undef vector
@@ -369,6 +373,10 @@ struct VZeroUpperGuard {
# define CV_NEON 0
#endif
#ifndef CV_SVE
# define CV_SVE 0
#endif
#ifndef CV_RVV071
# define CV_RVV071 0
#endif
@@ -399,6 +399,27 @@
#endif
#define __CV_CPU_DISPATCH_CHAIN_AVX512_ICL(fn, args, mode, ...) CV_CPU_CALL_AVX512_ICL(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__))
#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_SVE
# define CV_TRY_SVE 1
# define CV_CPU_FORCE_SVE 1
# define CV_CPU_HAS_SUPPORT_SVE 1
# define CV_CPU_CALL_SVE(fn, args) return (cpu_baseline::fn args)
# define CV_CPU_CALL_SVE_(fn, args) return (opt_SVE::fn args)
#elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_SVE
# define CV_TRY_SVE 1
# define CV_CPU_FORCE_SVE 0
# define CV_CPU_HAS_SUPPORT_SVE (cv::checkHardwareSupport(CV_CPU_SVE))
# define CV_CPU_CALL_SVE(fn, args) if (CV_CPU_HAS_SUPPORT_SVE) return (opt_SVE::fn args)
# define CV_CPU_CALL_SVE_(fn, args) if (CV_CPU_HAS_SUPPORT_SVE) return (opt_SVE::fn args)
#else
# define CV_TRY_SVE 0
# define CV_CPU_FORCE_SVE 0
# define CV_CPU_HAS_SUPPORT_SVE 0
# define CV_CPU_CALL_SVE(fn, args)
# define CV_CPU_CALL_SVE_(fn, args)
#endif
#define __CV_CPU_DISPATCH_CHAIN_SVE(fn, args, mode, ...) CV_CPU_CALL_SVE(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__))
#if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_NEON
# define CV_TRY_NEON 1
# define CV_CPU_FORCE_NEON 1
@@ -279,6 +279,7 @@ namespace cv {
#define CV_CPU_NEON_DOTPROD 101
#define CV_CPU_NEON_FP16 102
#define CV_CPU_NEON_BF16 103
#define CV_CPU_SVE 104
#define CV_CPU_MSA 150
@@ -342,6 +343,7 @@ enum CpuFeatures {
CPU_NEON_DOTPROD = 101,
CPU_NEON_FP16 = 102,
CPU_NEON_BF16 = 103,
CPU_SVE = 104,
CPU_MSA = 150,
@@ -81,9 +81,26 @@ CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN
"Universal intrinsics" is a types and functions set intended to simplify vectorization of code on
different platforms. Currently a few different SIMD extensions on different architectures are supported.
128 bit registers of various types support is implemented for a wide range of architectures
including x86(__SSE/SSE2/SSE4.2__), ARM(__NEON__), PowerPC(__VSX__), MIPS(__MSA__).
256 bit long registers are supported on x86(__AVX2__) and 512 bit long registers are supported on x86(__AVX512__).
OpenCV Universal Intrinsics support the following instruction sets:
- *128 bit* registers of various types support is implemented for a wide range of architectures including
- x86(SSE/SSE2/SSE4.2),
- ARM(NEON): 64-bit float (64F) requires AArch64,
- PowerPC(VSX),
- MIPS(MSA),
- LoongArch(LSX),
- RISC-V(RVV 0.7.1): Fixed-length implementation,
- WASM: 64-bit float (64F) is not supported,
- *256 bit* registers are supported on
- x86(AVX2),
- LoongArch (LASX),
- *512 bit* registers are supported on
- x86(AVX512),
- *Vector Length Agnostic (VLA)* registers are supported on
- RISC-V(RVV 1.0)
- ARM(SVE/SVE2): Powered by Arm KleidiCV integration (OpenCV 4.11+),
In case when there is no SIMD extension available during compilation, fallback C++ implementation of intrinsics
will be chosen and code will work as expected although it could be slower.
@@ -988,9 +988,10 @@ inline v_uint32x4 v_dotprod_expand_fast(const v_uint8x16& a, const v_uint8x16& b
inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b)
{
int16x8_t prod = vmull_s8(vget_low_s8(a.val), vget_low_s8(b.val));
prod = vmlal_s8(prod, vget_high_s8(a.val), vget_high_s8(b.val));
return v_int32x4(vaddl_s16(vget_low_s16(prod), vget_high_s16(prod)));
int16x8_t p0 = vmull_s8(vget_low_s8(a.val), vget_low_s8(b.val));
int16x8_t p1 = vmull_s8(vget_high_s8(a.val), vget_high_s8(b.val));
int32x4_t s0 = vaddl_s16(vget_low_s16(p0), vget_low_s16(p1));
return v_int32x4(vaddq_s32(s0, vaddl_s16(vget_high_s16(p0), vget_high_s16(p1))));
}
inline v_int32x4 v_dotprod_expand_fast(const v_int8x16& a, const v_int8x16& b, const v_int32x4& c)
{
+3 -3
View File
@@ -1549,15 +1549,15 @@ public:
/** @overload
* @param cn New number of channels. If the parameter is 0, the number of channels remains the same.
* @param newndims New number of dimentions.
* @param newsz Array with new matrix size by all dimentions. If some sizes are zero,
* @param newndims New number of dimensions.
* @param newsz Array with new matrix size by all dimensions. If some sizes are zero,
* the original sizes in those dimensions are presumed.
*/
Mat reshape(int cn, int newndims, const int* newsz) const;
/** @overload
* @param cn New number of channels. If the parameter is 0, the number of channels remains the same.
* @param newshape Vector with new matrix size by all dimentions. If some sizes are zero,
* @param newshape Vector with new matrix size by all dimensions. If some sizes are zero,
* the original sizes in those dimensions are presumed.
*/
Mat reshape(int cn, const std::vector<int>& newshape) const;
@@ -57,7 +57,7 @@ class QuatEnum
public:
/** @brief Enum of Euler angles type.
*
* Without considering the possibility of using two different convertions for the definition of the rotation axes ,
* Without considering the possibility of using two different conversions for the definition of the rotation axes ,
* there exists twelve possible sequences of rotation axes, divided into two groups:
* - Proper Euler angles (Z-X-Z, X-Y-X, Y-Z-Y, Z-Y-Z, X-Z-X, Y-X-Y)
* - TaitBryan angles (X-Y-Z, Y-Z-X, Z-X-Y, X-Z-Y, Z-Y-X, Y-X-Z).
@@ -273,7 +273,7 @@ public:
* where \f$ q_{X, \theta_1} \f$ is created from @ref createFromXRot, \f$ q_{Y, \theta_2} \f$ is created from @ref createFromYRot,
* \f$ q_{Z, \theta_3} \f$ is created from @ref createFromZRot.
* @param angles the Euler angles in a vector of length 3
* @param eulerAnglesType the convertion Euler angles type
* @param eulerAnglesType the conversion Euler angles type
*/
static Quat<_Tp> createFromEulerAngles(const Vec<_Tp, 3> &angles, QuatEnum::EulerAnglesType eulerAnglesType);
@@ -1610,7 +1610,7 @@ public:
* EXT_ZXZ| \f$ \theta_1 = \arctan2(m_{31},m_{32}) \\\theta_2 = \arccos(m_{33}) \\\theta_3 = \arctan2(-m_{13},m_{23})\f$| \f$ \theta_1=0\\ \theta_2=0\\ \theta_3=\arctan2(m_{21},m_{22}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3=\arctan2(m_{21},m_{11}) \f$
* EXT_ZYZ| \f$ \theta_1 = \arctan2(m_{32},-m_{31})\\\theta_2 = \arccos(m_{33}) \\\theta_3 = \arctan2(m_{23},m_{13}) \f$| \f$ \theta_1=0\\ \theta_2=0\\ \theta_3=\arctan2(m_{21},m_{11}) \f$| \f$ \theta_1= 0\\ \theta_2=\pi\\ \theta_3=\arctan2(m_{21},m_{11}) \f$
*
* @param eulerAnglesType the convertion Euler angles type
* @param eulerAnglesType the conversion Euler angles type
*/
Vec<_Tp, 3> toEulerAngles(QuatEnum::EulerAnglesType eulerAnglesType);
+15 -28
View File
@@ -4,14 +4,10 @@ import java.nio.ByteBuffer;
// C++: class Mat
//javadoc: Mat
public class Mat {
public final long nativeObj;
public class Mat extends CleanableMat {
public Mat(long addr) {
if (addr == 0)
throw new UnsupportedOperationException("Native object address is NULL");
nativeObj = addr;
super(addr);
}
//
@@ -20,7 +16,7 @@ public class Mat {
// javadoc: Mat::Mat()
public Mat() {
nativeObj = n_Mat();
super(n_Mat());
}
//
@@ -29,7 +25,7 @@ public class Mat {
// javadoc: Mat::Mat(rows, cols, type)
public Mat(int rows, int cols, int type) {
nativeObj = n_Mat(rows, cols, type);
super(n_Mat(rows, cols, type));
}
//
@@ -38,7 +34,7 @@ public class Mat {
// javadoc: Mat::Mat(rows, cols, type, data)
public Mat(int rows, int cols, int type, ByteBuffer data) {
nativeObj = n_Mat(rows, cols, type, data);
super(n_Mat(rows, cols, type, data));
}
//
@@ -47,7 +43,7 @@ public class Mat {
// javadoc: Mat::Mat(rows, cols, type, data, step)
public Mat(int rows, int cols, int type, ByteBuffer data, long step) {
nativeObj = n_Mat(rows, cols, type, data, step);
super(n_Mat(rows, cols, type, data, step));
}
//
@@ -56,7 +52,7 @@ public class Mat {
// javadoc: Mat::Mat(size, type)
public Mat(Size size, int type) {
nativeObj = n_Mat(size.width, size.height, type);
super(n_Mat(size.width, size.height, type));
}
//
@@ -65,7 +61,7 @@ public class Mat {
// javadoc: Mat::Mat(sizes, type)
public Mat(int[] sizes, int type) {
nativeObj = n_Mat(sizes.length, sizes, type);
super(n_Mat(sizes.length, sizes, type));
}
//
@@ -74,7 +70,7 @@ public class Mat {
// javadoc: Mat::Mat(rows, cols, type, s)
public Mat(int rows, int cols, int type, Scalar s) {
nativeObj = n_Mat(rows, cols, type, s.val[0], s.val[1], s.val[2], s.val[3]);
super(n_Mat(rows, cols, type, s.val[0], s.val[1], s.val[2], s.val[3]));
}
//
@@ -83,7 +79,7 @@ public class Mat {
// javadoc: Mat::Mat(size, type, s)
public Mat(Size size, int type, Scalar s) {
nativeObj = n_Mat(size.width, size.height, type, s.val[0], s.val[1], s.val[2], s.val[3]);
super(n_Mat(size.width, size.height, type, s.val[0], s.val[1], s.val[2], s.val[3]));
}
//
@@ -92,7 +88,7 @@ public class Mat {
// javadoc: Mat::Mat(sizes, type, s)
public Mat(int[] sizes, int type, Scalar s) {
nativeObj = n_Mat(sizes.length, sizes, type, s.val[0], s.val[1], s.val[2], s.val[3]);
super(n_Mat(sizes.length, sizes, type, s.val[0], s.val[1], s.val[2], s.val[3]));
}
//
@@ -101,12 +97,12 @@ public class Mat {
// javadoc: Mat::Mat(m, rowRange, colRange)
public Mat(Mat m, Range rowRange, Range colRange) {
nativeObj = n_Mat(m.nativeObj, rowRange.start, rowRange.end, colRange.start, colRange.end);
super(n_Mat(m.nativeObj, rowRange.start, rowRange.end, colRange.start, colRange.end));
}
// javadoc: Mat::Mat(m, rowRange)
public Mat(Mat m, Range rowRange) {
nativeObj = n_Mat(m.nativeObj, rowRange.start, rowRange.end);
super(n_Mat(m.nativeObj, rowRange.start, rowRange.end));
}
//
@@ -115,7 +111,7 @@ public class Mat {
// javadoc: Mat::Mat(m, ranges)
public Mat(Mat m, Range[] ranges) {
nativeObj = n_Mat(m.nativeObj, ranges);
super(n_Mat(m.nativeObj, ranges));
}
//
@@ -124,7 +120,7 @@ public class Mat {
// javadoc: Mat::Mat(m, roi)
public Mat(Mat m, Rect roi) {
nativeObj = n_Mat(m.nativeObj, roi.y, roi.y + roi.height, roi.x, roi.x + roi.width);
super(n_Mat(m.nativeObj, roi.y, roi.y + roi.height, roi.x, roi.x + roi.width));
}
//
@@ -754,12 +750,6 @@ public class Mat {
return new Mat(n_zeros(sizes.length, sizes, type));
}
@Override
protected void finalize() throws Throwable {
n_delete(nativeObj);
super.finalize();
}
// javadoc:Mat::toString()
@Override
public String toString() {
@@ -1834,9 +1824,6 @@ public class Mat {
// C++: static Mat Mat::zeros(int ndims, const int* sizes, int type)
private static native long n_zeros(int ndims, int[] sizes, int type);
// native support for java finalize()
private static native void n_delete(long nativeObj);
private static native int nPutD(long self, int row, int col, int count, double[] data);
private static native int nPutDIdx(long self, int[] idx, int count, double[] data);
+16
View File
@@ -283,24 +283,40 @@ inline IppCmpOp arithm_ipp_convert_cmp(int cmpop)
inline int arithm_ipp_cmp8u(const uchar* src1, size_t step1, const uchar* src2, size_t step2,
uchar* dst, size_t step, int width, int height, int cmpop)
{
// perf regression with AVX512: https://github.com/opencv/opencv/issues/28251
if (ippCPUID_AVX512F&cv::ipp::getIppFeatures())
return 0;
ARITHM_IPP_CMP(ippiCompare_8u_C1R, src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height));
}
inline int arithm_ipp_cmp16u(const ushort* src1, size_t step1, const ushort* src2, size_t step2,
uchar* dst, size_t step, int width, int height, int cmpop)
{
// perf regression with AVX512: https://github.com/opencv/opencv/issues/28251
if (ippCPUID_AVX512F&cv::ipp::getIppFeatures())
return 0;
ARITHM_IPP_CMP(ippiCompare_16u_C1R, src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height));
}
inline int arithm_ipp_cmp16s(const short* src1, size_t step1, const short* src2, size_t step2,
uchar* dst, size_t step, int width, int height, int cmpop)
{
// perf regression with AVX512: https://github.com/opencv/opencv/issues/28251
if (ippCPUID_AVX512F&cv::ipp::getIppFeatures())
return 0;
ARITHM_IPP_CMP(ippiCompare_16s_C1R, src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height));
}
inline int arithm_ipp_cmp32f(const float* src1, size_t step1, const float* src2, size_t step2,
uchar* dst, size_t step, int width, int height, int cmpop)
{
// perf regression with AVX512: https://github.com/opencv/opencv/issues/28251
if (ippCPUID_AVX512F&cv::ipp::getIppFeatures())
return 0;
ARITHM_IPP_CMP(ippiCompare_32f_C1R, src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height));
}
+14 -2
View File
@@ -69,10 +69,17 @@
#include <sanitizer/msan_interface.h>
#define CV_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
__msan_unpoison(address, size)
#define CV_ANNOTATE_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
#endif
#endif
#ifndef CV_ANNOTATE_MEMORY_IS_INITIALIZED
#define CV_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) do { } while(0)
#define CV_ANNOTATE_NO_SANITIZE_MEMORY
#endif
#if defined(__APPLE__) && defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
//lapack stores matrices in column-major order so transposing is needed everywhere
@@ -108,8 +115,9 @@ set_value(fptype *dst, size_t dst_ld, fptype value, size_t m, size_t n)
dst[i*dst_ld + j] = value;
}
// MSAN can't see that the fortran LAPACK functions initialize `info`
template <typename fptype> static inline int
lapack_LU(fptype* a, size_t a_step, int m, fptype* b, size_t b_step, int n, int* info)
CV_ANNOTATE_NO_SANITIZE_MEMORY lapack_LU(fptype* a, size_t a_step, int m, fptype* b, size_t b_step, int n, int* info)
{
#if defined (ACCELERATE_NEW_LAPACK) && defined (ACCELERATE_LAPACK_ILP64)
cv::AutoBuffer<long> piv_buff(m);
@@ -710,4 +718,8 @@ int lapack_gemm64fc(const double *src1, size_t src1_step, const double *src2, si
return lapack_gemm_c(src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m, n, k, flags);
}
#endif //HAVE_LAPACK
#if defined(__APPLE__) && defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif //HAVE_LAPACK
+24 -5
View File
@@ -46,6 +46,8 @@
#include <atomic>
#include <limits>
#include <iostream>
#include <algorithm>
#include <cmath>
#include "mathfuncs.hpp"
namespace cv
@@ -1423,12 +1425,21 @@ int cv::solveCubic( InputArray _coeffs, OutputArray _roots )
a3 = coeffs.at<double>(i+3);
}
if( a0 == 0 )
// Fix for Issue #27748: Normalize coefficients to avoid overflow/underflow
// and correctly detect negligible cubic terms.
double max_coeff = std::max({std::abs(a0), std::abs(a1), std::abs(a2), std::abs(a3)});
// If max_coeff is effectively zero, the equation is 0=0
if (max_coeff < std::numeric_limits<double>::epsilon())
return -1;
// Check if the cubic term is negligible relative to the largest coefficient
if( std::abs(a0) < std::numeric_limits<double>::epsilon() * max_coeff )
{
if( a1 == 0 )
if( std::abs(a1) < std::numeric_limits<double>::epsilon() * max_coeff )
{
if( a2 == 0 ) // constant
n = a3 == 0 ? -1 : 0;
if( std::abs(a2) < std::numeric_limits<double>::epsilon() * max_coeff )
n = std::abs(a3) < std::numeric_limits<double>::epsilon() * max_coeff ? -1 : 0;
else
{
// linear equation
@@ -1445,7 +1456,7 @@ int cv::solveCubic( InputArray _coeffs, OutputArray _roots )
d = std::sqrt(d);
double q1 = (-a2 + d) * 0.5;
double q2 = (a2 + d) * -0.5;
if( fabs(q1) > fabs(q2) )
if( std::abs(q1) > std::abs(q2) )
{
x0 = q1 / a1;
x1 = a3 / q1;
@@ -1462,6 +1473,13 @@ int cv::solveCubic( InputArray _coeffs, OutputArray _roots )
else
{
// cubic equation
// Normalize coefficients in-place to prevent overflow/instability
double scale = 1.0 / max_coeff;
a0 *= scale;
a1 *= scale;
a2 *= scale;
a3 *= scale;
a0 = 1./a0;
a1 *= a0;
a2 *= a0;
@@ -1470,6 +1488,7 @@ int cv::solveCubic( InputArray _coeffs, OutputArray _roots )
double Q = (a1 * a1 - 3 * a2) * (1./9);
double R = (a1 * (2 * a1 * a1 - 9 * a2) + 27 * a3) * (1./54);
double Qcubed = Q * Q * Q;
/*
Here we expand expression `Qcubed - R * R` for `d` variable
to reduce common terms `a1^6 / 729` and `-a1^4 * a2 / 81`
@@ -93,7 +93,7 @@ static void* AppleCLGetProcAddress(const char* name)
handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
if (handle == NULL)
{
if (path != NULL && path != defaultPath)
if (!path.empty() && path != defaultPath)
fprintf(stderr, ERROR_MSG_CANT_LOAD);
}
else if (dlsym(handle, OPENCL_FUNC_TO_CHECK_1_1) == NULL)
-4
View File
@@ -465,10 +465,6 @@ namespace {
static inline int _initMaxThreads()
{
int maxThreads = omp_get_max_threads();
if (!utils::getConfigurationParameterBool("OPENCV_FOR_OPENMP_DYNAMIC_DISABLE", false))
{
omp_set_dynamic(1);
}
return maxThreads;
}
static int numThreadsMax = _initMaxThreads();
+3
View File
@@ -179,6 +179,7 @@ const uint64_t AT_HWCAP = NT_GNU_HWCAP;
#define _WIN32_WINNT 0x0400 // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx
#endif
#include <windows.h>
#include <combaseapi.h>
#if (_WIN32_WINNT >= 0x0602)
#include <synchapi.h>
#endif
@@ -478,6 +479,7 @@ struct HWFeatures
g_hwFeatureNames[CPU_NEON_DOTPROD] = "NEON_DOTPROD";
g_hwFeatureNames[CPU_NEON_FP16] = "NEON_FP16";
g_hwFeatureNames[CPU_NEON_BF16] = "NEON_BF16";
g_hwFeatureNames[CPU_SVE] = "SVE";
g_hwFeatureNames[CPU_VSX] = "VSX";
g_hwFeatureNames[CPU_VSX3] = "VSX3";
@@ -641,6 +643,7 @@ struct HWFeatures
{
have[CV_CPU_NEON_DOTPROD] = (auxv.a_un.a_val & (1 << 20)) != 0; // HWCAP_ASIMDDP
have[CV_CPU_NEON_FP16] = (auxv.a_un.a_val & (1 << 10)) != 0; // HWCAP_ASIMDHP
have[CV_CPU_SVE] = (auxv.a_un.a_val & (1 << 22)) != 0; // HWCAP_SVE
}
#if defined(AT_HWCAP2)
else if (auxv.a_type == AT_HWCAP2)
+39
View File
@@ -1037,6 +1037,14 @@ static void flip(const Mat& src, Mat& dst, int flipcode)
}
}
static void flip_inplace(Mat& dst, int flipcode)
{
Mat m;
m.create(dst.size(), dst.type());
reference::flip(dst, m, flipcode);
memcpy(dst.ptr<uchar>(), m.ptr<uchar>(), dst.total() * dst.elemSize());
}
static void rotate(const Mat& src, Mat& dst, int rotateMode)
{
Mat tmp;
@@ -1103,6 +1111,36 @@ struct FlipOp : public BaseElemWiseOp
int flipcode;
};
struct FlipInplaceOp : public BaseElemWiseOp
{
FlipInplaceOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) { flipcode = 0; }
void getRandomSize(RNG& rng, vector<int>& size)
{
cvtest::randomSize(rng, 2, 2, ARITHM_MAX_SIZE_LOG, size);
}
void op(const vector<Mat>& src, Mat& dst, const Mat&)
{
dst.create(src[0].size(), src[0].type());
memcpy(dst.ptr<uchar>(), src[0].ptr<uchar>(), src[0].total() * src[0].elemSize());
cv::flip(dst, dst, flipcode);
}
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
{
dst.create(src[0].size(), src[0].type());
memcpy(dst.ptr<uchar>(), src[0].ptr<uchar>(), src[0].total() * src[0].elemSize());
reference::flip_inplace(dst, flipcode);
}
void generateScalars(int, RNG& rng)
{
flipcode = rng.uniform(0, 3) - 1;
}
double getMaxErr(int)
{
return 0;
}
int flipcode;
};
struct RotateOp : public BaseElemWiseOp
{
RotateOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) { rotatecode = 0; }
@@ -1789,6 +1827,7 @@ INSTANTIATE_TEST_CASE_P(Core_InRange, ElemWiseTest, ::testing::Values(ElemWiseOp
INSTANTIATE_TEST_CASE_P(Core_FiniteMask, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new FiniteMaskOp)));
INSTANTIATE_TEST_CASE_P(Core_Flip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new FlipOp)));
INSTANTIATE_TEST_CASE_P(Core_FlipInplace, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new FlipInplaceOp)));
INSTANTIATE_TEST_CASE_P(Core_Rotate, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new RotateOp)));
INSTANTIATE_TEST_CASE_P(Core_Transpose, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new TransposeOp)));
INSTANTIATE_TEST_CASE_P(Core_SetIdentity, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new SetIdentityOp)));
+27
View File
@@ -1917,6 +1917,33 @@ TEST(Core_SolveCubic, regression_27323)
}
}
TEST(Core_SolveCubic, regression_27748)
{
// a is extremely small relative to others (approx 1.8e-19 ratio),
// causing instability in standard cubic formula.
double a = 1.56041e-17;
double b = 84.4504;
double c = -96.795;
double d = 13.6826;
Mat coeffs = (Mat_<double>(1, 4) << a, b, c, d);
Mat roots;
int n = solveCubic(coeffs, roots);
// Expecting quadratic behavior (2 roots)
EXPECT_GE(n, 2);
// Verify roots satisfy the FULL cubic equation
for(int i = 0; i < n; i++)
{
double x = roots.at<double>(i);
double val = a*x*x*x + b*x*x + c*x + d;
// Check residual is small
EXPECT_LE(fabs(val), 1e-6) << "Root " << x << " does not satisfy the equation";
}
}
TEST(Core_SolvePoly, regression_5599)
{
// x^4 - x^2 = 0, roots: 1, -1, 0, 0