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:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
* - Tait–Bryan 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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user