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:
@@ -790,7 +790,7 @@ public:
|
||||
Mat F(count == 7 ? 9 : 3, 3, CV_64F, f);
|
||||
int n = count == 7 ? run7Point(m1, m2, F) : run8Point(m1, m2, F);
|
||||
|
||||
if( n == 0 )
|
||||
if( n <= 0 )
|
||||
_model.release();
|
||||
else
|
||||
F.rowRange(0, n*3).copyTo(_model);
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
#elif defined(HAVE_LAPACK)
|
||||
#include "opencv_lapack.h"
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
namespace cv { namespace usac {
|
||||
class DLSPnPImpl : public DLSPnP {
|
||||
@@ -890,3 +894,7 @@ Ptr<DLSPnP> DLSPnP::create(const Mat &points_, const Mat &calib_norm_pts, const
|
||||
return makePtr<DLSPnPImpl>(points_, calib_norm_pts, K);
|
||||
}
|
||||
}}
|
||||
|
||||
#if defined(__APPLE__) && defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#elif defined(HAVE_LAPACK)
|
||||
#include "opencv_lapack.h"
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
namespace cv { namespace usac {
|
||||
/*
|
||||
@@ -354,3 +358,7 @@ Ptr<EssentialMinimalSolver5pts> EssentialMinimalSolver5pts::create
|
||||
return makePtr<EssentialMinimalSolver5ptsImpl>(points_, use_svd, is_nister);
|
||||
}
|
||||
}}
|
||||
|
||||
#if defined(__APPLE__) && defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
@@ -11,6 +11,10 @@
|
||||
#elif defined(HAVE_LAPACK)
|
||||
#include "opencv_lapack.h"
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
namespace cv { namespace usac {
|
||||
class PnPMinimalSolver6PtsImpl : public PnPMinimalSolver6Pts {
|
||||
@@ -408,3 +412,7 @@ Ptr<P3PSolver> P3PSolver::create(const Mat &points_, const Mat &calib_norm_pts,
|
||||
return makePtr<P3PSolverImpl>(points_, calib_norm_pts, K);
|
||||
}
|
||||
}}
|
||||
|
||||
#if defined(__APPLE__) && defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
@@ -388,12 +388,12 @@ void Utils::densitySort (const Mat &points, int knn, Mat &sorted_points, std::ve
|
||||
sorted_mask[i] = i;
|
||||
|
||||
// get neighbors
|
||||
FlannNeighborhoodGraph &graph = *FlannNeighborhoodGraph::create(points, points_size, knn,
|
||||
cv::Ptr<FlannNeighborhoodGraph> graph = FlannNeighborhoodGraph::create(points, points_size, knn,
|
||||
true /*get distances */, 6, 1);
|
||||
|
||||
std::vector<double> sum_knn_distances (points_size, 0);
|
||||
for (int p = 0; p < points_size; p++) {
|
||||
const std::vector<double> &dists = graph.getNeighborsDistances(p);
|
||||
const std::vector<double> &dists = graph->getNeighborsDistances(p);
|
||||
for (int k = 0; k < knn; k++)
|
||||
sum_knn_distances[p] += dists[k];
|
||||
}
|
||||
|
||||
@@ -420,5 +420,13 @@ TEST(Calib3d_FindFundamentalMat, correctMatches)
|
||||
cout << np2 << endl;
|
||||
}
|
||||
|
||||
TEST(Calib3d_FindFundamentalMat, Crash)
|
||||
{
|
||||
vector<Point2f> m1 = {{245, 128},{284, 226},{140, 60},{133, 127},{71, 218},{152, 138},{181, 106}};
|
||||
vector<Point2f> m2 = m1;
|
||||
vector<uchar> mask;
|
||||
findFundamentalMat(m1, m2, mask, FM_LMEDS, 1, 0.99);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
/* End of file. */
|
||||
|
||||
@@ -654,7 +654,7 @@ CV_EXPORTS_W bool checkChessboard(InputArray img, Size size);
|
||||
- @ref CALIB_CB_LARGER The detected pattern is allowed to be larger than patternSize (see description).
|
||||
- @ref CALIB_CB_MARKER The detected pattern must have a marker (see description).
|
||||
This should be used if an accurate camera calibration is required.
|
||||
@param meta Optional output arrray of detected corners (CV_8UC1 and size = cv::Size(columns,rows)).
|
||||
@param meta Optional output array of detected corners (CV_8UC1 and size = cv::Size(columns,rows)).
|
||||
Each entry stands for one corner of the pattern and can have one of the following values:
|
||||
- 0 = no meta data attached
|
||||
- 1 = left-top corner of a black cell
|
||||
|
||||
@@ -2169,7 +2169,7 @@ cv::Point2f &Chessboard::Board::getCorner(int _row,int _col)
|
||||
}
|
||||
++count;
|
||||
row_start = row_start->bottom;
|
||||
}while(_row);
|
||||
}while(row_start);
|
||||
}
|
||||
CV_Error(Error::StsInternal,"cannot find corner");
|
||||
// return *top_left->top_left; // never reached
|
||||
|
||||
@@ -149,7 +149,7 @@ class Chessboard: public cv::Feature2D
|
||||
int max_tests; //!< maximal number of tested hypothesis
|
||||
bool super_resolution; //!< use super-repsolution for chessboard detection
|
||||
bool larger; //!< indicates if larger boards should be returned
|
||||
bool marker; //!< indicates that valid boards must have a white and black cirlce marker used for orientation
|
||||
bool marker; //!< indicates that valid boards must have a white and black circle marker used for orientation
|
||||
|
||||
Parameters()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,7 +4,7 @@ endif()
|
||||
|
||||
set(the_description "Deep neural network module. It allows to load models from different frameworks and to make forward pass")
|
||||
|
||||
ocv_add_dispatched_file_force_all("layers/layers_common" AVX AVX2 AVX512_SKX RVV LASX NEON)
|
||||
ocv_add_dispatched_file_force_all("layers/layers_common" AVX AVX2 AVX512_SKX RVV LASX NEON SVE)
|
||||
ocv_add_dispatched_file_force_all("int8layers/layers_common" AVX2 AVX512_SKX RVV LASX NEON)
|
||||
ocv_add_dispatched_file_force_all("layers/cpu_kernels/conv_block" AVX AVX2 NEON NEON_FP16)
|
||||
ocv_add_dispatched_file_force_all("layers/cpu_kernels/conv_depthwise" AVX AVX2 RVV LASX)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define OPENCV_DNN_VERSION_HPP
|
||||
|
||||
/// Use with major OpenCV version only.
|
||||
#define OPENCV_DNN_API_VERSION 20250619
|
||||
#define OPENCV_DNN_API_VERSION 20251223
|
||||
|
||||
#if !defined CV_DOXYGEN && !defined CV_STATIC_ANALYSIS && !defined CV_DNN_DONT_ADD_INLINE_NS
|
||||
#define CV__DNN_INLINE_NS __CV_CAT(dnn5_v, OPENCV_DNN_API_VERSION)
|
||||
|
||||
@@ -228,7 +228,7 @@ void blobFromImagesNCHW(const std::vector<Mat>& images, Mat& blob_, const Image2
|
||||
template<typename Tout>
|
||||
void blobFromImagesNCHW(const std::vector<UMat>& images, UMat& blob_, const Image2BlobParams& param)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "");
|
||||
CV_Error(Error::StsNotImplemented, "blobFromImagesNCHW is not implemented for UMat inputs");
|
||||
}
|
||||
|
||||
template<class Tmat>
|
||||
|
||||
@@ -116,14 +116,14 @@ public:
|
||||
{
|
||||
case CV_32F: break;
|
||||
case CV_32S: ge_dtype = ge::DT_INT32; break;
|
||||
default: CV_Error(Error::StsNotImplemented, "Unsuppported data type");
|
||||
default: CV_Error(Error::StsNotImplemented, "Unsupported data type");
|
||||
}
|
||||
auto size_of_type = sizeof(float);
|
||||
switch (blobs[0].type())
|
||||
{
|
||||
case CV_32F: break;
|
||||
case CV_32S: size_of_type = sizeof(int); break;
|
||||
default: CV_Error(Error::StsNotImplemented, "Unsuppported data type");
|
||||
default: CV_Error(Error::StsNotImplemented, "Unsupported data type");
|
||||
}
|
||||
|
||||
auto desc = std::make_shared<ge::TensorDesc>(ge_shape, ge::FORMAT_NCHW, ge_dtype);
|
||||
|
||||
@@ -227,6 +227,7 @@ public:
|
||||
p.useAVX512 = CV_CPU_HAS_SUPPORT_AVX512_SKX;
|
||||
p.useRVV = checkHardwareSupport(CPU_RVV);
|
||||
p.useLASX = checkHardwareSupport(CPU_LASX);
|
||||
p.useSVE = checkHardwareSupport(CPU_SVE);
|
||||
|
||||
parallel_for_(Range(0, nstripes), p, nstripes);
|
||||
}
|
||||
@@ -276,6 +277,12 @@ public:
|
||||
opt_AVX::fastGEMM1T( sptr, wptr, wstep, biasptr, dptr, nw, vecsize_aligned);
|
||||
else
|
||||
#endif
|
||||
#if CV_TRY_SVE
|
||||
if( useSVE ) {
|
||||
opt_SVE::fastGEMM1T( sptr, wptr, wstep, biasptr, dptr, nw, vecsize_aligned);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if CV_TRY_RVV && CV_RVV
|
||||
if( useRVV )
|
||||
opt_RVV::fastGEMM1T( sptr, wptr, wstep, biasptr, dptr, nw, vecsize);
|
||||
@@ -341,6 +348,7 @@ public:
|
||||
bool useAVX512;
|
||||
bool useRVV;
|
||||
bool useLASX;
|
||||
bool useSVE;
|
||||
};
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
|
||||
@@ -221,7 +221,7 @@ public:
|
||||
#ifdef HAVE_DNN_NGRAPH
|
||||
virtual Ptr<BackendNode> initNgraph(const std::vector<Ptr<BackendWrapper> >& inputs,
|
||||
const std::vector<Ptr<BackendNode> >& nodes) CV_OVERRIDE {
|
||||
// onnx to openvino convertion: https://github.com/openvinotoolkit/openvino/blob/2023.1.0/src/frontends/onnx/frontend/src/op/instance_norm.cpp
|
||||
// onnx to openvino conversion: https://github.com/openvinotoolkit/openvino/blob/2023.1.0/src/frontends/onnx/frontend/src/op/instance_norm.cpp
|
||||
|
||||
auto ieInpNode = nodes[0].dynamicCast<InfEngineNgraphNode>()->node;
|
||||
const auto &input_shape = ieInpNode.get_shape();
|
||||
|
||||
@@ -53,7 +53,119 @@ void fastGEMM( const float* aptr, size_t astep, const float* bptr,
|
||||
size_t bstep, float* cptr, size_t cstep,
|
||||
int ma, int na, int nb );
|
||||
|
||||
#if !defined(CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY) && CV_NEON
|
||||
#if !defined(CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY) && defined(CV_CPU_COMPILE_SVE)
|
||||
#include <arm_sve.h>
|
||||
// dst = vec * weights^t + bias
|
||||
|
||||
void fastGEMM1T( const float* vec, const float* weights,
|
||||
size_t wstep, const float* bias,
|
||||
float* dst, int nvecs, int vecsize )
|
||||
{
|
||||
svbool_t pg_all = svptrue_b32();
|
||||
int i = 0;
|
||||
int vl = svcntw();
|
||||
for( ; i <= nvecs - 15; i += 15 )
|
||||
{
|
||||
const float* wrow0 = weights + i * wstep; // base pointer for row i
|
||||
// we will use wrow0 + k, wrow0 + wstep + k, etc
|
||||
svfloat32_t vs0 = svdup_f32(0.0f), vs1 = svdup_f32(0.0f),
|
||||
vs2 = svdup_f32(0.0f), vs3 = svdup_f32(0.0f),
|
||||
vs4 = svdup_f32(0.0f), vs5 = svdup_f32(0.0f),
|
||||
vs6 = svdup_f32(0.0f), vs7 = svdup_f32(0.0f),
|
||||
vs8 = svdup_f32(0.0f), vs9 = svdup_f32(0.0f),
|
||||
vs10 = svdup_f32(0.0f), vs11 = svdup_f32(0.0f),
|
||||
vs12 = svdup_f32(0.0f), vs13 = svdup_f32(0.0f),
|
||||
vs14 = svdup_f32(0.0f);
|
||||
int k = 0;
|
||||
for( ; k <= vecsize - vl; k += vl )
|
||||
{
|
||||
// load input chunk
|
||||
const float* vecptr = reinterpret_cast<const float*>(vec) + k;
|
||||
svfloat32_t v = svld1_f32(pg_all, vecptr);
|
||||
// load weights from each of 15 rows at offset k
|
||||
vs0 = svmla_f32_m(pg_all, vs0, svld1_f32(pg_all, wrow0 + k), v);
|
||||
vs1 = svmla_f32_m(pg_all, vs1, svld1_f32(pg_all, wrow0 + wstep + k), v);
|
||||
vs2 = svmla_f32_m(pg_all, vs2, svld1_f32(pg_all, wrow0 + wstep*2 + k), v);
|
||||
vs3 = svmla_f32_m(pg_all, vs3, svld1_f32(pg_all, wrow0 + wstep*3 + k), v);
|
||||
vs4 = svmla_f32_m(pg_all, vs4, svld1_f32(pg_all, wrow0 + wstep*4 + k), v);
|
||||
vs5 = svmla_f32_m(pg_all, vs5, svld1_f32(pg_all, wrow0 + wstep*5 + k), v);
|
||||
vs6 = svmla_f32_m(pg_all, vs6, svld1_f32(pg_all, wrow0 + wstep*6 + k), v);
|
||||
vs7 = svmla_f32_m(pg_all, vs7, svld1_f32(pg_all, wrow0 + wstep*7 + k), v);
|
||||
vs8 = svmla_f32_m(pg_all, vs8, svld1_f32(pg_all, wrow0 + wstep*8 + k), v);
|
||||
vs9 = svmla_f32_m(pg_all, vs9, svld1_f32(pg_all, wrow0 + wstep*9 + k), v);
|
||||
vs10 = svmla_f32_m(pg_all, vs10, svld1_f32(pg_all, wrow0 + wstep*10 + k), v);
|
||||
vs11 = svmla_f32_m(pg_all, vs11, svld1_f32(pg_all, wrow0 + wstep*11 + k), v);
|
||||
vs12 = svmla_f32_m(pg_all, vs12, svld1_f32(pg_all, wrow0 + wstep*12 + k), v);
|
||||
vs13 = svmla_f32_m(pg_all, vs13, svld1_f32(pg_all, wrow0 + wstep*13 + k), v);
|
||||
vs14 = svmla_f32_m(pg_all, vs14, svld1_f32(pg_all, wrow0 + wstep*14 + k), v);
|
||||
}
|
||||
if(k < vecsize){
|
||||
svbool_t pg_tail = svwhilelt_b32(k, vecsize);
|
||||
const float* vecptr = reinterpret_cast<const float*>(vec) + k;
|
||||
svfloat32_t v = svld1_f32(pg_tail, vecptr);
|
||||
const float* wptr = wrow0 + k;
|
||||
vs0 = svmla_f32_m(pg_tail, vs0, svld1_f32(pg_tail, wptr), v);
|
||||
vs1 = svmla_f32_m(pg_tail, vs1, svld1_f32(pg_tail, wptr + wstep), v);
|
||||
vs2 = svmla_f32_m(pg_tail, vs2, svld1_f32(pg_tail, wptr + wstep*2), v);
|
||||
vs3 = svmla_f32_m(pg_tail, vs3, svld1_f32(pg_tail, wptr + wstep*3), v);
|
||||
vs4 = svmla_f32_m(pg_tail, vs4, svld1_f32(pg_tail, wptr + wstep*4), v);
|
||||
vs5 = svmla_f32_m(pg_tail, vs5, svld1_f32(pg_tail, wptr + wstep*5), v);
|
||||
vs6 = svmla_f32_m(pg_tail, vs6, svld1_f32(pg_tail, wptr + wstep*6), v);
|
||||
vs7 = svmla_f32_m(pg_tail, vs7, svld1_f32(pg_tail, wptr + wstep*7), v);
|
||||
vs8 = svmla_f32_m(pg_tail, vs8, svld1_f32(pg_tail, wptr + wstep*8), v);
|
||||
vs9 = svmla_f32_m(pg_tail, vs9, svld1_f32(pg_tail, wptr + wstep*9), v);
|
||||
vs10 = svmla_f32_m(pg_tail, vs10, svld1_f32(pg_tail, wptr + wstep*10), v);
|
||||
vs11 = svmla_f32_m(pg_tail, vs11, svld1_f32(pg_tail, wptr + wstep*11), v);
|
||||
vs12 = svmla_f32_m(pg_tail, vs12, svld1_f32(pg_tail, wptr + wstep*12), v);
|
||||
vs13 = svmla_f32_m(pg_tail, vs13, svld1_f32(pg_tail, wptr + wstep*13), v);
|
||||
vs14 = svmla_f32_m(pg_tail, vs14, svld1_f32(pg_tail, wptr + wstep*14), v);
|
||||
}
|
||||
float sum[15];
|
||||
sum[0] = svaddv_f32(pg_all, vs0);
|
||||
|
||||
sum[1] = svaddv_f32(pg_all, vs1);
|
||||
sum[2] = svaddv_f32(pg_all, vs2);
|
||||
sum[3] = svaddv_f32(pg_all, vs3);
|
||||
sum[4] = svaddv_f32(pg_all, vs4);
|
||||
sum[5] = svaddv_f32(pg_all, vs5);
|
||||
sum[6] = svaddv_f32(pg_all, vs6);
|
||||
sum[7] = svaddv_f32(pg_all, vs7);
|
||||
sum[8] = svaddv_f32(pg_all, vs8);
|
||||
sum[9] = svaddv_f32(pg_all, vs9);
|
||||
sum[10] = svaddv_f32(pg_all, vs10);
|
||||
sum[11] = svaddv_f32(pg_all, vs11);
|
||||
sum[12] = svaddv_f32(pg_all, vs12);
|
||||
sum[13] = svaddv_f32(pg_all, vs13);
|
||||
sum[14] = svaddv_f32(pg_all, vs14);
|
||||
for (int j = 0; j < 15; j += vl) {
|
||||
svbool_t pg = svwhilelt_b32(j, 15);
|
||||
svfloat32_t v_sum = svld1_f32(pg, sum + j);
|
||||
svfloat32_t v_bias = svld1_f32(pg, bias + i + j);
|
||||
svst1_f32(pg, dst + i + j, svadd_f32_z(pg, v_sum, v_bias));
|
||||
}
|
||||
}
|
||||
float temp = 0.f;
|
||||
for( ; i < nvecs; i++ )
|
||||
{
|
||||
const float* wrow = weights + i * wstep;
|
||||
svfloat32_t vs0 = svdup_f32(0.0f);
|
||||
int k = 0;
|
||||
for( ; k <= vecsize - vl; k += vl )
|
||||
{
|
||||
svfloat32_t v = svld1_f32(pg_all, reinterpret_cast<const float*>(vec) + k);
|
||||
vs0 = svmla_f32_m(pg_all, vs0, svld1_f32(pg_all, wrow + k), v);
|
||||
}
|
||||
if (k != vecsize) {
|
||||
svbool_t pg_tail = svwhilelt_b32(k, vecsize);
|
||||
svfloat32_t v = svld1_f32(pg_tail, reinterpret_cast<const float*>(vec) + k);
|
||||
vs0 = svmla_f32_m(pg_tail, vs0, svld1_f32(pg_tail, wrow + k), v);
|
||||
}
|
||||
temp = svaddv_f32(pg_all, vs0);
|
||||
dst[i] = temp + bias[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if !defined(CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY) && CV_NEON && !defined(CV_CPU_COMPILE_SVE)
|
||||
|
||||
static const uint32_t tailMaskArray[7] = {
|
||||
0u, 0u, 0u, 0u,
|
||||
|
||||
@@ -423,7 +423,7 @@ class MatMulLayerImpl CV_FINAL : public MatMulLayer {
|
||||
op->set_input_x1_by_name(*input_A_node, input_A_wrapper->name.c_str());
|
||||
op->update_input_desc_x1(*input_A_desc);
|
||||
// set inputs : x2
|
||||
if (blobs.empty()) { // varaible input B
|
||||
if (blobs.empty()) { // variable input B
|
||||
auto input_B_wrapper = inputs[1].dynamicCast<CannBackendWrapper>();
|
||||
auto input_B_desc = input_B_wrapper->getTensorDesc();
|
||||
auto input_B_node = nodes[1].dynamicCast<CannBackendNode>()->getOp();
|
||||
|
||||
@@ -548,8 +548,8 @@ public:
|
||||
int nplanes = std::accumulate(shape.begin(), shape.end() - 1, 1, std::multiplies<int>());
|
||||
|
||||
if (nplanes == 1) { // parallelize within the plane
|
||||
AutoBuffer<char> buf_ptrs(steps.size());
|
||||
auto ptrs = (char**)buf_ptrs.data();
|
||||
AutoBuffer<char*> buf_ptrs(steps.size());
|
||||
char** ptrs = buf_ptrs.data();
|
||||
ptrs[0] = out;
|
||||
for (int i = 0; i < ninputs; i++) {
|
||||
ptrs[i+1] = (char*)inp[i];
|
||||
@@ -594,8 +594,8 @@ public:
|
||||
parallel_for_(Range(0, plane_size), worker, nstripes);
|
||||
} else { // parallelize across the plane
|
||||
auto worker = [&](const Range &r) {
|
||||
AutoBuffer<char> buf_ptrs(steps.size());
|
||||
auto ptrs = (char**)buf_ptrs.data();
|
||||
AutoBuffer<char*> buf_ptrs(steps.size());
|
||||
char** ptrs = buf_ptrs.data();
|
||||
for (int plane_idx = r.start; plane_idx < r.end; plane_idx++) {
|
||||
ptrs[0] = out;
|
||||
for (int i = 0; i < ninputs; i++) ptrs[i+1] = (char*)inp[i];
|
||||
@@ -1318,7 +1318,7 @@ public:
|
||||
node = std::make_shared<ov::op::v1::Select>(inp0, inp1, inp2);
|
||||
}
|
||||
// Ideally we should do this but int32 internal blobs are converted to float32 data type in inference.
|
||||
// TODO: Remove data type convertion when we have type inference.
|
||||
// TODO: Remove data type conversion when we have type inference.
|
||||
else if (op == OPERATION::MOD) {
|
||||
auto inp0_i64 = std::make_shared<ov::op::v0::Convert>(inp0, ov::element::i64);
|
||||
auto inp1_i64 = std::make_shared<ov::op::v0::Convert>(inp1, ov::element::i64);
|
||||
|
||||
@@ -138,6 +138,9 @@ class LSTMLayerImpl CV_FINAL : public LSTMLayer
|
||||
#if CV_TRY_AVX2
|
||||
bool useAVX2;
|
||||
#endif
|
||||
#if CV_TRY_SVE
|
||||
bool useSVE;
|
||||
#endif
|
||||
#if CV_TRY_NEON
|
||||
bool useNEON;
|
||||
#endif
|
||||
@@ -156,6 +159,9 @@ public:
|
||||
#if CV_TRY_AVX2
|
||||
, useAVX2(checkHardwareSupport(CPU_AVX2))
|
||||
#endif
|
||||
#if CV_TRY_SVE
|
||||
, useSVE(checkHardwareSupport(CPU_SVE))
|
||||
#endif
|
||||
#if CV_TRY_NEON
|
||||
, useNEON(checkHardwareSupport(CPU_NEON))
|
||||
#endif
|
||||
@@ -410,7 +416,7 @@ public:
|
||||
if (layout == BATCH_SEQ_HID){
|
||||
//swap axis 0 and 1 input x
|
||||
cv::Mat tmp;
|
||||
// Since python input is 4 dimentional and C++ input 3 dimentinal
|
||||
// Since python input is 4 dimensional and C++ input 3 dimensional
|
||||
// we need to process each differently
|
||||
if (input[0].dims == 4){
|
||||
// here !!!
|
||||
@@ -495,6 +501,13 @@ public:
|
||||
&& Wh.depth() == CV_32F && hInternal.depth() == CV_32F && gates.depth() == CV_32F
|
||||
&& Wh.cols >= 8;
|
||||
#endif
|
||||
#if CV_TRY_SVE
|
||||
bool canUseSVE = gates.isContinuous() && bias.isContinuous()
|
||||
&& Wx.depth() == CV_32F && gates.depth() == CV_32F
|
||||
&& bias.depth() == CV_32F;
|
||||
bool canUseSVE_hInternal = hInternal.isContinuous() && gates.isContinuous() && bias.isContinuous()
|
||||
&& Wh.depth() == CV_32F && hInternal.depth() == CV_32F && gates.depth() == CV_32F;
|
||||
#endif
|
||||
#if CV_TRY_NEON
|
||||
bool canUseNeon = gates.isContinuous() && bias.isContinuous()
|
||||
&& Wx.depth() == CV_32F && gates.depth() == CV_32F
|
||||
@@ -554,6 +567,23 @@ public:
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if CV_TRY_SVE
|
||||
if (useSVE && canUseSVE && xCurr.isContinuous())
|
||||
{
|
||||
for (int n = 0; n < xCurr.rows; n++) {
|
||||
opt_SVE::fastGEMM1T(
|
||||
xCurr.ptr<float>(n),
|
||||
Wx.ptr<float>(),
|
||||
Wx.step1(),
|
||||
bias.ptr<float>(),
|
||||
gates.ptr<float>(n),
|
||||
Wx.rows,
|
||||
Wx.cols
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if CV_TRY_NEON
|
||||
if (useNEON && canUseNeon && xCurr.isContinuous())
|
||||
{
|
||||
@@ -610,6 +640,23 @@ public:
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if CV_TRY_SVE
|
||||
if (useSVE && canUseSVE_hInternal)
|
||||
{
|
||||
for (int n = 0; n < hInternal.rows; n++) {
|
||||
opt_SVE::fastGEMM1T(
|
||||
hInternal.ptr<float>(n),
|
||||
Wh.ptr<float>(),
|
||||
Wh.step1(),
|
||||
gates.ptr<float>(n),
|
||||
gates.ptr<float>(n),
|
||||
Wh.rows,
|
||||
Wh.cols
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if CV_TRY_NEON
|
||||
if (useNEON && canUseNeon_hInternal)
|
||||
{
|
||||
|
||||
@@ -194,6 +194,7 @@ private:
|
||||
void parseElementWise (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
|
||||
void parseDepthSpaceOps (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
|
||||
void parseRange (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
|
||||
void parseRandomNormalLike (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
|
||||
void parseScatter (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
|
||||
void parseTile (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
|
||||
void parseLayerNorm (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
|
||||
@@ -2046,6 +2047,25 @@ void ONNXImporter::parseConv(LayerParams& layerParams, const opencv_onnx::NodePr
|
||||
layerParams.blobs.push_back(getBlob(node_proto, j));
|
||||
}
|
||||
}
|
||||
// ONNX allows omitting 'kernel_shape' attribute for Conv. In that case, it should be inferred from weights.
|
||||
// See: https://onnx.ai/onnx/operators/onnx__Conv.html
|
||||
if (!layerParams.has("kernel_size"))
|
||||
{
|
||||
Mat weights;
|
||||
if (!layerParams.blobs.empty())
|
||||
weights = layerParams.blobs[0];
|
||||
else if (constBlobs.find(node_proto.input(1)) != constBlobs.end())
|
||||
weights = getBlob(node_proto, 1);
|
||||
|
||||
if (!weights.empty() && weights.dims >= 3)
|
||||
{
|
||||
const int kDims = weights.dims - 2;
|
||||
std::vector<int32_t> kernel(kDims);
|
||||
for (int i = 0; i < kDims; ++i)
|
||||
kernel[i] = weights.size[2 + i];
|
||||
layerParams.set("kernel_size", DictValue::arrayInt(kernel.data(), static_cast<int>(kernel.size())));
|
||||
}
|
||||
}
|
||||
int outCn = layerParams.blobs.empty() ? outShapes[node_proto.input(1)][0] : layerParams.blobs[0].size[0];
|
||||
layerParams.set("num_output", outCn);
|
||||
|
||||
@@ -2062,6 +2082,20 @@ void ONNXImporter::parseConvTranspose(LayerParams& layerParams, const opencv_onn
|
||||
layerParams.set("num_output", layerParams.blobs[0].size[1] * layerParams.get<int>("group", 1));
|
||||
layerParams.set("bias_term", node_proto.input_size() == 3);
|
||||
|
||||
// ONNX allows omitting 'kernel_shape' attribute for ConvTranspose. Infer it from weights if needed.
|
||||
if (!layerParams.has("kernel_size"))
|
||||
{
|
||||
const Mat& weights = layerParams.blobs[0];
|
||||
if (!weights.empty() && weights.dims >= 3)
|
||||
{
|
||||
const int kDims = weights.dims - 2;
|
||||
std::vector<int32_t> kernel(kDims);
|
||||
for (int i = 0; i < kDims; ++i)
|
||||
kernel[i] = weights.size[2 + i];
|
||||
layerParams.set("kernel_size", DictValue::arrayInt(kernel.data(), static_cast<int>(kernel.size())));
|
||||
}
|
||||
}
|
||||
|
||||
if (!layerParams.has("kernel_size"))
|
||||
CV_Error(Error::StsNotImplemented,
|
||||
"Required attribute 'kernel_size' is not present.");
|
||||
@@ -3006,6 +3040,14 @@ void ONNXImporter::parseRange(LayerParams& layerParams, const opencv_onnx::NodeP
|
||||
constBlobsExtraInfo.insert(std::make_pair(node_proto.output(0), TensorInfo(1)));
|
||||
}
|
||||
|
||||
void ONNXImporter::parseRandomNormalLike(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
|
||||
{
|
||||
CV_CheckEQ(node_proto.input_size(), 1, "RandomNormalLike: one input is required");
|
||||
|
||||
layerParams.type = "RandomNormalLike";
|
||||
addLayer(layerParams, node_proto);
|
||||
}
|
||||
|
||||
void ONNXImporter::parseScatter(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
|
||||
{
|
||||
CV_CheckEQ(node_proto.input_size(), 3, "Scatter: three inputs are required.");
|
||||
@@ -4022,6 +4064,7 @@ void ONNXImporter::buildDispatchMap_ONNX_AI()
|
||||
dispatch["Sum"] = dispatch["Min"] = dispatch["Max"] = dispatch["Mean"] = &ONNXImporter::parseElementWise;
|
||||
dispatch["Where"] = &ONNXImporter::parseElementWise;
|
||||
dispatch["Range"] = &ONNXImporter::parseRange;
|
||||
dispatch["RandomNormalLike"] = &ONNXImporter::parseRandomNormalLike;
|
||||
dispatch["Einsum"] = &ONNXImporter::parseEinsum;
|
||||
dispatch["Hardmax"] = &ONNXImporter::parseHardmax;
|
||||
dispatch["GatherND"] = &ONNXImporter::parseGatherND;
|
||||
|
||||
@@ -334,7 +334,8 @@ TFLiteImporter::DispatchMap TFLiteImporter::buildDispatchMap()
|
||||
dispatch["DEPTHWISE_CONV_2D"] = &TFLiteImporter::parseDWConvolution;
|
||||
dispatch["ADD"] = dispatch["MUL"] = dispatch["SUB"] =
|
||||
dispatch["SQRT"] = dispatch["DIV"] = dispatch["NEG"] =
|
||||
dispatch["RSQRT"] = dispatch["SQUARED_DIFFERENCE"] = &TFLiteImporter::parseEltwise;
|
||||
dispatch["RSQRT"] = dispatch["SQUARED_DIFFERENCE"] =
|
||||
dispatch["MAXIMUM"] = dispatch["MINIMUM"]= &TFLiteImporter::parseEltwise;
|
||||
dispatch["RELU"] = dispatch["PRELU"] = dispatch["HARD_SWISH"] =
|
||||
dispatch["LOGISTIC"] = dispatch["LEAKY_RELU"] = &TFLiteImporter::parseActivation;
|
||||
dispatch["MAX_POOL_2D"] = dispatch["AVERAGE_POOL_2D"] = &TFLiteImporter::parsePooling;
|
||||
@@ -681,7 +682,13 @@ void TFLiteImporter::parseEltwise(const Operator& op, const std::string& opcode,
|
||||
}
|
||||
else if (opcode == "SQRT" && !isOpInt8) {
|
||||
layerParams.type = "Sqrt";
|
||||
} else {
|
||||
}
|
||||
else if (opcode == "MAXIMUM" && !isOpInt8) {
|
||||
layerParams.set("operation", "max");
|
||||
}
|
||||
else if (opcode == "MINIMUM" && !isOpInt8) {
|
||||
layerParams.set("operation", "min");
|
||||
}else {
|
||||
CV_Error(Error::StsNotImplemented, cv::format("DNN/TFLite: Unknown opcode for %s Eltwise layer '%s'", isOpInt8 ? "INT8" : "FP32", opcode.c_str()));
|
||||
}
|
||||
|
||||
|
||||
@@ -3465,6 +3465,51 @@ TEST_P(Test_ONNX_layers, TopK) {
|
||||
test("top_k_smallest");
|
||||
}
|
||||
|
||||
// BUG: https://github.com/opencv/opencv/issues/28532
|
||||
TEST_P(Test_ONNX_layers, DISABLED_RandomNormalLike_basic)
|
||||
{
|
||||
Net net = readNetFromONNX(findDataFile("dnn/onnx/models/random_normal_like.onnx", true));
|
||||
|
||||
Mat input(2, 3, CV_32F, Scalar(0));
|
||||
net.setInput(input);
|
||||
Mat out = net.forward();
|
||||
|
||||
EXPECT_EQ(out.rows, 2);
|
||||
EXPECT_EQ(out.cols, 3);
|
||||
EXPECT_EQ(out.type(), CV_32F);
|
||||
|
||||
double minVal, maxVal;
|
||||
minMaxLoc(out, &minVal, &maxVal);
|
||||
EXPECT_NE(minVal, 0.0);
|
||||
EXPECT_NE(maxVal, 0.0);
|
||||
EXPECT_NE(minVal, maxVal);
|
||||
|
||||
Mat out2 = net.forward();
|
||||
EXPECT_EQ(countNonZero(out != out2), 0);
|
||||
}
|
||||
|
||||
// BUG: https://github.com/opencv/opencv/issues/28532
|
||||
TEST_P(Test_ONNX_layers, DISABLED_RandomNormalLike_complex)
|
||||
{
|
||||
Net net = readNetFromONNX(findDataFile("dnn/onnx/models/random_normal_like_complex.onnx", true));
|
||||
|
||||
Mat input(2, 3, CV_32F, Scalar(0));
|
||||
net.setInput(input);
|
||||
Mat out = net.forward();
|
||||
|
||||
EXPECT_EQ(out.rows, 2);
|
||||
EXPECT_EQ(out.cols, 3);
|
||||
EXPECT_EQ(out.type(), CV_32F);
|
||||
|
||||
double minVal, maxVal;
|
||||
minMaxLoc(out, &minVal, &maxVal);
|
||||
EXPECT_NE(minVal, maxVal);
|
||||
|
||||
net.setInput(input);
|
||||
Mat out2 = net.forward();
|
||||
EXPECT_EQ(countNonZero(out != out2), 0);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Test_ONNX_nets, dnnBackendsAndTargets());
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -289,6 +289,62 @@ TEST_P(Test_TFLite, face_blendshapes)
|
||||
testModel("face_blendshapes", inp);
|
||||
}
|
||||
|
||||
TEST_P(Test_TFLite, maximum)
|
||||
{
|
||||
Net net = readNetFromTFLite(findDataFile("dnn/tflite/maximum.tflite"));
|
||||
|
||||
net.setPreferableBackend(backend);
|
||||
net.setPreferableTarget(target);
|
||||
|
||||
Mat input_x = blobFromNPY(findDataFile("dnn/tflite/maximum_input_x.npy"));
|
||||
Mat input_y = blobFromNPY(findDataFile("dnn/tflite/maximum_input_y.npy"));
|
||||
|
||||
net.setInput(input_x, "x");
|
||||
net.setInput(input_y, "y");
|
||||
|
||||
Mat out = net.forward();
|
||||
Mat ref = blobFromNPY(findDataFile("dnn/tflite/maximum_output.npy"));
|
||||
|
||||
double l1 = 1e-5;
|
||||
double lInf = 1e-4;
|
||||
|
||||
if (target == DNN_TARGET_CUDA_FP16 || target == DNN_TARGET_OPENCL_FP16)
|
||||
{
|
||||
l1 = 1e-3;
|
||||
lInf = 1e-3;
|
||||
}
|
||||
|
||||
normAssert(ref, out, "", l1, lInf);
|
||||
}
|
||||
|
||||
TEST_P(Test_TFLite, minimum)
|
||||
{
|
||||
Net net = readNetFromTFLite(findDataFile("dnn/tflite/minimum.tflite"));
|
||||
|
||||
net.setPreferableBackend(backend);
|
||||
net.setPreferableTarget(target);
|
||||
|
||||
Mat input_x = blobFromNPY(findDataFile("dnn/tflite/minimum_input_x.npy"));
|
||||
Mat input_y = blobFromNPY(findDataFile("dnn/tflite/minimum_input_y.npy"));
|
||||
|
||||
net.setInput(input_x, "x");
|
||||
net.setInput(input_y, "y");
|
||||
|
||||
Mat out = net.forward();
|
||||
Mat ref = blobFromNPY(findDataFile("dnn/tflite/minimum_output.npy"));
|
||||
|
||||
double l1 = 1e-5;
|
||||
double lInf = 1e-4;
|
||||
|
||||
if (target == DNN_TARGET_CUDA_FP16 || target == DNN_TARGET_OPENCL_FP16)
|
||||
{
|
||||
l1 = 1e-3;
|
||||
lInf = 1e-3;
|
||||
}
|
||||
|
||||
normAssert(ref, out, "", l1, lInf);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Test_TFLite, dnnBackendsAndTargets());
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -563,7 +563,7 @@ public:
|
||||
CV_WRAP static Ptr<GFTTDetector> create( int maxCorners=1000, double qualityLevel=0.01, double minDistance=1,
|
||||
int blockSize=3, bool useHarrisDetector=false, double k=0.04 );
|
||||
CV_WRAP static Ptr<GFTTDetector> create( int maxCorners, double qualityLevel, double minDistance,
|
||||
int blockSize, int gradiantSize, bool useHarrisDetector=false, double k=0.04 );
|
||||
int blockSize, int gradientSize, bool useHarrisDetector=false, double k=0.04 );
|
||||
CV_WRAP virtual void setMaxFeatures(int maxFeatures) = 0;
|
||||
CV_WRAP virtual int getMaxFeatures() const = 0;
|
||||
|
||||
@@ -645,6 +645,11 @@ public:
|
||||
CV_PROP_RW bool filterByConvexity;
|
||||
CV_PROP_RW float minConvexity, maxConvexity;
|
||||
|
||||
/** @brief Flag to enable contour collection.
|
||||
If set to true, the detector will store the contours of the detected blobs in memory,
|
||||
which can be retrieved after the detect() call using getBlobContours().
|
||||
@note Default value is false.
|
||||
*/
|
||||
CV_PROP_RW bool collectContours;
|
||||
|
||||
void read( const FileNode& fn );
|
||||
@@ -658,6 +663,11 @@ public:
|
||||
CV_WRAP virtual SimpleBlobDetector::Params getParams() const = 0;
|
||||
|
||||
CV_WRAP virtual String getDefaultName() const CV_OVERRIDE;
|
||||
|
||||
/** @brief Returns the contours of the blobs detected during the last call to detect().
|
||||
@note The @ref Params::collectContours parameter must be set to true before calling
|
||||
detect() for this method to return any data.
|
||||
*/
|
||||
CV_WRAP virtual const std::vector<std::vector<cv::Point> >& getBlobContours() const = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -1036,7 +1036,11 @@ void ORB_Impl::detectAndCompute( InputArray _image, InputArray _mask,
|
||||
bool useOCL = false;
|
||||
#endif
|
||||
|
||||
Mat image = _image.getMat(), mask = _mask.getMat();
|
||||
Mat image = _image.getMat(), mask;
|
||||
if (!_mask.empty())
|
||||
{
|
||||
threshold(_mask, mask, 0, 255, THRESH_BINARY);
|
||||
}
|
||||
if( image.type() != CV_8UC1 )
|
||||
cvtColor(_image, image, COLOR_BGR2GRAY);
|
||||
|
||||
@@ -1134,7 +1138,7 @@ void ORB_Impl::detectAndCompute( InputArray _image, InputArray _mask,
|
||||
}
|
||||
|
||||
copyMakeBorder(currImg, extImg, border, border, border, border,
|
||||
BORDER_REFLECT_101+BORDER_ISOLATED);
|
||||
BORDER_REFLECT_101 + BORDER_ISOLATED);
|
||||
if (!mask.empty())
|
||||
copyMakeBorder(currMask, extMask, border, border, border, border,
|
||||
BORDER_CONSTANT+BORDER_ISOLATED);
|
||||
|
||||
@@ -168,4 +168,31 @@ BIGDATA_TEST(Features2D_ORB, regression_opencv_python_537) // memory usage: ~3
|
||||
ASSERT_NO_THROW(orbPtr->detectAndCompute(img, noArray(), kps, fv));
|
||||
}
|
||||
|
||||
TEST(Features2D_ORB, MaskValue)
|
||||
{
|
||||
Mat gray = imread(cvtest::findDataFile("features2d/tsukuba.png"), IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(gray.empty());
|
||||
|
||||
cv::Rect roi(gray.cols/4, gray.rows/4, gray.cols/2, gray.rows/2);
|
||||
|
||||
Mat mask255 = Mat::zeros(gray.size(), CV_8UC1);
|
||||
Mat mask1 = Mat::zeros(gray.size(), CV_8UC1);
|
||||
mask255(roi).setTo(255);
|
||||
mask1(roi).setTo(1);
|
||||
|
||||
Ptr<ORB> orb = cv::ORB::create();
|
||||
|
||||
vector<KeyPoint> keypoints_mask255, keypoints_mask1;
|
||||
Mat descriptors_mask255, descriptors_mask1;
|
||||
|
||||
orb->detectAndCompute(gray, mask255, keypoints_mask255, descriptors_mask255, false);
|
||||
orb->detectAndCompute(gray, mask1, keypoints_mask1, descriptors_mask1, false);
|
||||
|
||||
ASSERT_EQ(keypoints_mask255.size(), keypoints_mask1.size())
|
||||
<< "Number of keypoints differs between mask values 255 and 1";
|
||||
|
||||
Mat diff = descriptors_mask255 != descriptors_mask1;
|
||||
ASSERT_EQ(countNonZero(diff), 0);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -790,14 +790,17 @@ GuiReceiver::GuiReceiver() : bTimeOut(false), nb_windows(0)
|
||||
|
||||
void GuiReceiver::isLastWindow()
|
||||
{
|
||||
if (--nb_windows <= 0)
|
||||
if (qApp->quitOnLastWindowClosed())
|
||||
{
|
||||
delete guiMainThread;//delete global_control_panel too
|
||||
guiMainThread = NULL;
|
||||
|
||||
if (doesExternalQAppExist)
|
||||
if (--nb_windows <= 0)
|
||||
{
|
||||
qApp->quit();
|
||||
delete guiMainThread; // delete global_control_panel too
|
||||
guiMainThread = NULL;
|
||||
|
||||
if (doesExternalQAppExist)
|
||||
{
|
||||
qApp->quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,6 +557,7 @@ It also demonstrates how to save multiple images in a TIFF file:
|
||||
@param filename Name of the file.
|
||||
@param img (Mat or vector of Mat) Image or Images to be saved.
|
||||
@param params Format-specific parameters encoded as pairs (paramId_1, paramValue_1, paramId_2, paramValue_2, ... .) see cv::ImwriteFlags
|
||||
@return true if the image is successfully written to the specified file; false otherwise.
|
||||
*/
|
||||
CV_EXPORTS_W bool imwrite( const String& filename, InputArray img,
|
||||
const std::vector<int>& params = std::vector<int>());
|
||||
|
||||
@@ -211,6 +211,10 @@ bool AvifDecoder::readHeader() {
|
||||
return true;
|
||||
|
||||
decoder_ = avifDecoderCreate();
|
||||
if (!decoder_) {
|
||||
CV_Error(Error::StsNoMem, "Failed to create AVIF decoder");
|
||||
return false;
|
||||
}
|
||||
decoder_->strictFlags = AVIF_STRICT_DISABLED;
|
||||
if (!m_buf.empty()) {
|
||||
CV_Assert(m_buf.type() == CV_8UC1);
|
||||
@@ -226,6 +230,11 @@ bool AvifDecoder::readHeader() {
|
||||
decoder_);
|
||||
OPENCV_AVIF_CHECK_STATUS(avifDecoderParse(decoder_), decoder_);
|
||||
|
||||
if (!decoder_->image) {
|
||||
CV_Error(Error::StsParseError, "AVIF image is null after parsing");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_width = decoder_->image->width;
|
||||
m_height = decoder_->image->height;
|
||||
m_frame_count = decoder_->imageCount;
|
||||
@@ -380,7 +389,6 @@ bool AvifEncoder::writeanimation(const Animation& animation,
|
||||
? AVIF_ADD_IMAGE_FLAG_SINGLE
|
||||
: AVIF_ADD_IMAGE_FLAG_NONE;
|
||||
std::vector<AvifImageUniquePtr> images;
|
||||
std::vector<cv::Mat> imgs_scaled;
|
||||
for (const cv::Mat &img : animation.frames) {
|
||||
CV_CheckType(
|
||||
img.type(),
|
||||
@@ -388,11 +396,17 @@ bool AvifEncoder::writeanimation(const Animation& animation,
|
||||
((bit_depth == 10 || bit_depth == 12) && img.depth() == CV_16U),
|
||||
"AVIF only supports bit depth of 8 with CV_8U input or "
|
||||
"bit depth of 10 or 12 with CV_16U input");
|
||||
|
||||
CV_Check(img.channels(),
|
||||
img.channels() == 1 || img.channels() == 3 || img.channels() == 4,
|
||||
"AVIF only supports 1, 3, 4 channels");
|
||||
|
||||
images.emplace_back(ConvertToAvif(img, do_lossless, bit_depth, m_metadata));
|
||||
auto avifImg = ConvertToAvif(img, do_lossless, bit_depth, m_metadata);
|
||||
if (!avifImg) {
|
||||
CV_Error(Error::StsError, "Failed to convert Mat to AVIF image");
|
||||
return false;
|
||||
}
|
||||
images.emplace_back(std::move(avifImg));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < images.size(); i++)
|
||||
|
||||
@@ -130,9 +130,6 @@ bool ExrDecoder::readHeader()
|
||||
|
||||
m_file = new InputFile( m_filename.c_str() );
|
||||
|
||||
if( !m_file ) // probably paranoid
|
||||
return false;
|
||||
|
||||
m_datawindow = m_file->header().dataWindow();
|
||||
m_width = m_datawindow.max.x - m_datawindow.min.x + 1;
|
||||
m_height = m_datawindow.max.y - m_datawindow.min.y + 1;
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
@@ -364,7 +365,7 @@ bool PngDecoder::readHeader()
|
||||
m_color_type = color_type;
|
||||
m_bit_depth = bit_depth;
|
||||
|
||||
if (m_is_fcTL_loaded && ((long long int)x0 + w0 > m_width || (long long int)y0 + h0 > m_height || dop > 2 || bop > 1))
|
||||
if (m_is_fcTL_loaded && ((int64_t)x0 + w0 > m_width || (int64_t)y0 + h0 > m_height || dop > 2 || bop > 1))
|
||||
return false;
|
||||
|
||||
png_color_16p background_color;
|
||||
@@ -456,7 +457,7 @@ bool PngDecoder::readData( Mat& img )
|
||||
if (dop == 2)
|
||||
memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize);
|
||||
|
||||
if (x0 + w0 > frameCur.getWidth() || y0 + h0 > frameCur.getHeight())
|
||||
if ((uint64_t)x0 + w0 > frameCur.getWidth() || (uint64_t)y0 + h0 > frameCur.getHeight())
|
||||
return false;
|
||||
|
||||
compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur);
|
||||
@@ -508,7 +509,7 @@ bool PngDecoder::readData( Mat& img )
|
||||
dop = chunk.p[32];
|
||||
bop = chunk.p[33];
|
||||
|
||||
if (int(x0 + w0) > img.cols || int(y0 + h0) > img.rows || dop > 2 || bop > 1)
|
||||
if ((int64_t)x0 + w0 > img.cols || (int64_t)y0 + h0 > img.rows || dop > 2 || bop > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -995,7 +995,7 @@ bool TiffDecoder::readData( Mat& img )
|
||||
break;
|
||||
|
||||
default:
|
||||
CV_LOG_ONCE_ERROR(NULL, "OpenCV TIFF(line " << __LINE__ << "): Unsupported convertion :"
|
||||
CV_LOG_ONCE_ERROR(NULL, "OpenCV TIFF(line " << __LINE__ << "): Unsupported conversion :"
|
||||
<< " bpp = " << bpp << " ncn = " << (int)ncn
|
||||
<< " wanted_channels =" << wanted_channels );
|
||||
break;
|
||||
|
||||
@@ -213,7 +213,7 @@ TEST(Imgcodecs_EXR, read_YA_unchanged)
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC2, img.type());
|
||||
|
||||
// Cannot test writing, 2 channel writing not suppported by loadsave
|
||||
// Cannot test writing, 2 channel writing not supported by loadsave
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, read_YC_changeDepth)
|
||||
|
||||
@@ -532,149 +532,153 @@ enum HistCompMethods {
|
||||
|
||||
/** the color conversion codes
|
||||
@see @ref imgproc_color_conversions
|
||||
@note The source image (src) must be of an appropriate type for the desired color conversion.
|
||||
- `[8U]` means to support `CV_8U` src type.
|
||||
- `[16U]` means to support `CV_16U` src type.
|
||||
- `[32F]` means to support `CV_32F` src type.
|
||||
@ingroup imgproc_color_conversions
|
||||
*/
|
||||
enum ColorConversionCodes {
|
||||
COLOR_BGR2BGRA = 0, //!< add alpha channel to RGB or BGR image
|
||||
COLOR_RGB2RGBA = COLOR_BGR2BGRA,
|
||||
COLOR_BGR2BGRA = 0, //!< [8U/16U/32F] add alpha channel to RGB or BGR image
|
||||
COLOR_RGB2RGBA = COLOR_BGR2BGRA, //!< [8U/16U/32F]
|
||||
|
||||
COLOR_BGRA2BGR = 1, //!< remove alpha channel from RGB or BGR image
|
||||
COLOR_RGBA2RGB = COLOR_BGRA2BGR,
|
||||
COLOR_BGRA2BGR = 1, //!< [8U/16U/32F] remove alpha channel from RGB or BGR image
|
||||
COLOR_RGBA2RGB = COLOR_BGRA2BGR, //!< [8U/16U/32F]
|
||||
|
||||
COLOR_BGR2RGBA = 2, //!< convert between RGB and BGR color spaces (with or without alpha channel)
|
||||
COLOR_RGB2BGRA = COLOR_BGR2RGBA,
|
||||
COLOR_BGR2RGBA = 2, //!< [8U/16U/32F] convert between RGB and BGR color spaces (with or without alpha channel)
|
||||
COLOR_RGB2BGRA = COLOR_BGR2RGBA, //!< [8U/16U/32F]
|
||||
|
||||
COLOR_RGBA2BGR = 3,
|
||||
COLOR_BGRA2RGB = COLOR_RGBA2BGR,
|
||||
COLOR_RGBA2BGR = 3, //!< [8U/16U/32F]
|
||||
COLOR_BGRA2RGB = COLOR_RGBA2BGR, //!< [8U/16U/32F]
|
||||
|
||||
COLOR_BGR2RGB = 4,
|
||||
COLOR_RGB2BGR = COLOR_BGR2RGB,
|
||||
COLOR_BGR2RGB = 4, //!< [8U/16U/32F]
|
||||
COLOR_RGB2BGR = COLOR_BGR2RGB, //!< [8U/16U/32F]
|
||||
|
||||
COLOR_BGRA2RGBA = 5,
|
||||
COLOR_RGBA2BGRA = COLOR_BGRA2RGBA,
|
||||
COLOR_BGRA2RGBA = 5, //!< [8U/16U/32F]
|
||||
COLOR_RGBA2BGRA = COLOR_BGRA2RGBA, //!< [8U/16U/32F]
|
||||
|
||||
COLOR_BGR2GRAY = 6, //!< convert between RGB/BGR and grayscale, @ref color_convert_rgb_gray "color conversions"
|
||||
COLOR_RGB2GRAY = 7,
|
||||
COLOR_GRAY2BGR = 8,
|
||||
COLOR_GRAY2RGB = COLOR_GRAY2BGR,
|
||||
COLOR_GRAY2BGRA = 9,
|
||||
COLOR_GRAY2RGBA = COLOR_GRAY2BGRA,
|
||||
COLOR_BGRA2GRAY = 10,
|
||||
COLOR_RGBA2GRAY = 11,
|
||||
COLOR_BGR2GRAY = 6, //!< [8U/16U/32F] convert between RGB/BGR and grayscale, @ref color_convert_rgb_gray "color conversions"
|
||||
COLOR_RGB2GRAY = 7, //!< [8U/16U/32F]
|
||||
COLOR_GRAY2BGR = 8, //!< [8U/16U/32F]
|
||||
COLOR_GRAY2RGB = COLOR_GRAY2BGR, //!< [8U/16U/32F]
|
||||
COLOR_GRAY2BGRA = 9, //!< [8U/16U/32F]
|
||||
COLOR_GRAY2RGBA = COLOR_GRAY2BGRA, //!< [8U/16U/32F]
|
||||
COLOR_BGRA2GRAY = 10, //!< [8U/16U/32F]
|
||||
COLOR_RGBA2GRAY = 11, //!< [8U/16U/32F]
|
||||
|
||||
COLOR_BGR2BGR565 = 12, //!< convert between RGB/BGR and BGR565 (16-bit images)
|
||||
COLOR_RGB2BGR565 = 13,
|
||||
COLOR_BGR5652BGR = 14,
|
||||
COLOR_BGR5652RGB = 15,
|
||||
COLOR_BGRA2BGR565 = 16,
|
||||
COLOR_RGBA2BGR565 = 17,
|
||||
COLOR_BGR5652BGRA = 18,
|
||||
COLOR_BGR5652RGBA = 19,
|
||||
COLOR_BGR2BGR565 = 12, //!< [8U] convert between RGB/BGR and BGR565 (16-bit images)
|
||||
COLOR_RGB2BGR565 = 13, //!< [8U]
|
||||
COLOR_BGR5652BGR = 14, //!< [8U]
|
||||
COLOR_BGR5652RGB = 15, //!< [8U]
|
||||
COLOR_BGRA2BGR565 = 16, //!< [8U]
|
||||
COLOR_RGBA2BGR565 = 17, //!< [8U]
|
||||
COLOR_BGR5652BGRA = 18, //!< [8U]
|
||||
COLOR_BGR5652RGBA = 19, //!< [8U]
|
||||
|
||||
COLOR_GRAY2BGR565 = 20, //!< convert between grayscale to BGR565 (16-bit images)
|
||||
COLOR_BGR5652GRAY = 21,
|
||||
COLOR_GRAY2BGR565 = 20, //!< [8U] convert between grayscale to BGR565 (16-bit images)
|
||||
COLOR_BGR5652GRAY = 21, //!< [8U]
|
||||
|
||||
COLOR_BGR2BGR555 = 22, //!< convert between RGB/BGR and BGR555 (16-bit images)
|
||||
COLOR_RGB2BGR555 = 23,
|
||||
COLOR_BGR5552BGR = 24,
|
||||
COLOR_BGR5552RGB = 25,
|
||||
COLOR_BGRA2BGR555 = 26,
|
||||
COLOR_RGBA2BGR555 = 27,
|
||||
COLOR_BGR5552BGRA = 28,
|
||||
COLOR_BGR5552RGBA = 29,
|
||||
COLOR_BGR2BGR555 = 22, //!< [8U] convert between RGB/BGR and BGR555 (16-bit images)
|
||||
COLOR_RGB2BGR555 = 23, //!< [8U]
|
||||
COLOR_BGR5552BGR = 24, //!< [8U]
|
||||
COLOR_BGR5552RGB = 25, //!< [8U]
|
||||
COLOR_BGRA2BGR555 = 26, //!< [8U]
|
||||
COLOR_RGBA2BGR555 = 27, //!< [8U]
|
||||
COLOR_BGR5552BGRA = 28, //!< [8U]
|
||||
COLOR_BGR5552RGBA = 29, //!< [8U]
|
||||
|
||||
COLOR_GRAY2BGR555 = 30, //!< convert between grayscale and BGR555 (16-bit images)
|
||||
COLOR_BGR5552GRAY = 31,
|
||||
COLOR_GRAY2BGR555 = 30, //!< [8U] convert between grayscale and BGR555 (16-bit images)
|
||||
COLOR_BGR5552GRAY = 31, //!< [8U]
|
||||
|
||||
COLOR_BGR2XYZ = 32, //!< convert RGB/BGR to CIE XYZ, @ref color_convert_rgb_xyz "color conversions"
|
||||
COLOR_RGB2XYZ = 33,
|
||||
COLOR_XYZ2BGR = 34,
|
||||
COLOR_XYZ2RGB = 35,
|
||||
COLOR_BGR2XYZ = 32, //!< [8U/16U/32F] convert RGB/BGR to CIE XYZ, @ref color_convert_rgb_xyz "color conversions"
|
||||
COLOR_RGB2XYZ = 33, //!< [8U/16U/32F]
|
||||
COLOR_XYZ2BGR = 34, //!< [8U/16U/32F]
|
||||
COLOR_XYZ2RGB = 35, //!< [8U/16U/32F]
|
||||
|
||||
COLOR_BGR2YCrCb = 36, //!< convert RGB/BGR to luma-chroma (aka YCC), @ref color_convert_rgb_ycrcb "color conversions"
|
||||
COLOR_RGB2YCrCb = 37,
|
||||
COLOR_YCrCb2BGR = 38,
|
||||
COLOR_YCrCb2RGB = 39,
|
||||
COLOR_BGR2YCrCb = 36, //!< [8U/16U/32F] convert RGB/BGR to luma-chroma (aka YCC), @ref color_convert_rgb_ycrcb "color conversions"
|
||||
COLOR_RGB2YCrCb = 37, //!< [8U/16U/32F]
|
||||
COLOR_YCrCb2BGR = 38, //!< [8U/16U/32F]
|
||||
COLOR_YCrCb2RGB = 39, //!< [8U/16U/32F]
|
||||
|
||||
COLOR_BGR2HSV = 40, //!< convert RGB/BGR to HSV (hue saturation value) with H range 0..180 if 8 bit image, @ref color_convert_rgb_hsv "color conversions"
|
||||
COLOR_RGB2HSV = 41,
|
||||
COLOR_BGR2HSV = 40, //!< [8U/32F] convert RGB/BGR to HSV (hue saturation value) with H range 0..180 if 8 bit image, @ref color_convert_rgb_hsv "color conversions"
|
||||
COLOR_RGB2HSV = 41, //!< [8U/32F]
|
||||
|
||||
COLOR_BGR2Lab = 44, //!< convert RGB/BGR to CIE Lab, @ref color_convert_rgb_lab "color conversions"
|
||||
COLOR_RGB2Lab = 45,
|
||||
COLOR_BGR2Lab = 44, //!< [8U/32F] convert RGB/BGR to CIE Lab, @ref color_convert_rgb_lab "color conversions"
|
||||
COLOR_RGB2Lab = 45, //!< [8U/32F]
|
||||
|
||||
COLOR_BGR2Luv = 50, //!< convert RGB/BGR to CIE Luv, @ref color_convert_rgb_luv "color conversions"
|
||||
COLOR_RGB2Luv = 51,
|
||||
COLOR_BGR2HLS = 52, //!< convert RGB/BGR to HLS (hue lightness saturation) with H range 0..180 if 8 bit image, @ref color_convert_rgb_hls "color conversions"
|
||||
COLOR_RGB2HLS = 53,
|
||||
COLOR_BGR2Luv = 50, //!< [8U/32F] convert RGB/BGR to CIE Luv, @ref color_convert_rgb_luv "color conversions"
|
||||
COLOR_RGB2Luv = 51, //!< [8U/32F]
|
||||
COLOR_BGR2HLS = 52, //!< [8U/32F] convert RGB/BGR to HLS (hue lightness saturation) with H range 0..180 if 8 bit image, @ref color_convert_rgb_hls "color conversions"
|
||||
COLOR_RGB2HLS = 53, //!< [8U/32F]
|
||||
|
||||
COLOR_HSV2BGR = 54, //!< backward conversions HSV to RGB/BGR with H range 0..180 if 8 bit image
|
||||
COLOR_HSV2RGB = 55,
|
||||
COLOR_HSV2BGR = 54, //!< [8U/32F] backward conversions HSV to RGB/BGR with H range 0..180 if 8 bit image
|
||||
COLOR_HSV2RGB = 55, //!< [8U/32F]
|
||||
|
||||
COLOR_Lab2BGR = 56,
|
||||
COLOR_Lab2RGB = 57,
|
||||
COLOR_Luv2BGR = 58,
|
||||
COLOR_Luv2RGB = 59,
|
||||
COLOR_HLS2BGR = 60, //!< backward conversions HLS to RGB/BGR with H range 0..180 if 8 bit image
|
||||
COLOR_HLS2RGB = 61,
|
||||
COLOR_Lab2BGR = 56, //!< [8U/32F]
|
||||
COLOR_Lab2RGB = 57, //!< [8U/32F]
|
||||
COLOR_Luv2BGR = 58, //!< [8U/32F]
|
||||
COLOR_Luv2RGB = 59, //!< [8U/32F]
|
||||
COLOR_HLS2BGR = 60, //!< [8U/32F] backward conversions HLS to RGB/BGR with H range 0..180 if 8 bit image
|
||||
COLOR_HLS2RGB = 61, //!< [8U/32F]
|
||||
|
||||
COLOR_BGR2HSV_FULL = 66, //!< convert RGB/BGR to HSV (hue saturation value) with H range 0..255 if 8 bit image, @ref color_convert_rgb_hsv "color conversions"
|
||||
COLOR_RGB2HSV_FULL = 67,
|
||||
COLOR_BGR2HLS_FULL = 68, //!< convert RGB/BGR to HLS (hue lightness saturation) with H range 0..255 if 8 bit image, @ref color_convert_rgb_hls "color conversions"
|
||||
COLOR_RGB2HLS_FULL = 69,
|
||||
COLOR_BGR2HSV_FULL = 66, //!< [8U/32F] convert RGB/BGR to HSV (hue saturation value) with H range 0..255 if 8 bit image, @ref color_convert_rgb_hsv "color conversions"
|
||||
COLOR_RGB2HSV_FULL = 67, //!< [8U/32F]
|
||||
COLOR_BGR2HLS_FULL = 68, //!< [8U/32F] convert RGB/BGR to HLS (hue lightness saturation) with H range 0..255 if 8 bit image, @ref color_convert_rgb_hls "color conversions"
|
||||
COLOR_RGB2HLS_FULL = 69, //!< [8U/32F]
|
||||
|
||||
COLOR_HSV2BGR_FULL = 70, //!< backward conversions HSV to RGB/BGR with H range 0..255 if 8 bit image
|
||||
COLOR_HSV2RGB_FULL = 71,
|
||||
COLOR_HLS2BGR_FULL = 72, //!< backward conversions HLS to RGB/BGR with H range 0..255 if 8 bit image
|
||||
COLOR_HLS2RGB_FULL = 73,
|
||||
COLOR_HSV2BGR_FULL = 70, //!< [8U/32F] backward conversions HSV to RGB/BGR with H range 0..255 if 8 bit image
|
||||
COLOR_HSV2RGB_FULL = 71, //!< [8U/32F]
|
||||
COLOR_HLS2BGR_FULL = 72, //!< [8U/32F] backward conversions HLS to RGB/BGR with H range 0..255 if 8 bit image
|
||||
COLOR_HLS2RGB_FULL = 73, //!< [8U/32F]
|
||||
|
||||
COLOR_LBGR2Lab = 74,
|
||||
COLOR_LRGB2Lab = 75,
|
||||
COLOR_LBGR2Luv = 76,
|
||||
COLOR_LRGB2Luv = 77,
|
||||
COLOR_LBGR2Lab = 74, //!< [8U/32F]
|
||||
COLOR_LRGB2Lab = 75, //!< [8U/32F]
|
||||
COLOR_LBGR2Luv = 76, //!< [8U/32F]
|
||||
COLOR_LRGB2Luv = 77, //!< [8U/32F]
|
||||
|
||||
COLOR_Lab2LBGR = 78,
|
||||
COLOR_Lab2LRGB = 79,
|
||||
COLOR_Luv2LBGR = 80,
|
||||
COLOR_Luv2LRGB = 81,
|
||||
COLOR_Lab2LBGR = 78, //!< [8U/32F]
|
||||
COLOR_Lab2LRGB = 79, //!< [8U/32F]
|
||||
COLOR_Luv2LBGR = 80, //!< [8U/32F]
|
||||
COLOR_Luv2LRGB = 81, //!< [8U/32F]
|
||||
|
||||
COLOR_BGR2YUV = 82, //!< convert between RGB/BGR and YUV
|
||||
COLOR_RGB2YUV = 83,
|
||||
COLOR_YUV2BGR = 84,
|
||||
COLOR_YUV2RGB = 85,
|
||||
COLOR_BGR2YUV = 82, //!< [8U/16U/32F] convert between RGB/BGR and YUV
|
||||
COLOR_RGB2YUV = 83, //!< [8U/16U/32F]
|
||||
COLOR_YUV2BGR = 84, //!< [8U/16U/32F]
|
||||
COLOR_YUV2RGB = 85, //!< [8U/16U/32F]
|
||||
|
||||
COLOR_YUV2RGB_NV12 = 90, //!< convert between 4:2:0-subsampled YUV NV12 and RGB, two planes (in one or separate arrays): Y and U/V interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_NV12 = 91, //!< convert between 4:2:0-subsampled YUV NV12 and BGR, two planes (in one or separate arrays): Y and U/V interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_NV21 = 92, //!< convert between 4:2:0-subsampled YUV NV21 and RGB, two planes (in one or separate arrays): Y and V/U interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_NV21 = 93, //!< convert between 4:2:0-subsampled YUV NV21 and BGR, two planes (in one or separate arrays): Y and V/U interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_NV12 = 90, //!< [8U] convert between 4:2:0-subsampled YUV NV12 and RGB, two planes (in one or separate arrays): Y and U/V interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_NV12 = 91, //!< [8U] convert between 4:2:0-subsampled YUV NV12 and BGR, two planes (in one or separate arrays): Y and U/V interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_NV21 = 92, //!< [8U] convert between 4:2:0-subsampled YUV NV21 and RGB, two planes (in one or separate arrays): Y and V/U interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_NV21 = 93, //!< [8U] convert between 4:2:0-subsampled YUV NV21 and BGR, two planes (in one or separate arrays): Y and V/U interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV420sp2RGB = COLOR_YUV2RGB_NV21, //!< synonym to NV21
|
||||
COLOR_YUV420sp2BGR = COLOR_YUV2BGR_NV21, //!< synonym to NV21
|
||||
|
||||
COLOR_YUV2RGBA_NV12 = 94, //!< convert between 4:2:0-subsampled YUV NV12 and RGBA, two planes (in one or separate arrays): Y and U/V interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_NV12 = 95, //!< convert between 4:2:0-subsampled YUV NV12 and BGRA, two planes (in one or separate arrays): Y and U/V interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_NV21 = 96, //!< convert between 4:2:0-subsampled YUV NV21 and RGBA, two planes (in one or separate arrays): Y and V/U interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_NV21 = 97, //!< convert between 4:2:0-subsampled YUV NV21 and BGRA, two planes (in one or separate arrays): Y and V/U interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_NV12 = 94, //!< [8U] convert between 4:2:0-subsampled YUV NV12 and RGBA, two planes (in one or separate arrays): Y and U/V interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_NV12 = 95, //!< [8U] convert between 4:2:0-subsampled YUV NV12 and BGRA, two planes (in one or separate arrays): Y and U/V interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_NV21 = 96, //!< [8U] convert between 4:2:0-subsampled YUV NV21 and RGBA, two planes (in one or separate arrays): Y and V/U interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_NV21 = 97, //!< [8U] convert between 4:2:0-subsampled YUV NV21 and BGRA, two planes (in one or separate arrays): Y and V/U interleaved, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV420sp2RGBA = COLOR_YUV2RGBA_NV21, //!< synonym to NV21
|
||||
COLOR_YUV420sp2BGRA = COLOR_YUV2BGRA_NV21, //!< synonym to NV21
|
||||
|
||||
COLOR_YUV2RGB_YV12 = 98, //!< convert between 4:2:0-subsampled YUV YV12 and RGB, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_YV12 = 99, //!< convert between 4:2:0-subsampled YUV YV12 and BGR, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_IYUV = 100, //!< convert between 4:2:0-subsampled YUV IYUV and RGB, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_IYUV = 101, //!< convert between 4:2:0-subsampled YUV IYUV and BGR, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_YV12 = 98, //!< [8U] convert between 4:2:0-subsampled YUV YV12 and RGB, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_YV12 = 99, //!< [8U] convert between 4:2:0-subsampled YUV YV12 and BGR, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_IYUV = 100, //!< [8U] convert between 4:2:0-subsampled YUV IYUV and RGB, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_IYUV = 101, //!< [8U] convert between 4:2:0-subsampled YUV IYUV and BGR, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_I420 = COLOR_YUV2RGB_IYUV, //!< synonym to IYUV
|
||||
COLOR_YUV2BGR_I420 = COLOR_YUV2BGR_IYUV, //!< synonym to IYUV
|
||||
COLOR_YUV420p2RGB = COLOR_YUV2RGB_YV12, //!< synonym to YV12
|
||||
COLOR_YUV420p2BGR = COLOR_YUV2BGR_YV12, //!< synonym to YV12
|
||||
|
||||
COLOR_YUV2RGBA_YV12 = 102, //!< convert between 4:2:0-subsampled YUV YV12 and RGBA, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_YV12 = 103, //!< convert between 4:2:0-subsampled YUV YV12 and BGRA, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_IYUV = 104, //!< convert between 4:2:0-subsampled YUV YV12 and RGBA, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_IYUV = 105, //!< convert between 4:2:0-subsampled YUV YV12 and BGRA, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_YV12 = 102, //!< [8U] convert between 4:2:0-subsampled YUV YV12 and RGBA, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_YV12 = 103, //!< [8U] convert between 4:2:0-subsampled YUV YV12 and BGRA, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_IYUV = 104, //!< [8U] convert between 4:2:0-subsampled YUV YV12 and RGBA, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_IYUV = 105, //!< [8U] convert between 4:2:0-subsampled YUV YV12 and BGRA, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_I420 = COLOR_YUV2RGBA_IYUV, //!< synonym to IYUV
|
||||
COLOR_YUV2BGRA_I420 = COLOR_YUV2BGRA_IYUV, //!< synonym to IYUV
|
||||
COLOR_YUV420p2RGBA = COLOR_YUV2RGBA_YV12, //!< synonym to YV12
|
||||
COLOR_YUV420p2BGRA = COLOR_YUV2BGRA_YV12, //!< synonym to YV12
|
||||
|
||||
COLOR_YUV2GRAY_420 = 106, //!< extract Y channel from YUV 4:2:0 image
|
||||
COLOR_YUV2GRAY_420 = 106, //!< [8U] extract Y channel from YUV 4:2:0 image
|
||||
COLOR_YUV2GRAY_NV21 = COLOR_YUV2GRAY_420, //!< synonym to COLOR_YUV2GRAY_420
|
||||
COLOR_YUV2GRAY_NV12 = COLOR_YUV2GRAY_420, //!< synonym to COLOR_YUV2GRAY_420
|
||||
COLOR_YUV2GRAY_YV12 = COLOR_YUV2GRAY_420, //!< synonym to COLOR_YUV2GRAY_420
|
||||
@@ -683,8 +687,8 @@ enum ColorConversionCodes {
|
||||
COLOR_YUV420sp2GRAY = COLOR_YUV2GRAY_420, //!< synonym to COLOR_YUV2GRAY_420
|
||||
COLOR_YUV420p2GRAY = COLOR_YUV2GRAY_420, //!< synonym to COLOR_YUV2GRAY_420
|
||||
|
||||
COLOR_YUV2RGB_UYVY = 107, //!< convert between YUV UYVY and RGB, YUV is 4:2:2-subsampled and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_UYVY = 108, //!< convert between YUV UYVY and BGR, YUV is 4:2:2-subsampled and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_UYVY = 107, //!< [8U] convert between YUV UYVY and RGB, YUV is 4:2:2-subsampled and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_UYVY = 108, //!< [8U] convert between YUV UYVY and BGR, YUV is 4:2:2-subsampled and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
//COLOR_YUV2RGB_VYUY = 109, //!< convert between YUV VYUY and RGB, YUV is 4:2:2-subsampled and interleaved as V/Y1/U/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
//COLOR_YUV2BGR_VYUY = 110, //!< convert between YUV VYUY and BGR, YUV is 4:2:2-subsampled and interleaved as V/Y1/U/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_Y422 = COLOR_YUV2RGB_UYVY, //!< synonym to UYVY
|
||||
@@ -692,180 +696,181 @@ enum ColorConversionCodes {
|
||||
COLOR_YUV2RGB_UYNV = COLOR_YUV2RGB_UYVY, //!< synonym to UYVY
|
||||
COLOR_YUV2BGR_UYNV = COLOR_YUV2BGR_UYVY, //!< synonym to UYVY
|
||||
|
||||
COLOR_YUV2RGBA_UYVY = 111, //!< convert between YUV UYVY and RGBA, YUV is 4:2:2-subsampled and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_UYVY = 112, //!< convert between YUV UYVY and BGRA, YUV is 4:2:2-subsampled and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
//COLOR_YUV2RGBA_VYUY = 113, //!< convert between YUV VYUY and RGBA, YUV is 4:2:2-subsampled and interleaved as V/Y1/U/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
//COLOR_YUV2BGRA_VYUY = 114, //!< convert between YUV VYUY and BGRA, YUV is 4:2:2-subsampled and interleaved as V/Y1/U/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_UYVY = 111, //!< [8U] convert between YUV UYVY and RGBA, YUV is 4:2:2-subsampled and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_UYVY = 112, //!< [8U] convert between YUV UYVY and BGRA, YUV is 4:2:2-subsampled and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
//COLOR_YUV2RGBA_VYUY = 113, //!< [8U] convert between YUV VYUY and RGBA, YUV is 4:2:2-subsampled and interleaved as V/Y1/U/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
//COLOR_YUV2BGRA_VYUY = 114, //!< [8U] convert between YUV VYUY and BGRA, YUV is 4:2:2-subsampled and interleaved as V/Y1/U/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_Y422 = COLOR_YUV2RGBA_UYVY, //!< synonym to UYVY
|
||||
COLOR_YUV2BGRA_Y422 = COLOR_YUV2BGRA_UYVY, //!< synonym to UYVY
|
||||
COLOR_YUV2RGBA_UYNV = COLOR_YUV2RGBA_UYVY, //!< synonym to UYVY
|
||||
COLOR_YUV2BGRA_UYNV = COLOR_YUV2BGRA_UYVY, //!< synonym to UYVY
|
||||
|
||||
COLOR_YUV2RGB_YUY2 = 115, //!< convert between YUV YUY2 and RGB, YUV is 4:2:2-subsampled and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_YUY2 = 116, //!< convert between YUV YUY2 and BGR, YUV is 4:2:2-subsampled and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_YVYU = 117, //!< convert between YUV YVYU and RGB, YUV is 4:2:2-subsampled and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_YVYU = 118, //!< convert between YUV YVYU and BGR, YUV is 4:2:2-subsampled and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_YUY2 = 115, //!< [8U] convert between YUV YUY2 and RGB, YUV is 4:2:2-subsampled and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_YUY2 = 116, //!< [8U] convert between YUV YUY2 and BGR, YUV is 4:2:2-subsampled and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_YVYU = 117, //!< [8U] convert between YUV YVYU and RGB, YUV is 4:2:2-subsampled and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGR_YVYU = 118, //!< [8U] convert between YUV YVYU and BGR, YUV is 4:2:2-subsampled and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGB_YUYV = COLOR_YUV2RGB_YUY2, //!< synonym to YUY2
|
||||
COLOR_YUV2BGR_YUYV = COLOR_YUV2BGR_YUY2, //!< synonym to YUY2
|
||||
COLOR_YUV2RGB_YUNV = COLOR_YUV2RGB_YUY2, //!< synonym to YUY2
|
||||
COLOR_YUV2BGR_YUNV = COLOR_YUV2BGR_YUY2, //!< synonym to YUY2
|
||||
|
||||
COLOR_YUV2RGBA_YUY2 = 119, //!< convert between YUV YUY2 and RGBA, YUV is 4:2:2-subsampled and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_YUY2 = 120, //!< convert between YUV YUY2 and BGRA, YUV is 4:2:2-subsampled and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_YVYU = 121, //!< convert between YUV YVYU and RGBA, YUV is 4:2:2-subsampled and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_YVYU = 122, //!< convert between YUV YVYU and BGRA, YUV is 4:2:2-subsampled and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_YUY2 = 119, //!< [8U] convert between YUV YUY2 and RGBA, YUV is 4:2:2-subsampled and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_YUY2 = 120, //!< [8U] convert between YUV YUY2 and BGRA, YUV is 4:2:2-subsampled and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_YVYU = 121, //!< [8U] convert between YUV YVYU and RGBA, YUV is 4:2:2-subsampled and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2BGRA_YVYU = 122, //!< [8U] convert between YUV YVYU and BGRA, YUV is 4:2:2-subsampled and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_YUV2RGBA_YUYV = COLOR_YUV2RGBA_YUY2, //!< synonym to YUY2
|
||||
COLOR_YUV2BGRA_YUYV = COLOR_YUV2BGRA_YUY2, //!< synonym to YUY2
|
||||
COLOR_YUV2RGBA_YUNV = COLOR_YUV2RGBA_YUY2, //!< synonym to YUY2
|
||||
COLOR_YUV2BGRA_YUNV = COLOR_YUV2BGRA_YUY2, //!< synonym to YUY2
|
||||
|
||||
COLOR_YUV2GRAY_UYVY = 123, //!< extract Y channel from YUV 4:2:2 image
|
||||
COLOR_YUV2GRAY_YUY2 = 124, //!< extract Y channel from YUV 4:2:2 image
|
||||
//COLOR_YUV2GRAY_VYUY = COLOR_YUV2GRAY_UYVY,
|
||||
COLOR_YUV2GRAY_UYVY = 123, //!< [8U] extract Y channel from YUV 4:2:2 image
|
||||
COLOR_YUV2GRAY_YUY2 = 124, //!< [8U] extract Y channel from YUV 4:2:2 image
|
||||
//CV_YUV2GRAY_VYUY = CV_YUV2GRAY_UYVY, //!< synonym to COLOR_YUV2GRAY_UYVY
|
||||
COLOR_YUV2GRAY_Y422 = COLOR_YUV2GRAY_UYVY, //!< synonym to COLOR_YUV2GRAY_UYVY
|
||||
COLOR_YUV2GRAY_UYNV = COLOR_YUV2GRAY_UYVY, //!< synonym to COLOR_YUV2GRAY_UYVY
|
||||
COLOR_YUV2GRAY_YVYU = COLOR_YUV2GRAY_YUY2, //!< synonym to COLOR_YUV2GRAY_YUY2
|
||||
COLOR_YUV2GRAY_YUYV = COLOR_YUV2GRAY_YUY2, //!< synonym to COLOR_YUV2GRAY_YUY2
|
||||
COLOR_YUV2GRAY_YUNV = COLOR_YUV2GRAY_YUY2, //!< synonym to COLOR_YUV2GRAY_YUY2
|
||||
|
||||
//! alpha premultiplication
|
||||
COLOR_RGBA2mRGBA = 125,
|
||||
COLOR_mRGBA2RGBA = 126,
|
||||
COLOR_RGBA2mRGBA = 125, //!< [8U]
|
||||
COLOR_mRGBA2RGBA = 126, //!< [8U]
|
||||
|
||||
COLOR_RGB2YUV_I420 = 127, //!< convert between RGB and 4:2:0-subsampled YUV I420, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGR2YUV_I420 = 128, //!< convert between BGR and 4:2:0-subsampled YUV I420, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGB2YUV_I420 = 127, //!< [8U] convert between RGB and 4:2:0-subsampled YUV I420, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGR2YUV_I420 = 128, //!< [8U] convert between BGR and 4:2:0-subsampled YUV I420, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGB2YUV_IYUV = COLOR_RGB2YUV_I420, //!< synonym to I420
|
||||
COLOR_BGR2YUV_IYUV = COLOR_BGR2YUV_I420, //!< synonym to I420
|
||||
|
||||
COLOR_RGBA2YUV_I420 = 129, //!< convert between RGBA and 4:2:0-subsampled YUV I420, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGRA2YUV_I420 = 130, //!< convert between BGRA and 4:2:0-subsampled YUV I420, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGBA2YUV_I420 = 129, //!< [8U] convert between RGBA and 4:2:0-subsampled YUV I420, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGRA2YUV_I420 = 130, //!< [8U] convert between BGRA and 4:2:0-subsampled YUV I420, three planes in one array: Y, U and V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGBA2YUV_IYUV = COLOR_RGBA2YUV_I420, //!< synonym to I420
|
||||
COLOR_BGRA2YUV_IYUV = COLOR_BGRA2YUV_I420, //!< synonym to I420
|
||||
COLOR_RGB2YUV_YV12 = 131, //!< convert between RGB and 4:2:0-subsampled YUV YV12, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGR2YUV_YV12 = 132, //!< convert between BGR and 4:2:0-subsampled YUV YV12, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGBA2YUV_YV12 = 133, //!< convert between RGBA and 4:2:0-subsampled YUV YV12, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGRA2YUV_YV12 = 134, //!< convert between BGRA and 4:2:0-subsampled YUV YV12, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGB2YUV_YV12 = 131, //!< [8U] convert between RGB and 4:2:0-subsampled YUV YV12, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGR2YUV_YV12 = 132, //!< [8U] convert between BGR and 4:2:0-subsampled YUV YV12, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGBA2YUV_YV12 = 133, //!< [8U] convert between RGBA and 4:2:0-subsampled YUV YV12, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGRA2YUV_YV12 = 134, //!< [8U] convert between BGRA and 4:2:0-subsampled YUV YV12, three planes in one array: Y, V and U, see @ref color_convert_rgb_yuv_42x
|
||||
|
||||
//! Demosaicing, see @ref color_convert_bayer "color conversions" for additional information
|
||||
COLOR_BayerBG2BGR = 46, //!< equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2BGR = 47, //!< equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2BGR = 48, //!< equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2BGR = 49, //!< equivalent to GBRG Bayer pattern
|
||||
COLOR_BayerBG2BGR = 46, //!< [8U/16U] equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2BGR = 47, //!< [8U/16U] equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2BGR = 48, //!< [8U/16U] equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2BGR = 49, //!< [8U/16U] equivalent to GBRG Bayer pattern
|
||||
|
||||
COLOR_BayerRGGB2BGR = COLOR_BayerBG2BGR,
|
||||
COLOR_BayerGRBG2BGR = COLOR_BayerGB2BGR,
|
||||
COLOR_BayerBGGR2BGR = COLOR_BayerRG2BGR,
|
||||
COLOR_BayerGBRG2BGR = COLOR_BayerGR2BGR,
|
||||
COLOR_BayerRGGB2BGR = COLOR_BayerBG2BGR, //!< [8U/16U]
|
||||
COLOR_BayerGRBG2BGR = COLOR_BayerGB2BGR, //!< [8U/16U]
|
||||
COLOR_BayerBGGR2BGR = COLOR_BayerRG2BGR, //!< [8U/16U]
|
||||
COLOR_BayerGBRG2BGR = COLOR_BayerGR2BGR, //!< [8U/16U]
|
||||
|
||||
COLOR_BayerRGGB2RGB = COLOR_BayerBGGR2BGR,
|
||||
COLOR_BayerGRBG2RGB = COLOR_BayerGBRG2BGR,
|
||||
COLOR_BayerBGGR2RGB = COLOR_BayerRGGB2BGR,
|
||||
COLOR_BayerGBRG2RGB = COLOR_BayerGRBG2BGR,
|
||||
COLOR_BayerRGGB2RGB = COLOR_BayerBGGR2BGR, //!< [8U/16U]
|
||||
COLOR_BayerGRBG2RGB = COLOR_BayerGBRG2BGR, //!< [8U/16U]
|
||||
COLOR_BayerBGGR2RGB = COLOR_BayerRGGB2BGR, //!< [8U/16U]
|
||||
COLOR_BayerGBRG2RGB = COLOR_BayerGRBG2BGR, //!< [8U/16U]
|
||||
|
||||
COLOR_BayerBG2RGB = COLOR_BayerRG2BGR, //!< equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2RGB = COLOR_BayerGR2BGR, //!< equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2RGB = COLOR_BayerBG2BGR, //!< equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2RGB = COLOR_BayerGB2BGR, //!< equivalent to GBRG Bayer pattern
|
||||
COLOR_BayerBG2RGB = COLOR_BayerRG2BGR, //!< [8U/16U] equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2RGB = COLOR_BayerGR2BGR, //!< [8U/16U] equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2RGB = COLOR_BayerBG2BGR, //!< [8U/16U] equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2RGB = COLOR_BayerGB2BGR, //!< [8U/16U] equivalent to GBRG Bayer pattern
|
||||
|
||||
COLOR_BayerBG2GRAY = 86, //!< equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2GRAY = 87, //!< equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2GRAY = 88, //!< equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2GRAY = 89, //!< equivalent to GBRG Bayer pattern
|
||||
COLOR_BayerBG2GRAY = 86, //!< [8U/16U] equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2GRAY = 87, //!< [8U/16U] equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2GRAY = 88, //!< [8U/16U] equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2GRAY = 89, //!< [8U/16U] equivalent to GBRG Bayer pattern
|
||||
|
||||
COLOR_BayerRGGB2GRAY = COLOR_BayerBG2GRAY,
|
||||
COLOR_BayerGRBG2GRAY = COLOR_BayerGB2GRAY,
|
||||
COLOR_BayerBGGR2GRAY = COLOR_BayerRG2GRAY,
|
||||
COLOR_BayerGBRG2GRAY = COLOR_BayerGR2GRAY,
|
||||
COLOR_BayerRGGB2GRAY = COLOR_BayerBG2GRAY, //!< [8U/16U]
|
||||
COLOR_BayerGRBG2GRAY = COLOR_BayerGB2GRAY, //!< [8U/16U]
|
||||
COLOR_BayerBGGR2GRAY = COLOR_BayerRG2GRAY, //!< [8U/16U]
|
||||
COLOR_BayerGBRG2GRAY = COLOR_BayerGR2GRAY, //!< [8U/16U]
|
||||
|
||||
//! Demosaicing using Variable Number of Gradients
|
||||
COLOR_BayerBG2BGR_VNG = 62, //!< equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2BGR_VNG = 63, //!< equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2BGR_VNG = 64, //!< equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2BGR_VNG = 65, //!< equivalent to GBRG Bayer pattern
|
||||
COLOR_BayerBG2BGR_VNG = 62, //!< [8U] equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2BGR_VNG = 63, //!< [8U] equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2BGR_VNG = 64, //!< [8U] equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2BGR_VNG = 65, //!< [8U] equivalent to GBRG Bayer pattern
|
||||
|
||||
COLOR_BayerRGGB2BGR_VNG = COLOR_BayerBG2BGR_VNG,
|
||||
COLOR_BayerGRBG2BGR_VNG = COLOR_BayerGB2BGR_VNG,
|
||||
COLOR_BayerBGGR2BGR_VNG = COLOR_BayerRG2BGR_VNG,
|
||||
COLOR_BayerGBRG2BGR_VNG = COLOR_BayerGR2BGR_VNG,
|
||||
COLOR_BayerRGGB2BGR_VNG = COLOR_BayerBG2BGR_VNG, //!< [8U]
|
||||
COLOR_BayerGRBG2BGR_VNG = COLOR_BayerGB2BGR_VNG, //!< [8U]
|
||||
COLOR_BayerBGGR2BGR_VNG = COLOR_BayerRG2BGR_VNG, //!< [8U]
|
||||
COLOR_BayerGBRG2BGR_VNG = COLOR_BayerGR2BGR_VNG, //!< [8U]
|
||||
|
||||
COLOR_BayerRGGB2RGB_VNG = COLOR_BayerBGGR2BGR_VNG,
|
||||
COLOR_BayerGRBG2RGB_VNG = COLOR_BayerGBRG2BGR_VNG,
|
||||
COLOR_BayerBGGR2RGB_VNG = COLOR_BayerRGGB2BGR_VNG,
|
||||
COLOR_BayerGBRG2RGB_VNG = COLOR_BayerGRBG2BGR_VNG,
|
||||
COLOR_BayerRGGB2RGB_VNG = COLOR_BayerBGGR2BGR_VNG, //!< [8U]
|
||||
COLOR_BayerGRBG2RGB_VNG = COLOR_BayerGBRG2BGR_VNG, //!< [8U]
|
||||
COLOR_BayerBGGR2RGB_VNG = COLOR_BayerRGGB2BGR_VNG, //!< [8U]
|
||||
COLOR_BayerGBRG2RGB_VNG = COLOR_BayerGRBG2BGR_VNG, //!< [8U]
|
||||
|
||||
COLOR_BayerBG2RGB_VNG = COLOR_BayerRG2BGR_VNG, //!< equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2RGB_VNG = COLOR_BayerGR2BGR_VNG, //!< equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2RGB_VNG = COLOR_BayerBG2BGR_VNG, //!< equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2RGB_VNG = COLOR_BayerGB2BGR_VNG, //!< equivalent to GBRG Bayer pattern
|
||||
COLOR_BayerBG2RGB_VNG = COLOR_BayerRG2BGR_VNG, //!< [8U] equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2RGB_VNG = COLOR_BayerGR2BGR_VNG, //!< [8U] equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2RGB_VNG = COLOR_BayerBG2BGR_VNG, //!< [8U] equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2RGB_VNG = COLOR_BayerGB2BGR_VNG, //!< [8U] equivalent to GBRG Bayer pattern
|
||||
|
||||
//! Edge-Aware Demosaicing
|
||||
COLOR_BayerBG2BGR_EA = 135, //!< equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2BGR_EA = 136, //!< equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2BGR_EA = 137, //!< equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2BGR_EA = 138, //!< equivalent to GBRG Bayer pattern
|
||||
COLOR_BayerBG2BGR_EA = 135, //!< [8U/16U] equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2BGR_EA = 136, //!< [8U/16U] equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2BGR_EA = 137, //!< [8U/16U] equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2BGR_EA = 138, //!< [8U/16U] equivalent to GBRG Bayer pattern
|
||||
|
||||
COLOR_BayerRGGB2BGR_EA = COLOR_BayerBG2BGR_EA,
|
||||
COLOR_BayerGRBG2BGR_EA = COLOR_BayerGB2BGR_EA,
|
||||
COLOR_BayerBGGR2BGR_EA = COLOR_BayerRG2BGR_EA,
|
||||
COLOR_BayerGBRG2BGR_EA = COLOR_BayerGR2BGR_EA,
|
||||
COLOR_BayerRGGB2BGR_EA = COLOR_BayerBG2BGR_EA, //!< [8U/16U]
|
||||
COLOR_BayerGRBG2BGR_EA = COLOR_BayerGB2BGR_EA, //!< [8U/16U]
|
||||
COLOR_BayerBGGR2BGR_EA = COLOR_BayerRG2BGR_EA, //!< [8U/16U]
|
||||
COLOR_BayerGBRG2BGR_EA = COLOR_BayerGR2BGR_EA, //!< [8U/16U]
|
||||
|
||||
COLOR_BayerRGGB2RGB_EA = COLOR_BayerBGGR2BGR_EA,
|
||||
COLOR_BayerGRBG2RGB_EA = COLOR_BayerGBRG2BGR_EA,
|
||||
COLOR_BayerBGGR2RGB_EA = COLOR_BayerRGGB2BGR_EA,
|
||||
COLOR_BayerGBRG2RGB_EA = COLOR_BayerGRBG2BGR_EA,
|
||||
COLOR_BayerRGGB2RGB_EA = COLOR_BayerBGGR2BGR_EA, //!< [8U/16U]
|
||||
COLOR_BayerGRBG2RGB_EA = COLOR_BayerGBRG2BGR_EA, //!< [8U/16U]
|
||||
COLOR_BayerBGGR2RGB_EA = COLOR_BayerRGGB2BGR_EA, //!< [8U/16U]
|
||||
COLOR_BayerGBRG2RGB_EA = COLOR_BayerGRBG2BGR_EA, //!< [8U/16U]
|
||||
|
||||
COLOR_BayerBG2RGB_EA = COLOR_BayerRG2BGR_EA, //!< equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2RGB_EA = COLOR_BayerGR2BGR_EA, //!< equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2RGB_EA = COLOR_BayerBG2BGR_EA, //!< equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2RGB_EA = COLOR_BayerGB2BGR_EA, //!< equivalent to GBRG Bayer pattern
|
||||
COLOR_BayerBG2RGB_EA = COLOR_BayerRG2BGR_EA, //!< [8U/16U] equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2RGB_EA = COLOR_BayerGR2BGR_EA, //!< [8U/16U] equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2RGB_EA = COLOR_BayerBG2BGR_EA, //!< [8U/16U] equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2RGB_EA = COLOR_BayerGB2BGR_EA, //!< [8U/16U] equivalent to GBRG Bayer pattern
|
||||
|
||||
//! Demosaicing with alpha channel
|
||||
COLOR_BayerBG2BGRA = 139, //!< equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2BGRA = 140, //!< equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2BGRA = 141, //!< equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2BGRA = 142, //!< equivalent to GBRG Bayer pattern
|
||||
COLOR_BayerBG2BGRA = 139, //!< [8U/16U] equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2BGRA = 140, //!< [8U/16U] equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2BGRA = 141, //!< [8U/16U] equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2BGRA = 142, //!< [8U/16U] equivalent to GBRG Bayer pattern
|
||||
|
||||
COLOR_BayerRGGB2BGRA = COLOR_BayerBG2BGRA,
|
||||
COLOR_BayerGRBG2BGRA = COLOR_BayerGB2BGRA,
|
||||
COLOR_BayerBGGR2BGRA = COLOR_BayerRG2BGRA,
|
||||
COLOR_BayerGBRG2BGRA = COLOR_BayerGR2BGRA,
|
||||
COLOR_BayerRGGB2BGRA = COLOR_BayerBG2BGRA, //!< [8U/16U]
|
||||
COLOR_BayerGRBG2BGRA = COLOR_BayerGB2BGRA, //!< [8U/16U]
|
||||
COLOR_BayerBGGR2BGRA = COLOR_BayerRG2BGRA, //!< [8U/16U]
|
||||
COLOR_BayerGBRG2BGRA = COLOR_BayerGR2BGRA, //!< [8U/16U]
|
||||
|
||||
COLOR_BayerRGGB2RGBA = COLOR_BayerBGGR2BGRA,
|
||||
COLOR_BayerGRBG2RGBA = COLOR_BayerGBRG2BGRA,
|
||||
COLOR_BayerBGGR2RGBA = COLOR_BayerRGGB2BGRA,
|
||||
COLOR_BayerGBRG2RGBA = COLOR_BayerGRBG2BGRA,
|
||||
COLOR_BayerRGGB2RGBA = COLOR_BayerBGGR2BGRA, //!< [8U/16U]
|
||||
COLOR_BayerGRBG2RGBA = COLOR_BayerGBRG2BGRA, //!< [8U/16U]
|
||||
COLOR_BayerBGGR2RGBA = COLOR_BayerRGGB2BGRA, //!< [8U/16U]
|
||||
COLOR_BayerGBRG2RGBA = COLOR_BayerGRBG2BGRA, //!< [8U/16U]
|
||||
|
||||
COLOR_BayerBG2RGBA = COLOR_BayerRG2BGRA, //!< equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2RGBA = COLOR_BayerGR2BGRA, //!< equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2RGBA = COLOR_BayerBG2BGRA, //!< equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2RGBA = COLOR_BayerGB2BGRA, //!< equivalent to GBRG Bayer pattern
|
||||
COLOR_BayerBG2RGBA = COLOR_BayerRG2BGRA, //!< [8U/16U] equivalent to RGGB Bayer pattern
|
||||
COLOR_BayerGB2RGBA = COLOR_BayerGR2BGRA, //!< [8U/16U] equivalent to GRBG Bayer pattern
|
||||
COLOR_BayerRG2RGBA = COLOR_BayerBG2BGRA, //!< [8U/16U] equivalent to BGGR Bayer pattern
|
||||
COLOR_BayerGR2RGBA = COLOR_BayerGB2BGRA, //!< [8U/16U] equivalent to GBRG Bayer pattern
|
||||
|
||||
COLOR_RGB2YUV_UYVY = 143, //!< convert between RGB and YUV UYVU, YUV is 4:2:2 and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGR2YUV_UYVY = 144, //!< convert between BGR and YUV UYVU, YUV is 4:2:2 and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGB2YUV_UYVY = 143, //!< [8U] convert between RGB and YUV UYVU, YUV is 4:2:2 and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGR2YUV_UYVY = 144, //!< [8U] convert between BGR and YUV UYVU, YUV is 4:2:2 and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGB2YUV_Y422 = COLOR_RGB2YUV_UYVY, //!< synonym to UYVY
|
||||
COLOR_BGR2YUV_Y422 = COLOR_BGR2YUV_UYVY, //!< synonym to UYVY
|
||||
COLOR_RGB2YUV_UYNV = COLOR_RGB2YUV_UYVY, //!< synonym to UYVY
|
||||
COLOR_BGR2YUV_UYNV = COLOR_BGR2YUV_UYVY, //!< synonym to UYVY
|
||||
|
||||
COLOR_RGBA2YUV_UYVY = 145, //!< convert between RGBA and YUV UYVU, YUV is 4:2:2 and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGRA2YUV_UYVY = 146, //!< convert between BGRA and YUV UYVU, YUV is 4:2:2 and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGBA2YUV_UYVY = 145, //!< [8U] convert between RGBA and YUV UYVU, YUV is 4:2:2 and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGRA2YUV_UYVY = 146, //!< [8U] convert between BGRA and YUV UYVU, YUV is 4:2:2 and interleaved as U/Y1/V/Y2, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGBA2YUV_Y422 = COLOR_RGBA2YUV_UYVY, //!< synonym to UYVY
|
||||
COLOR_BGRA2YUV_Y422 = COLOR_BGRA2YUV_UYVY, //!< synonym to UYVY
|
||||
COLOR_RGBA2YUV_UYNV = COLOR_RGBA2YUV_UYVY, //!< synonym to UYVY
|
||||
COLOR_BGRA2YUV_UYNV = COLOR_BGRA2YUV_UYVY, //!< synonym to UYVY
|
||||
|
||||
COLOR_RGB2YUV_YUY2 = 147, //!< convert between RGB and YUV YUY2, YUV is 4:2:2 and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGR2YUV_YUY2 = 148, //!< convert between BGR and YUV YUY2, YUV is 4:2:2 and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGB2YUV_YVYU = 149, //!< convert between RGB and YUV YVYU, YUV is 4:2:2 and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGR2YUV_YVYU = 150, //!< convert between BGR and YUV YVYU, YUV is 4:2:2 and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGB2YUV_YUY2 = 147, //!< [8U] convert between RGB and YUV YUY2, YUV is 4:2:2 and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGR2YUV_YUY2 = 148, //!< [8U] convert between BGR and YUV YUY2, YUV is 4:2:2 and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGB2YUV_YVYU = 149, //!< [8U] convert between RGB and YUV YVYU, YUV is 4:2:2 and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGR2YUV_YVYU = 150, //!< [8U] convert between BGR and YUV YVYU, YUV is 4:2:2 and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGB2YUV_YUYV = COLOR_RGB2YUV_YUY2, //!< synonym to YUY2
|
||||
COLOR_BGR2YUV_YUYV = COLOR_BGR2YUV_YUY2, //!< synonym to YUY2
|
||||
COLOR_RGB2YUV_YUNV = COLOR_RGB2YUV_YUY2, //!< synonym to YUY2
|
||||
COLOR_BGR2YUV_YUNV = COLOR_BGR2YUV_YUY2, //!< synonym to YUY2
|
||||
|
||||
COLOR_RGBA2YUV_YUY2 = 151, //!< convert between RGBA and YUV YUY2, YUV is 4:2:2 and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGRA2YUV_YUY2 = 152, //!< convert between BGRA and YUV YUY2, YUV is 4:2:2 and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGBA2YUV_YVYU = 153, //!< convert between RGBA and YUV YVYU, YUV is 4:2:2 and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGRA2YUV_YVYU = 154, //!< convert between BGRA and YUV YVYU, YUV is 4:2:2 and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGBA2YUV_YUY2 = 151, //!< [8U] convert between RGBA and YUV YUY2, YUV is 4:2:2 and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGRA2YUV_YUY2 = 152, //!< [8U] convert between BGRA and YUV YUY2, YUV is 4:2:2 and interleaved as Y1/U/Y2/V, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGBA2YUV_YVYU = 153, //!< [8U] convert between RGBA and YUV YVYU, YUV is 4:2:2 and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_BGRA2YUV_YVYU = 154, //!< [8U] convert between BGRA and YUV YVYU, YUV is 4:2:2 and interleaved as Y1/V/Y2/U, see @ref color_convert_rgb_yuv_42x
|
||||
COLOR_RGBA2YUV_YUYV = COLOR_RGBA2YUV_YUY2, //!< synonym to YUY2
|
||||
COLOR_BGRA2YUV_YUYV = COLOR_BGRA2YUV_YUY2, //!< synonym to YUY2
|
||||
COLOR_RGBA2YUV_YUNV = COLOR_RGBA2YUV_YUY2, //!< synonym to YUY2
|
||||
@@ -2999,6 +3004,22 @@ peak) and will be smaller when there are multiple peaks.
|
||||
CV_EXPORTS_W Point2d phaseCorrelate(InputArray src1, InputArray src2,
|
||||
InputArray window = noArray(), CV_OUT double* response = 0);
|
||||
|
||||
/** @brief Detects translational shifts between two images.
|
||||
|
||||
This function extends the standard @ref phaseCorrelate method by improving sub-pixel accuracy
|
||||
through iterative shift refinement in the phase-correlation space, as described in
|
||||
@cite hrazdira2020iterative.
|
||||
|
||||
@param src1 Source floating point array (CV_32FC1 or CV_64FC1)
|
||||
@param src2 Source floating point array (CV_32FC1 or CV_64FC1)
|
||||
@param L2size The size of the correlation neighborhood used by the iterative shift refinement algorithm.
|
||||
@param maxIters The maximum number of iterations the iterative refinement algorithm will run.
|
||||
@returns detected sub-pixel shift between the two arrays.
|
||||
|
||||
@sa phaseCorrelate, dft, idft, createHanningWindow
|
||||
*/
|
||||
CV_EXPORTS_W Point2d phaseCorrelateIterative(InputArray src1, InputArray src2, int L2size = 7, int maxIters = 10);
|
||||
|
||||
/** @brief This function computes a Hanning window coefficients in two dimensions.
|
||||
|
||||
See (https://en.wikipedia.org/wiki/Hann_function) and (https://en.wikipedia.org/wiki/Window_function)
|
||||
@@ -3736,6 +3757,7 @@ floating-point.
|
||||
channels is derived automatically from src and code.
|
||||
@param hint Implementation modification flags. See #AlgorithmHint
|
||||
|
||||
@note The source image (src) must be of an appropriate type for the desired color conversion. see ColorConversionCodes
|
||||
@see @ref imgproc_color_conversions
|
||||
*/
|
||||
CV_EXPORTS_W void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0, AlgorithmHint hint = cv::ALGO_HINT_DEFAULT );
|
||||
@@ -3789,6 +3811,7 @@ The function can do the following transformations:
|
||||
|
||||
#COLOR_BayerBG2BGRA , #COLOR_BayerGB2BGRA , #COLOR_BayerRG2BGRA , #COLOR_BayerGR2BGRA
|
||||
|
||||
@note The source image (src) must be of an appropriate type for the desired color conversion. see ColorConversionCodes
|
||||
@sa cvtColor
|
||||
*/
|
||||
CV_EXPORTS_W void demosaicing(InputArray src, OutputArray dst, int code, int dstCn = 0);
|
||||
@@ -3812,6 +3835,18 @@ used for images only.
|
||||
@note Only applicable to contour moments calculations from Python bindings: Note that the numpy
|
||||
type for the input array should be either np.int32 or np.float32.
|
||||
|
||||
@note For contour-based moments, the zeroth-order moment \c m00 represents
|
||||
the contour area.
|
||||
|
||||
If the input contour is degenerate (for example, a single point or all points
|
||||
are collinear), the area is zero and therefore \c m00 == 0.
|
||||
|
||||
In this case, the centroid coordinates (\c m10/m00, \c m01/m00) are undefined
|
||||
and must be handled explicitly by the caller.
|
||||
|
||||
A common workaround is to compute the center using cv::boundingRect() or by
|
||||
averaging the input points.
|
||||
|
||||
@sa contourArea, arcLength
|
||||
*/
|
||||
CV_EXPORTS_W Moments moments( InputArray array, bool binaryImage = false );
|
||||
@@ -4219,7 +4254,7 @@ area. It takes the set of points and the parameter k as input and returns the ar
|
||||
enclosing polygon.
|
||||
|
||||
The Implementation is based on a paper by Aggarwal, Chang and Yap @cite Aggarwal1985. They
|
||||
provide a \f$\theta(n²log(n)log(k))\f$ algorighm for finding the minimal convex polygon with k
|
||||
provide a \f$\theta(n²log(n)log(k))\f$ algorithm for finding the minimal convex polygon with k
|
||||
vertices enclosing a 2D convex polygon with n vertices (k < n). Since the #minEnclosingConvexPolygon
|
||||
function takes a 2D point set as input, an additional preprocessing step of computing the convex hull
|
||||
of the 2D point set is required. The complexity of the #convexHull function is \f$O(n log(n))\f$ which
|
||||
|
||||
@@ -162,26 +162,40 @@ approxPolyDP_( const Point_<T>* src_contour, int count0, Point_<T>* dst_contour,
|
||||
|
||||
if( pos != slice.end )
|
||||
{
|
||||
double dx, dy, dist, max_dist = 0;
|
||||
double dx, dy, max_dist_2_mul_segment_len_2 = 0;
|
||||
|
||||
dx = end_pt.x - start_pt.x;
|
||||
dy = end_pt.y - start_pt.y;
|
||||
double segment_len_2 = dx * dx + dy * dy;
|
||||
|
||||
CV_Assert( dx != 0 || dy != 0 );
|
||||
|
||||
while( pos != slice.end )
|
||||
{
|
||||
READ_PT(pt, pos);
|
||||
dist = fabs((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy);
|
||||
double projection = ((pt.x - start_pt.x) * dx + (pt.y - start_pt.y) * dy);
|
||||
|
||||
if( dist > max_dist )
|
||||
double dist_2_mul_segment_len_2;
|
||||
if ( projection < 0 )
|
||||
{
|
||||
max_dist = dist;
|
||||
dist_2_mul_segment_len_2 = ((pt.x - start_pt.x) * (pt.x - start_pt.x) + (pt.y - start_pt.y) * (pt.y - start_pt.y)) * segment_len_2;
|
||||
} else if ( projection > segment_len_2 )
|
||||
{
|
||||
dist_2_mul_segment_len_2 = ((pt.x - end_pt.x) * (pt.x - end_pt.x) + (pt.y - end_pt.y) * (pt.y - end_pt.y)) * segment_len_2;
|
||||
} else
|
||||
{
|
||||
double dist = ((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy);
|
||||
dist_2_mul_segment_len_2 = dist * dist;
|
||||
}
|
||||
|
||||
if( dist_2_mul_segment_len_2 > max_dist_2_mul_segment_len_2 )
|
||||
{
|
||||
max_dist_2_mul_segment_len_2 = dist_2_mul_segment_len_2;
|
||||
right_slice.start = (pos+count-1)%count;
|
||||
}
|
||||
}
|
||||
|
||||
le_eps = max_dist * max_dist <= eps * (dx * dx + dy * dy);
|
||||
le_eps = max_dist_2_mul_segment_len_2 <= eps * segment_len_2;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -321,7 +321,7 @@ bilateralFilter_32f( const Mat& src, Mat& dst, int d,
|
||||
}
|
||||
|
||||
// parallel_for usage
|
||||
CV_CPU_DISPATCH(bilateralFilterInvoker_32f, (cn, radius, maxk, space_ofs, temp, dst, scale_index, space_weight, expLUT),
|
||||
CV_CPU_DISPATCH(bilateralFilterInvoker_32f, (cn, radius, maxk, space_ofs, temp, dst, scale_index, space_weight, expLUT, kExpNumBins),
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ void bilateralFilterInvoker_8u(
|
||||
int* space_ofs, float *space_weight, float *color_weight);
|
||||
void bilateralFilterInvoker_32f(
|
||||
int cn, int radius, int maxk, int *space_ofs,
|
||||
const Mat& temp, Mat& dst, float scale_index, float *space_weight, float *expLUT);
|
||||
const Mat& temp, Mat& dst, float scale_index, float *space_weight, float *expLUT, int kExpNumBins);
|
||||
|
||||
#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
|
||||
|
||||
@@ -495,9 +495,9 @@ class BilateralFilter_32f_Invoker :
|
||||
public:
|
||||
|
||||
BilateralFilter_32f_Invoker(int _cn, int _radius, int _maxk, int *_space_ofs,
|
||||
const Mat& _temp, Mat& _dest, float _scale_index, float *_space_weight, float *_expLUT) :
|
||||
const Mat& _temp, Mat& _dest, float _scale_index, float *_space_weight, float *_expLUT, int _kExpNumBins) :
|
||||
cn(_cn), radius(_radius), maxk(_maxk), space_ofs(_space_ofs),
|
||||
temp(&_temp), dest(&_dest), scale_index(_scale_index), space_weight(_space_weight), expLUT(_expLUT)
|
||||
temp(&_temp), dest(&_dest), scale_index(_scale_index), space_weight(_space_weight), expLUT(_expLUT), kExpNumBins(_kExpNumBins)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -550,7 +550,7 @@ public:
|
||||
v_float32 val0 = vx_load(ksptr);
|
||||
v_float32 knan0 = v_not_nan(val0);
|
||||
v_float32 alpha0 = v_and(v_and(v_mul(v_absdiff(val0, rval0), sindex), v_not_nan(rval0)), knan0);
|
||||
v_int32 idx0 = v_trunc(alpha0);
|
||||
v_int32 idx0 = v_min(v_trunc(alpha0), vx_setall_s32(kExpNumBins));
|
||||
alpha0 = v_sub(alpha0, v_cvt_f32(idx0));
|
||||
v_float32 w0 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx0), alpha0, v_mul(v_lut(this->expLUT, idx0), v_sub(v_one, alpha0)))), knan0);
|
||||
v_wsum0 = v_add(v_wsum0, w0);
|
||||
@@ -560,7 +560,7 @@ public:
|
||||
v_float32 val1 = vx_load(ksptr + nlanes);
|
||||
v_float32 knan1 = v_not_nan(val1);
|
||||
v_float32 alpha1 = v_and(v_and(v_mul(v_absdiff(val1, rval1), sindex), v_not_nan(rval1)), knan1);
|
||||
v_int32 idx1 = v_trunc(alpha1);
|
||||
v_int32 idx1 = v_min(v_trunc(alpha1), vx_setall_s32(kExpNumBins));
|
||||
alpha1 = v_sub(alpha1, v_cvt_f32(idx1));
|
||||
v_float32 w1 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx1), alpha1, v_mul(v_lut(this->expLUT, idx1), v_sub(v_one, alpha1)))), knan1);
|
||||
v_wsum1 = v_add(v_wsum1, w1);
|
||||
@@ -570,7 +570,7 @@ public:
|
||||
v_float32 val2 = vx_load(ksptr + nlanes_2);
|
||||
v_float32 knan2 = v_not_nan(val2);
|
||||
v_float32 alpha2 = v_and(v_and(v_mul(v_absdiff(val2, rval2), sindex), v_not_nan(rval2)), knan2);
|
||||
v_int32 idx2 = v_trunc(alpha2);
|
||||
v_int32 idx2 = v_min(v_trunc(alpha2), vx_setall_s32(kExpNumBins));
|
||||
alpha2 = v_sub(alpha2, v_cvt_f32(idx2));
|
||||
v_float32 w2 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx2), alpha2, v_mul(v_lut(this->expLUT, idx2), v_sub(v_one, alpha2)))), knan2);
|
||||
v_wsum2 = v_add(v_wsum2, w2);
|
||||
@@ -580,7 +580,7 @@ public:
|
||||
v_float32 val3 = vx_load(ksptr + nlanes_3);
|
||||
v_float32 knan3 = v_not_nan(val3);
|
||||
v_float32 alpha3 = v_and(v_and(v_mul(v_absdiff(val3, rval3), sindex), v_not_nan(rval3)), knan3);
|
||||
v_int32 idx3 = v_trunc(alpha3);
|
||||
v_int32 idx3 = v_min(v_trunc(alpha3), vx_setall_s32(kExpNumBins));
|
||||
alpha3 = v_sub(alpha3, v_cvt_f32(idx3));
|
||||
v_float32 w3 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx3), alpha3, v_mul(v_lut(this->expLUT, idx3), v_sub(v_one, alpha3)))), knan3);
|
||||
v_wsum3 = v_add(v_wsum3, w3);
|
||||
@@ -611,7 +611,7 @@ public:
|
||||
v_float32 val0 = vx_load(ksptr);
|
||||
v_float32 knan0 = v_not_nan(val0);
|
||||
v_float32 alpha0 = v_and(v_and(v_mul(v_absdiff(val0, rval0), sindex), rval0_not_nan), knan0);
|
||||
v_int32 idx0 = v_trunc(alpha0);
|
||||
v_int32 idx0 = v_min(v_trunc(alpha0), vx_setall_s32(kExpNumBins));
|
||||
alpha0 = v_sub(alpha0, v_cvt_f32(idx0));
|
||||
v_float32 w0 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx0), alpha0, v_mul(v_lut(this->expLUT, idx0), v_sub(v_one, alpha0)))), knan0);
|
||||
v_wsum0 = v_add(v_wsum0, w0);
|
||||
@@ -621,7 +621,7 @@ public:
|
||||
v_float32 val1 = vx_load(ksptr + nlanes);
|
||||
v_float32 knan1 = v_not_nan(val1);
|
||||
v_float32 alpha1 = v_and(v_and(v_mul(v_absdiff(val1, rval1), sindex), rval1_not_nan), knan1);
|
||||
v_int32 idx1 = v_trunc(alpha1);
|
||||
v_int32 idx1 = v_min(v_trunc(alpha1), vx_setall_s32(kExpNumBins));
|
||||
alpha1 = v_sub(alpha1, v_cvt_f32(idx1));
|
||||
v_float32 w1 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx1), alpha1, v_mul(v_lut(this->expLUT, idx1), v_sub(v_one, alpha1)))), knan1);
|
||||
v_wsum1 = v_add(v_wsum1, w1);
|
||||
@@ -640,7 +640,7 @@ public:
|
||||
{
|
||||
const float* ksptr = sptr_j + space_ofs[k];
|
||||
float val = *ksptr;
|
||||
float alpha = std::abs(val - rval) * scale_index;
|
||||
float alpha = std::min(std::abs(val - rval) * scale_index, (float)kExpNumBins);
|
||||
int idx = cvFloor(alpha);
|
||||
alpha -= idx;
|
||||
if (!cvIsNaN(val))
|
||||
@@ -681,7 +681,7 @@ public:
|
||||
|
||||
v_float32 knan = v_and(v_and(v_not_nan(kb), v_not_nan(kg)), v_not_nan(kr));
|
||||
v_float32 alpha = v_and(v_and(v_and(v_and(v_mul(v_add(v_add(v_absdiff(kb, rb), v_absdiff(kg, rg)), v_absdiff(kr, rr)), sindex), v_not_nan(rb)), v_not_nan(rg)), v_not_nan(rr)), knan);
|
||||
v_int32 idx = v_trunc(alpha);
|
||||
v_int32 idx = v_min(v_trunc(alpha), vx_setall_s32(kExpNumBins));
|
||||
alpha = v_sub(alpha, v_cvt_f32(idx));
|
||||
|
||||
v_float32 w = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx), alpha, v_mul(v_lut(this->expLUT, idx), v_sub(v_one, alpha)))), knan);
|
||||
@@ -709,7 +709,7 @@ public:
|
||||
bool v_NAN = cvIsNaN(b) || cvIsNaN(g) || cvIsNaN(r);
|
||||
float rb = rsptr[0], rg = rsptr[1], rr = rsptr[2];
|
||||
bool r_NAN = cvIsNaN(rb) || cvIsNaN(rg) || cvIsNaN(rr);
|
||||
float alpha = (std::abs(b - rb) + std::abs(g - rg) + std::abs(r - rr)) * scale_index;
|
||||
float alpha = std::min((std::abs(b - rb) + std::abs(g - rg) + std::abs(r - rr)) * scale_index, (float)kExpNumBins);
|
||||
int idx = cvFloor(alpha);
|
||||
alpha -= idx;
|
||||
if (!v_NAN)
|
||||
@@ -753,17 +753,18 @@ private:
|
||||
const Mat* temp;
|
||||
Mat *dest;
|
||||
float scale_index, *space_weight, *expLUT;
|
||||
int kExpNumBins;
|
||||
};
|
||||
|
||||
} // namespace anon
|
||||
|
||||
void bilateralFilterInvoker_32f(
|
||||
int cn, int radius, int maxk, int *space_ofs,
|
||||
const Mat& temp, Mat& dst, float scale_index, float *space_weight, float *expLUT)
|
||||
const Mat& temp, Mat& dst, float scale_index, float *space_weight, float *expLUT, int kExpNumBins)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
BilateralFilter_32f_Invoker body(cn, radius, maxk, space_ofs, temp, dst, scale_index, space_weight, expLUT);
|
||||
BilateralFilter_32f_Invoker body(cn, radius, maxk, space_ofs, temp, dst, scale_index, space_weight, expLUT, kExpNumBins);
|
||||
parallel_for_(Range(0, dst.rows), body, dst.total()/(double)(1<<16));
|
||||
}
|
||||
|
||||
|
||||
@@ -219,9 +219,9 @@ void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool ret
|
||||
}
|
||||
|
||||
for( i = 0; i < tl_count-1; i++ )
|
||||
hullbuf[nout++] = int(pointer[tl_stack[i]] - data0);
|
||||
hullbuf[nout++] = tl_stack[i];
|
||||
for( i = tr_count - 1; i > 0; i-- )
|
||||
hullbuf[nout++] = int(pointer[tr_stack[i]] - data0);
|
||||
hullbuf[nout++] = tr_stack[i];
|
||||
int stop_idx = tr_count > 2 ? tr_stack[1] : tl_count > 2 ? tl_stack[tl_count - 2] : -1;
|
||||
|
||||
// lower half
|
||||
@@ -257,9 +257,43 @@ void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool ret
|
||||
}
|
||||
|
||||
for( i = 0; i < bl_count-1; i++ )
|
||||
hullbuf[nout++] = int(pointer[bl_stack[i]] - data0);
|
||||
hullbuf[nout++] = bl_stack[i];
|
||||
for( i = br_count-1; i > 0; i-- )
|
||||
hullbuf[nout++] = int(pointer[br_stack[i]] - data0);
|
||||
hullbuf[nout++] = br_stack[i];
|
||||
|
||||
if (!returnPoints)
|
||||
{
|
||||
// Try keep monotonous indices in case of self-intersection.
|
||||
for (i = 0; i < nout; ++i)
|
||||
{
|
||||
auto prev = pointer[hullbuf[(i == 0 ? nout : i) - 1]];
|
||||
auto next = pointer[hullbuf[(i + 1) % nout]];
|
||||
auto cur = pointer[hullbuf[i]];
|
||||
if ((prev < cur && cur < next) || (prev > cur && cur > next))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int j = hullbuf[i] + 1; j < total; ++j)
|
||||
{
|
||||
cur = pointer[j];
|
||||
if (*pointer[hullbuf[i]] == *cur)
|
||||
{
|
||||
if ((prev < cur && cur < next) || (prev > cur && cur > next))
|
||||
{
|
||||
hullbuf[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for (i = 0; i < nout; ++i)
|
||||
{
|
||||
hullbuf[i] = int(pointer[hullbuf[i]] - data0);
|
||||
}
|
||||
|
||||
// try to make the convex hull indices form
|
||||
// an ascending or descending sequence by the cyclic
|
||||
|
||||
@@ -1668,7 +1668,7 @@ ThickLine( Mat& img, Point2l p0, Point2l p1, const void* color,
|
||||
{
|
||||
if( line_type < cv::LINE_AA )
|
||||
{
|
||||
if( line_type == 1 || line_type == 4 || shift == 0 )
|
||||
if( line_type == 1 || line_type == 8 || shift == 0 )
|
||||
{
|
||||
p0.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
|
||||
p0.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
|
||||
|
||||
@@ -1171,8 +1171,24 @@ static bool replacementFilter2D(int stype, int dtype, int kernel_type,
|
||||
int anchor_x, int anchor_y,
|
||||
double delta, int borderType, bool isSubmatrix)
|
||||
{
|
||||
// Prioritize stateless implementation
|
||||
int res = cv_hal_filter_stateless(src_data, src_step, stype,
|
||||
dst_data, dst_step, dtype, width, height,
|
||||
full_width, full_height, offset_x, offset_y,
|
||||
kernel_data, kernel_step, kernel_type,
|
||||
kernel_width, kernel_height, anchor_x, anchor_y,
|
||||
delta, borderType, isSubmatrix, src_data == dst_data);
|
||||
if (res == CV_HAL_ERROR_OK)
|
||||
{
|
||||
return true;
|
||||
} else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED)
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation filter_stateless ==> " CVAUX_STR(cv_hal_filter_stateless) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
cvhalFilter2D* ctx;
|
||||
int res = cv_hal_filterInit(&ctx, kernel_data, kernel_step, kernel_type, kernel_width, kernel_height, width, height,
|
||||
res = cv_hal_filterInit(&ctx, kernel_data, kernel_step, kernel_type, kernel_width, kernel_height, width, height,
|
||||
stype, dtype, borderType, delta, anchor_x, anchor_y, isSubmatrix, src_data == dst_data);
|
||||
if (res == CV_HAL_ERROR_NOT_IMPLEMENTED)
|
||||
{
|
||||
@@ -1385,8 +1401,23 @@ static bool replacementSepFilter(int stype, int dtype, int ktype,
|
||||
uchar * kernely_data, int kernely_len,
|
||||
int anchor_x, int anchor_y, double delta, int borderType)
|
||||
{
|
||||
// Prioritize stateless implementation
|
||||
int res = cv_hal_sepFilter_stateless(src_data, src_step, stype,
|
||||
dst_data, dst_step, dtype,
|
||||
width, height, full_width, full_height, offset_x, offset_y,
|
||||
kernelx_data, kernelx_len, kernely_data, kernely_len, ktype,
|
||||
anchor_x, anchor_y, delta, borderType);
|
||||
if (res == CV_HAL_ERROR_OK)
|
||||
{
|
||||
return true;
|
||||
} else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED)
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation sepFilter_stateless ==> " CVAUX_STR(cv_hal_sepFilter_stateless) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
cvhalFilter2D *ctx;
|
||||
int res = cv_hal_sepFilterInit(&ctx, stype, dtype, ktype,
|
||||
res = cv_hal_sepFilterInit(&ctx, stype, dtype, ktype,
|
||||
kernelx_data, kernelx_len,
|
||||
kernely_data, kernely_len,
|
||||
anchor_x, anchor_y, delta, borderType);
|
||||
|
||||
@@ -86,6 +86,40 @@ int my_hal_filterFree(cvhalFilter2D *context) {
|
||||
*/
|
||||
struct cvhalFilter2D {};
|
||||
|
||||
/**
|
||||
@brief 2D filtering in a stateless manner
|
||||
@param src_data source image data
|
||||
@param src_step source image step
|
||||
@param src_type source image type
|
||||
@param dst_data destination image data
|
||||
@param dst_step destination image step
|
||||
@param dst_type destination image type
|
||||
@param width images width
|
||||
@param height images height
|
||||
@param full_width full width of source image (outside the ROI)
|
||||
@param full_height full height of source image (outside the ROI)
|
||||
@param offset_x source image ROI offset X
|
||||
@param offset_y source image ROI offset Y
|
||||
@param kernel_data pointer to kernel data
|
||||
@param kernel_step kernel step
|
||||
@param kernel_type kernel type (CV_8U, ...)
|
||||
@param kernel_width kernel width
|
||||
@param kernel_height kernel height
|
||||
@param anchor_x relative X position of center point within the kernel
|
||||
@param anchor_y relative Y position of center point within the kernel
|
||||
@param delta added to pixel values
|
||||
@param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
|
||||
@param isSubmatrix indicates whether the submatrices will be allowed as source image
|
||||
@param allowInplace indicates whether the inplace operation will be possible
|
||||
@sa cv::filter2D, cv::hal::Filter2D
|
||||
*/
|
||||
inline int hal_ni_filter_stateless(const uchar * src_data, size_t src_step, int src_type,
|
||||
uchar * dst_data, size_t dst_step, int dst_type,
|
||||
int width, int height, int full_width, int full_height, int offset_x, int offset_y,
|
||||
const uchar * kernel_data, size_t kernel_step, int kernel_type, int kernel_width, int kernel_height,
|
||||
int anchor_x, int anchor_y, double delta, int borderType, bool isSubmatrix, bool allowInplace)
|
||||
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
/**
|
||||
@brief hal_filterInit
|
||||
@param context double pointer to user-defined context
|
||||
@@ -131,11 +165,45 @@ inline int hal_ni_filter(cvhalFilter2D *context, uchar *src_data, size_t src_ste
|
||||
inline int hal_ni_filterFree(cvhalFilter2D *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
//! @cond IGNORED
|
||||
#define cv_hal_filter_stateless hal_ni_filter_stateless
|
||||
#define cv_hal_filterInit hal_ni_filterInit
|
||||
#define cv_hal_filter hal_ni_filter
|
||||
#define cv_hal_filterFree hal_ni_filterFree
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
@brief separable filtering in a stateless manner
|
||||
@param src_data source image data
|
||||
@param src_step source image step
|
||||
@param src_type source image type
|
||||
@param dst_data destination image data
|
||||
@param dst_step destination image step
|
||||
@param dst_type destination image type
|
||||
@param width images width
|
||||
@param height images height
|
||||
@param full_width full width of source image (outside the ROI)
|
||||
@param full_height full height of source image (outside the ROI)
|
||||
@param offset_x source image ROI offset X
|
||||
@param offset_y source image ROI offset Y
|
||||
@param kernelx_data pointer to x-kernel data
|
||||
@param kernelx_len x-kernel vector length
|
||||
@param kernely_data pointer to y-kernel data
|
||||
@param kernely_len y-kernel vector length
|
||||
@param kernel_type kernel type (CV_8U, ...)
|
||||
@param anchor_x relative X position of center point within the kernel
|
||||
@param anchor_y relative Y position of center point within the kernel
|
||||
@param delta added to pixel values
|
||||
@param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
|
||||
@sa cv::sepFilter2D, cv::hal::SepFilter2D
|
||||
*/
|
||||
inline int hal_ni_sepFilter_stateless(const uchar * src_data, size_t src_step, int src_type,
|
||||
uchar * dst_data, size_t dst_step, int dst_type,
|
||||
int width, int height, int full_width, int full_height, int offset_x, int offset_y,
|
||||
const uchar * kernelx_data, int kernelx_len,
|
||||
const uchar * kernely_data, int kernely_len,
|
||||
int kernel_type, int anchor_x, int anchor_y, double delta, int borderType)
|
||||
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
/**
|
||||
@brief hal_sepFilterInit
|
||||
@param context double pointer to user-defined context
|
||||
@@ -177,11 +245,54 @@ inline int hal_ni_sepFilter(cvhalFilter2D *context, uchar *src_data, size_t src_
|
||||
inline int hal_ni_sepFilterFree(cvhalFilter2D *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
//! @cond IGNORED
|
||||
#define cv_hal_sepFilter_stateless hal_ni_sepFilter_stateless
|
||||
#define cv_hal_sepFilterInit hal_ni_sepFilterInit
|
||||
#define cv_hal_sepFilter hal_ni_sepFilter
|
||||
#define cv_hal_sepFilterFree hal_ni_sepFilterFree
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
@brief morphology in a stateless manner
|
||||
@param operation morphology operation CV_HAL_MORPH_ERODE or CV_HAL_MORPH_DILATE
|
||||
@param src_data source image data
|
||||
@param src_step source image step
|
||||
@param src_type source image type
|
||||
@param dst_data destination image data
|
||||
@param dst_step destination image step
|
||||
@param dst_type destination image type
|
||||
@param width images width
|
||||
@param height images height
|
||||
@param src_full_width full width of source image (outside the ROI)
|
||||
@param src_full_height full height of source image (outside the ROI)
|
||||
@param src_roi_x source image ROI X offset
|
||||
@param src_roi_y source image ROI Y offset
|
||||
@param dst_full_width full width of destination image
|
||||
@param dst_full_height full height of destination image
|
||||
@param dst_roi_x destination image ROI X offset
|
||||
@param dst_roi_y destination image ROI Y offset
|
||||
@param kernel_data pointer to kernel data
|
||||
@param kernel_step kernel step
|
||||
@param kernel_type kernel type (CV_8U, ...)
|
||||
@param kernel_width kernel width
|
||||
@param kernel_height kernel height
|
||||
@param anchor_x relative X position of center point within the kernel
|
||||
@param anchor_y relative Y position of center point within the kernel
|
||||
@param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
|
||||
@param borderValue values to use for CV_HAL_BORDER_CONSTANT mode
|
||||
@param iterations number of iterations
|
||||
@param allowSubmatrix indicates whether the submatrices will be allowed as source image
|
||||
@param allowInplace indicates whether the inplace operation will be possible
|
||||
@sa cv::erode, cv::dilate, cv::morphologyEx, cv::hal::Morph
|
||||
*/
|
||||
inline int hal_ni_morph_stateless(int operation, const uchar * src_data, size_t src_step, int src_type,
|
||||
uchar * dst_data, size_t dst_step, int dst_type,
|
||||
int width, int height, int src_full_width, int src_full_height, int src_roi_x, int src_roi_y,
|
||||
int dst_full_width, int dst_full_height, int dst_roi_x, int dst_roi_y,
|
||||
const uchar * kernel_data, size_t kernel_step, int kernel_type, int kernel_width, int kernel_height,
|
||||
int anchor_x, int anchor_y, int borderType, const double borderValue[4],
|
||||
int iterations, bool allowSubmatrix, bool allowInplace)
|
||||
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
/**
|
||||
@brief hal_morphInit
|
||||
@param context double pointer to user-defined context
|
||||
@@ -233,6 +344,7 @@ inline int hal_ni_morph(cvhalFilter2D *context, uchar *src_data, size_t src_step
|
||||
inline int hal_ni_morphFree(cvhalFilter2D *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
//! @cond IGNORED
|
||||
#define cv_hal_morph_stateless hal_ni_morph_stateless
|
||||
#define cv_hal_morphInit hal_ni_morphInit
|
||||
#define cv_hal_morph hal_ni_morph
|
||||
#define cv_hal_morphFree hal_ni_morphFree
|
||||
|
||||
@@ -1024,7 +1024,7 @@ void HoughLinesPointSet( InputArray _point, OutputArray _lines, int lines_max, i
|
||||
int r = idx - (n+1)*(numrho+2) - 1;
|
||||
line.rho = static_cast<float>(min_rho) + r * (float)rho_step;
|
||||
line.angle = static_cast<float>(min_theta) + n * (float)theta_step;
|
||||
lines.push_back(Vec3d((double)accum[idx], (double)line.rho, (double)line.angle));
|
||||
lines.emplace_back((double)accum[idx], (double)line.rho, (double)line.angle);
|
||||
}
|
||||
|
||||
Mat(lines).copyTo(_lines);
|
||||
@@ -1125,7 +1125,7 @@ public:
|
||||
{
|
||||
if (ptr[x])
|
||||
{
|
||||
list.push_back(Point(x, y));
|
||||
list.emplace_back(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1489,7 +1489,7 @@ protected:
|
||||
// Check if the circle has enough support
|
||||
if(maxCount > accThreshold)
|
||||
{
|
||||
circlesLocal.push_back(EstimatedCircle(Vec3f(curCenter.x, curCenter.y, rBest), maxCount));
|
||||
circlesLocal.emplace_back(Vec3f(curCenter.x, curCenter.y, rBest), maxCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1847,7 +1847,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
|
||||
continue;
|
||||
|
||||
mdata[y*mstep + x] = (uchar)1;
|
||||
stack.push_back(Point(x, y));
|
||||
stack.emplace_back(x, y);
|
||||
bool backtrace_mode = false;
|
||||
|
||||
do
|
||||
@@ -1858,7 +1858,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
|
||||
int vy = dyData[p.y*dxystep + p.x];
|
||||
|
||||
float mag = std::sqrt((float)vx*vx+(float)vy*vy);
|
||||
nz.push_back(Vec4f((float)p.x, (float)p.y, (float)vx, (float)vy));
|
||||
nz.emplace_back((float)p.x, (float)p.y, (float)vx, (float)vy);
|
||||
CV_Assert(mdata[p.y*mstep + p.x] == 1);
|
||||
|
||||
int sx = cvRound(vx * RAY_FP_SCALE / mag);
|
||||
@@ -1903,7 +1903,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
|
||||
if( mdata[y_*mstep + x_] || !edgeData[y_*estep + x_])
|
||||
continue;
|
||||
mdata[y_*mstep + x_] = (uchar)1;
|
||||
stack.push_back(Point(x_, y_));
|
||||
stack.emplace_back(x_, y_);
|
||||
neighbors++;
|
||||
}
|
||||
|
||||
@@ -1919,7 +1919,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
|
||||
// insert a special "stop marker" in the end of each
|
||||
// connected component to make sure we
|
||||
// finalize and analyze the arc segment
|
||||
nz.push_back(Vec4f(0.f, 0.f, 0.f, 0.f));
|
||||
nz.emplace_back(0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1951,7 +1951,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
|
||||
{
|
||||
float cx = (float)((left + x - 1)*dp*0.5f);
|
||||
float cy = (float)(y*dp);
|
||||
centers.push_back(Point2f(cx, cy));
|
||||
centers.emplace_back(cx, cy);
|
||||
left = -1;
|
||||
}
|
||||
}
|
||||
@@ -2223,7 +2223,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
|
||||
// (accepted ? '+' : '-'), cx, cy, rk, cjk.weight, count, max_runlen, cjk.mask);
|
||||
|
||||
if( accepted )
|
||||
local_circles.push_back(EstimatedCircle(Vec3f(cx, cy, (float)rk), cjk.weight));
|
||||
local_circles.emplace_back(Vec3f(cx, cy, (float)rk), cjk.weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,8 +212,22 @@ static bool halMorph(int op, int src_type, int dst_type,
|
||||
int kernel_width, int kernel_height, int anchor_x, int anchor_y,
|
||||
int borderType, const double borderValue[4], int iterations, bool isSubmatrix)
|
||||
{
|
||||
// Prioritize stateless implementation
|
||||
int res = cv_hal_morph_stateless(op, src_data, src_step, src_type, dst_data, dst_step, dst_type, width, height,
|
||||
roi_width, roi_height, roi_x, roi_y, roi_width2, roi_height2, roi_x2, roi_y2,
|
||||
kernel_data, kernel_step, kernel_type, kernel_width, kernel_height, anchor_x, anchor_y,
|
||||
borderType, borderValue, iterations, isSubmatrix, src_data == dst_data);
|
||||
if (res == CV_HAL_ERROR_OK)
|
||||
{
|
||||
return true;
|
||||
} else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED)
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation morph_stateless ==> " CVAUX_STR(cv_hal_morph_stateless) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
cvhalFilter2D * ctx;
|
||||
int res = cv_hal_morphInit(&ctx, op, src_type, dst_type, width, height,
|
||||
res = cv_hal_morphInit(&ctx, op, src_type, dst_type, width, height,
|
||||
kernel_type, kernel_data, kernel_step, kernel_width, kernel_height,
|
||||
anchor_x, anchor_y,
|
||||
borderType, borderValue,
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
#include "precomp.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
void calculateCrossPowerSpectrum(const cv::Mat& dft1, const cv::Mat& dft2, cv::Mat& cps)
|
||||
{
|
||||
for (int row = 0; row < dft1.rows; ++row)
|
||||
{
|
||||
auto* cpsp = cps.ptr<cv::Vec<T, 2>>(row);
|
||||
const auto* dft1p = dft1.ptr<cv::Vec<T, 2>>(row);
|
||||
const auto* dft2p = dft2.ptr<cv::Vec<T, 2>>(row);
|
||||
for (int col = 0; col < dft1.cols; ++col)
|
||||
{
|
||||
const T re = dft1p[col][0] * dft2p[col][0] + dft1p[col][1] * dft2p[col][1];
|
||||
const T im = dft1p[col][0] * dft2p[col][1] - dft1p[col][1] * dft2p[col][0];
|
||||
const T mag = std::sqrt(re * re + im * im);
|
||||
cpsp[col][0] = re / mag;
|
||||
cpsp[col][1] = im / mag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat calculateCrossPowerSpectrum(const cv::Mat& dft1, const cv::Mat& dft2)
|
||||
{
|
||||
cv::Mat cps(dft1.rows, dft1.cols, dft1.type());
|
||||
if (dft1.type() == CV_32FC2)
|
||||
calculateCrossPowerSpectrum<float>(dft1, dft2, cps);
|
||||
else if (dft1.type() == CV_64FC2)
|
||||
calculateCrossPowerSpectrum<double>(dft1, dft2, cps);
|
||||
else
|
||||
CV_Error(cv::Error::StsNotImplemented, "Only CV_32FC2 and CV_64FC2 types are supported");
|
||||
return cps;
|
||||
}
|
||||
|
||||
void fftshift(cv::Mat& out)
|
||||
{
|
||||
int cx = out.cols / 2;
|
||||
int cy = out.rows / 2;
|
||||
cv::Mat q0(out, cv::Rect(0, 0, cx, cy));
|
||||
cv::Mat q1(out, cv::Rect(cx, 0, cx, cy));
|
||||
cv::Mat q2(out, cv::Rect(0, cy, cx, cy));
|
||||
cv::Mat q3(out, cv::Rect(cx, cy, cx, cy));
|
||||
|
||||
cv::Mat tmp;
|
||||
q0.copyTo(tmp);
|
||||
q3.copyTo(q0);
|
||||
tmp.copyTo(q3);
|
||||
q1.copyTo(tmp);
|
||||
q2.copyTo(q1);
|
||||
tmp.copyTo(q2);
|
||||
}
|
||||
|
||||
bool isOutOfBounds(const cv::Point2i& peak, const cv::Mat& mat, int size)
|
||||
{
|
||||
return peak.x - size / 2 < 0 || peak.y - size / 2 < 0 || peak.x + size / 2 >= mat.cols ||
|
||||
peak.y + size / 2 >= mat.rows;
|
||||
}
|
||||
|
||||
bool reduceL2size(int& L2size)
|
||||
{
|
||||
L2size -= 2;
|
||||
return L2size >= 3;
|
||||
}
|
||||
|
||||
int getL1size(int L2Usize, double L1ratio)
|
||||
{
|
||||
int L1size = static_cast<int>(std::floor(L1ratio * L2Usize));
|
||||
return (L1size % 2) ? L1size : L1size + 1;
|
||||
}
|
||||
|
||||
cv::Point2d getPeakSubpixel(const cv::Mat& mat)
|
||||
{
|
||||
const auto m = moments(mat);
|
||||
return cv::Point2d(m.m10 / m.m00, m.m01 / m.m00);
|
||||
}
|
||||
|
||||
bool accuracyReached(const cv::Point2d& L1peak, const cv::Point2d& L1mid)
|
||||
{
|
||||
return std::abs(L1peak.x - L1mid.x) < 0.5 && std::abs(L1peak.y - L1mid.y) < 0.5;
|
||||
}
|
||||
|
||||
cv::Point2d getSubpixelShift(const cv::Mat& L3,
|
||||
const cv::Point2d& L3peak,
|
||||
const cv::Point2d& L3mid,
|
||||
int L2size)
|
||||
{
|
||||
while (isOutOfBounds(L3peak, L3, L2size))
|
||||
if (!reduceL2size(L2size))
|
||||
return L3peak - L3mid;
|
||||
|
||||
cv::Mat L2 = L3(cv::Rect(static_cast<int>(L3peak.x - L2size / 2),
|
||||
static_cast<int>(L3peak.y - L2size / 2),
|
||||
L2size,
|
||||
L2size));
|
||||
cv::Point2d L2peak = getPeakSubpixel(L2);
|
||||
cv::Point2d L2mid(L2.cols / 2, L2.rows / 2);
|
||||
return L3peak - L3mid + L2peak - L2mid;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
cv::Point2d
|
||||
cv::phaseCorrelateIterative(InputArray _src1, InputArray _src2, int L2size, int maxIters)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Mat src1 = _src1.getMat();
|
||||
Mat src2 = _src2.getMat();
|
||||
|
||||
CV_Assert(src1.type() == src2.type());
|
||||
CV_Assert(src1.size() == src2.size());
|
||||
CV_Assert(src1.type() == CV_32FC1 || src1.type() == CV_64FC1);
|
||||
|
||||
// apply DFT window to input images
|
||||
Mat window;
|
||||
createHanningWindow(window, src1.size(), _src1.type());
|
||||
Mat image1, image2;
|
||||
multiply(_src1, window, image1);
|
||||
multiply(_src2, window, image2);
|
||||
|
||||
// compute the DFTs of input images
|
||||
dft(image1, image1, DFT_COMPLEX_OUTPUT);
|
||||
dft(image2, image2, DFT_COMPLEX_OUTPUT);
|
||||
|
||||
// compute the phase correlation landscape L3
|
||||
Mat L3 = calculateCrossPowerSpectrum(image1, image2);
|
||||
dft(L3, L3, DFT_INVERSE | DFT_SCALE | DFT_REAL_OUTPUT);
|
||||
fftshift(L3);
|
||||
Point2d L3mid(L3.cols / 2, L3.rows / 2);
|
||||
|
||||
// calculate the maximum correlation location
|
||||
Point2i L3peak;
|
||||
minMaxLoc(L3, nullptr, nullptr, nullptr, &L3peak);
|
||||
|
||||
// reduce the L2size as long as L2 is out of bounds of L3
|
||||
while (isOutOfBounds(L3peak, L3, L2size))
|
||||
if (!reduceL2size(L2size))
|
||||
return Point2d(L3peak) - L3mid;
|
||||
|
||||
// extract the L2 maximum correlation neighborhood from L3
|
||||
Mat L2 = L3(Rect(L3peak.x - L2size / 2, L3peak.y - L2size / 2, L2size, L2size));
|
||||
|
||||
// upsample L2 maximum correlation neighborhood to get L2U
|
||||
Mat L2U;
|
||||
const int L2Usize = 223; // empirically determined optimal constant
|
||||
resize(L2, L2U, {L2Usize, L2Usize}, 0, 0, INTER_LINEAR);
|
||||
const Point2d L2Umid(L2U.cols / 2, L2U.rows / 2);
|
||||
|
||||
// run the iterative refinement algorithm using the specified L1 ratio
|
||||
// gradually decrease L1 ratio if convergence is not achieved
|
||||
const double L1ratioBase = 0.45; // empirically determined optimal constant
|
||||
const double L1ratioStep = 0.025;
|
||||
for (double L1ratio = L1ratioBase; getL1size(L2U.cols, L1ratio) > 0; L1ratio -= L1ratioStep)
|
||||
{
|
||||
Point2d L2Upeak = L2Umid; // reset the accumulated L2U peak position
|
||||
const int L1size = getL1size(L2U.cols, L1ratio); // calculate the current L1 size
|
||||
const Point2d L1mid(L1size / 2, L1size / 2); // update the L1 mid position
|
||||
|
||||
// perform the iterative refinement algorithm
|
||||
for (int iter = 0; iter < maxIters; ++iter)
|
||||
{
|
||||
// verify that the L1 region is within the L2U region
|
||||
if (isOutOfBounds(L2Upeak, L2U, L1size))
|
||||
break;
|
||||
|
||||
// extract the L1 region from L2U
|
||||
const Mat L1 = L2U(Rect(static_cast<int>(L2Upeak.x - L1size / 2),
|
||||
static_cast<int>(L2Upeak.y - L1size / 2),
|
||||
L1size,
|
||||
L1size));
|
||||
|
||||
// calculate the centroid location
|
||||
const Point2d L1peak = getPeakSubpixel(L1);
|
||||
|
||||
// add the contribution of the current iteration to the accumulated L2U peak location
|
||||
L2Upeak += Point2d(std::round(L1peak.x - L1mid.x), std::round(L1peak.y - L1mid.y));
|
||||
|
||||
// check for convergence
|
||||
if (accuracyReached(L1peak, L1mid))
|
||||
// return the refined subpixel image shift
|
||||
return Point2d(L3peak) - L3mid +
|
||||
(L2Upeak - L2Umid + L1peak - L1mid) /
|
||||
(static_cast<double>(L2Usize) / L2size);
|
||||
}
|
||||
}
|
||||
|
||||
// iterative refinement failed to converge, return non-iterative subpixel shift
|
||||
return getSubpixelShift(L3, Point2d(L3peak), L3mid, L2size);
|
||||
}
|
||||
@@ -365,7 +365,7 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
|
||||
Mat hull;
|
||||
Point2f out[3];
|
||||
RotatedRect box;
|
||||
box.angle = -(float)CV_PI / 2; // default angle for box without rotation and single point
|
||||
double angle = -CV_PI / 2; // default angle for box without rotation and single point
|
||||
|
||||
static const bool clockwise = false;
|
||||
convexHull(_points, hull, clockwise, true);
|
||||
@@ -390,7 +390,7 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
|
||||
if (out[1].x == 0.f && out[1].y > 0.f)
|
||||
std::swap(box.size.width, box.size.height);
|
||||
else
|
||||
box.angle += (float)atan2( (double)out[1].y, (double)out[1].x );
|
||||
angle = -atan2( (double)out[1].x, (double)out[1].y );
|
||||
}
|
||||
else if( n == 2 )
|
||||
{
|
||||
@@ -406,12 +406,12 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
|
||||
}
|
||||
else if (dy < 0)
|
||||
{
|
||||
box.angle = (float)atan2( dy, dx );
|
||||
angle = atan2( dy, dx );
|
||||
std::swap(box.size.width, box.size.height);
|
||||
}
|
||||
else if (dy > 0)
|
||||
{
|
||||
box.angle += (float)atan2( dy, dx );
|
||||
angle = -atan2( dx, dy );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -420,7 +420,7 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
|
||||
box.center = hpoints[0];
|
||||
}
|
||||
|
||||
box.angle = (float)(box.angle*180/CV_PI);
|
||||
box.angle = (float)(angle*180/CV_PI);
|
||||
CV_DbgCheckGE(box.angle, -90.0f, "");
|
||||
CV_DbgCheckLT(box.angle, 0.0f, "");
|
||||
return box;
|
||||
|
||||
@@ -41,6 +41,7 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -1199,12 +1200,17 @@ void stackBlur(InputArray _src, OutputArray _dst, Size ksize)
|
||||
CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 &&
|
||||
ksize.height > 0 && ksize.height % 2 == 1 );
|
||||
|
||||
int radiusH = ksize.height / 2;
|
||||
int radiusW = ksize.width / 2;
|
||||
|
||||
int stype = _src.type(), sdepth = _src.depth();
|
||||
Mat src = _src.getMat();
|
||||
|
||||
if (ksize.width > src.cols)
|
||||
ksize.width = (src.cols % 2 == 0) ? std::max(1, src.cols - 1) : src.cols;
|
||||
if (ksize.height > src.rows)
|
||||
ksize.height = (src.rows % 2 == 0) ? std::max(1, src.rows - 1) : src.rows;
|
||||
|
||||
int radiusH = ksize.height / 2;
|
||||
int radiusW = ksize.width / 2;
|
||||
|
||||
if (ksize.width == 1)
|
||||
{
|
||||
_src.copyTo(_dst);
|
||||
|
||||
@@ -265,7 +265,7 @@ int Subdiv2D::newPoint(Point2f pt, bool isvirtual, int firstEdge)
|
||||
{
|
||||
if( freePoint == 0 )
|
||||
{
|
||||
vtx.push_back(Vertex());
|
||||
vtx.emplace_back();
|
||||
freePoint = (int)(vtx.size()-1);
|
||||
}
|
||||
int vidx = freePoint;
|
||||
@@ -520,8 +520,8 @@ void Subdiv2D::initDelaunay( Rect rect )
|
||||
Point2f ppB( rx, ry + big_coord );
|
||||
Point2f ppC( rx - big_coord, ry - big_coord );
|
||||
|
||||
vtx.push_back(Vertex());
|
||||
qedges.push_back(QuadEdge());
|
||||
vtx.emplace_back();
|
||||
qedges.emplace_back();
|
||||
|
||||
freeQEdge = 0;
|
||||
freePoint = 0;
|
||||
@@ -566,8 +566,8 @@ void Subdiv2D::initDelaunay( Rect2f rect )
|
||||
Point2f ppB( rx, ry + big_coord );
|
||||
Point2f ppC( rx - big_coord, ry - big_coord );
|
||||
|
||||
vtx.push_back(Vertex());
|
||||
qedges.push_back(QuadEdge());
|
||||
vtx.emplace_back();
|
||||
qedges.emplace_back();
|
||||
|
||||
freeQEdge = 0;
|
||||
freePoint = 0;
|
||||
@@ -784,7 +784,7 @@ void Subdiv2D::getEdgeList(std::vector<Vec4f>& edgeList) const
|
||||
{
|
||||
Point2f org = vtx[qedges[i].pt[0]].pt;
|
||||
Point2f dst = vtx[qedges[i].pt[2]].pt;
|
||||
edgeList.push_back(Vec4f(org.x, org.y, dst.x, dst.y));
|
||||
edgeList.emplace_back(org.x, org.y, dst.x, dst.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -836,7 +836,7 @@ void Subdiv2D::getTriangleList(std::vector<Vec6f>& triangleList) const
|
||||
edgemask[edge_a] = true;
|
||||
edgemask[edge_b] = true;
|
||||
edgemask[edge_c] = true;
|
||||
triangleList.push_back(Vec6f(a.x, a.y, b.x, b.y, c.x, c.y));
|
||||
triangleList.emplace_back(a.x, a.y, b.x, b.y, c.x, c.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,19 @@ TEST(Imgproc_ApproxPoly, bad_epsilon)
|
||||
ASSERT_ANY_THROW(approxPolyDP(inputPoints, outputPoints, eps, false));
|
||||
}
|
||||
|
||||
TEST(Imgproc_ApproxPoly, distace_between_point_and_segment)
|
||||
{
|
||||
vector<Point2f> inputPoints = {
|
||||
{ {0.f, 0.f}, {4.f, 2.f}, {11.f, 1.f}, {8.f, 0.f} }
|
||||
};
|
||||
std::vector<Point2f> result;
|
||||
approxPolyDP(inputPoints, result, 1.9, false);
|
||||
vector<Point2f> expectedResult = {
|
||||
{ {0.f, 0.f}, {11.f, 1.f}, {8.f, 0.f} }
|
||||
};
|
||||
ASSERT_EQ(result, expectedResult);
|
||||
}
|
||||
|
||||
struct ApproxPolyN: public testing::Test
|
||||
{
|
||||
void SetUp()
|
||||
|
||||
@@ -291,4 +291,33 @@ namespace opencv_test { namespace {
|
||||
test.safe_run();
|
||||
}
|
||||
|
||||
// Regression test for issue #28254
|
||||
// Out-of-bounds read in AVX2 bilateralFilter 32f path with BORDER_CONSTANT
|
||||
TEST(Imgproc_BilateralFilter, regression_28254_oob_read)
|
||||
{
|
||||
// Create a 64x64 CV_32FC1 image with values in range [100, 200]
|
||||
// Image must be large enough (width >= 32) to trigger SIMD/AVX2 code path.
|
||||
// Values are set so BORDER_CONSTANT padding (default 0) is outside the range,
|
||||
// which triggers the out-of-bounds condition in the LUT access.
|
||||
cv::Mat src(64, 64, CV_32FC1);
|
||||
cv::randu(src, 100.0f, 200.0f);
|
||||
cv::Mat dst;
|
||||
|
||||
// Parameters that trigger the bug
|
||||
int d = -1;
|
||||
double sigmaColor = 2.7;
|
||||
double sigmaSpace = 44.5;
|
||||
int borderType = cv::BORDER_CONSTANT;
|
||||
|
||||
// This should not crash or trigger AddressSanitizer
|
||||
EXPECT_NO_THROW(
|
||||
cv::bilateralFilter(src, dst, d, sigmaColor, sigmaSpace, borderType)
|
||||
);
|
||||
|
||||
// Verify output is valid
|
||||
EXPECT_FALSE(dst.empty());
|
||||
EXPECT_EQ(dst.size(), src.size());
|
||||
EXPECT_EQ(dst.type(), src.type());
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -233,5 +233,20 @@ TEST(Imgproc_DrawContours, MatListOfMatIntScalarInt)
|
||||
EXPECT_EQ(nz, 0);
|
||||
}
|
||||
|
||||
TEST(Imgproc_Moments, degenerateContours)
|
||||
{
|
||||
std::vector<cv::Point> c1;
|
||||
c1.push_back(cv::Point(10,10));
|
||||
cv::Moments m1 = cv::moments(c1, false);
|
||||
EXPECT_EQ(m1.m00, 0);
|
||||
|
||||
std::vector<cv::Point> c2;
|
||||
c2.push_back(cv::Point(0,0));
|
||||
c2.push_back(cv::Point(5,5));
|
||||
c2.push_back(cv::Point(10,10));
|
||||
cv::Moments m2 = cv::moments(c2, false);
|
||||
EXPECT_EQ(m2.m00, 0);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
/* End of file. */
|
||||
|
||||
@@ -304,9 +304,11 @@ TEST(Imgproc_ConvexityDefects, ordering_4539)
|
||||
vector<int> hull_ind;
|
||||
vector<Vec4i> defects;
|
||||
|
||||
#if 0 // deprecated behavior
|
||||
// first, check the original contour as-is, without intermediate fillPoly/drawContours.
|
||||
convexHull(contour_, hull_ind, false, false);
|
||||
EXPECT_THROW( convexityDefects(contour_, hull_ind, defects), cv::Exception );
|
||||
#endif
|
||||
|
||||
int scale = 20;
|
||||
contour_ *= (double)scale;
|
||||
@@ -319,10 +321,12 @@ TEST(Imgproc_ConvexityDefects, ordering_4539)
|
||||
findContours(canvas_gray, contours, noArray(), RETR_LIST, CHAIN_APPROX_SIMPLE);
|
||||
convexHull(contours[0], hull_ind, false, false);
|
||||
|
||||
#if 0 // deprecated behavior
|
||||
// the original contour contains self-intersections,
|
||||
// therefore convexHull does not return a monotonous sequence of points
|
||||
// and therefore convexityDefects throws an exception
|
||||
EXPECT_THROW( convexityDefects(contours[0], hull_ind, defects), cv::Exception );
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// one way to eliminate the contour self-intersection in this particular case is to apply dilate(),
|
||||
@@ -1049,7 +1053,7 @@ TEST_P(minEnclosingTriangle_Modes, accuracy)
|
||||
const Mat midPoint = (cur + next) / 2;
|
||||
EXPECT_TRUE(isPointOnHull(hull, midPoint));
|
||||
|
||||
// at least one of hull edges must be on tirangle edge
|
||||
// at least one of hull edges must be on triangle edge
|
||||
hasEdgeOnHull = hasEdgeOnHull || isEdgeOnHull(hull, cur, next);
|
||||
}
|
||||
EXPECT_TRUE(hasEdgeOnHull);
|
||||
@@ -1279,10 +1283,60 @@ INSTANTIATE_TEST_CASE_P(Imgproc, minAreaRect_of_line,
|
||||
testing::Values(
|
||||
std::make_tuple(Point2f(10, 15), Point2f(10, 25), Point2f(10, 20), Size2f(10, 0), -90.f),
|
||||
std::make_tuple(Point2f(450, 500), Point2f(508, 500), Point2f(479, 500), Size2f(0, 58), -90.f),
|
||||
std::make_tuple(Point2f(10, 20), Point2f(13, 16), Point2f(11.5, 18), Size2f(5, 0), -53.1301002f),
|
||||
std::make_tuple(Point2f(10, 20), Point2f(13, 16), Point2f(11.5, 18), Size2f(5, 0), -53.1301041f),
|
||||
std::make_tuple(Point2f(9, 19), Point2f(4, 7), Point2f(6.5, 13), Size2f(0, 13), -22.6198654f)
|
||||
));
|
||||
|
||||
typedef testing::TestWithParam<tuple<tuple<std::vector<Point>, Mat>, bool> > convexHull_monotonous;
|
||||
TEST_P(convexHull_monotonous, self_intersecting_contour)
|
||||
{
|
||||
std::vector<Point> contour = get<0>(get<0>(GetParam()));
|
||||
Mat ref = get<1>(get<0>(GetParam())).clone();
|
||||
bool clockwise = get<1>(GetParam());
|
||||
if (!clockwise)
|
||||
{
|
||||
std::reverse(ref.begin<int>(), ref.end<int>());
|
||||
}
|
||||
|
||||
Mat indices;
|
||||
convexHull(contour, indices, clockwise, false);
|
||||
|
||||
Point minLoc;
|
||||
minMaxLoc(indices, nullptr, nullptr, &minLoc);
|
||||
std::rotate(indices.begin<int>(), indices.begin<int>() + minLoc.y, indices.end<int>());
|
||||
|
||||
minMaxLoc(ref, nullptr, nullptr, &minLoc);
|
||||
std::rotate(ref.begin<int>(), ref.begin<int>() + minLoc.y, ref.end<int>());
|
||||
|
||||
ASSERT_EQ( cvtest::norm(indices, ref, NORM_INF), 0) << indices;
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(Imgproc, convexHull_monotonous,
|
||||
testing::Combine(
|
||||
testing::Values(
|
||||
std::make_tuple(
|
||||
std::vector<Point>{
|
||||
Point(3, 2), Point(3, 4), Point(2, 5), Point(1, 5),
|
||||
Point(2, 5), Point(3, 4), Point(6, 4), Point(6, 2)
|
||||
},
|
||||
(Mat_<int>(5, 1) << 0, 3, 4, 6, 7)
|
||||
),
|
||||
std::make_tuple(
|
||||
std::vector<Point>{
|
||||
Point(3, -2), Point(3, -4), Point(2, -5), Point(1, -5),
|
||||
Point(2, -5), Point(3, -4), Point(6, -4), Point(6, -2)
|
||||
},
|
||||
(Mat_<int>(5, 1) << 3, 0, 7, 6, 4)
|
||||
),
|
||||
std::make_tuple(
|
||||
std::vector<Point>{
|
||||
Point(1, 1), Point(1, 0), Point(0, 0), Point(1, 0), Point(0, 1)
|
||||
},
|
||||
(Mat_<int>(4, 1) << 0, 1, 2, 4)
|
||||
)
|
||||
),
|
||||
testing::Bool()
|
||||
));
|
||||
|
||||
}} // namespace
|
||||
|
||||
/* End of file. */
|
||||
|
||||
@@ -1281,4 +1281,28 @@ TEST(Drawing, contours_filled)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for LINE_4 vs LINE_8 connectivity behavior
|
||||
// Regression test for issue #26413
|
||||
TEST(Drawing, line_connectivity_regression_26413)
|
||||
{
|
||||
Mat img4(10, 10, CV_8UC1, Scalar(0));
|
||||
Mat img8(10, 10, CV_8UC1, Scalar(0));
|
||||
|
||||
// Draw a diagonal line from (0,0) to (9,9)
|
||||
// LINE_4 (4-connected) should produce staircase pattern (no diagonals)
|
||||
// LINE_8 (8-connected) should produce diagonal steps
|
||||
line(img4, Point(0, 0), Point(9, 9), Scalar(255), 1, LINE_4);
|
||||
line(img8, Point(0, 0), Point(9, 9), Scalar(255), 1, LINE_8);
|
||||
|
||||
int count4 = countNonZero(img4);
|
||||
int count8 = countNonZero(img8);
|
||||
|
||||
// LINE_8 for a 10-pixel diagonal should have exactly 10 pixels
|
||||
EXPECT_EQ(10, count8) << "LINE_8 diagonal from (0,0) to (9,9) should have 10 pixels";
|
||||
|
||||
// LINE_4 for a 10-pixel diagonal should have approximately 19 pixels
|
||||
// (needs both horizontal and vertical steps)
|
||||
EXPECT_GT(count4, 15) << "LINE_4 diagonal should have significantly more pixels due to staircase";
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -509,7 +509,8 @@ int CV_GoodFeatureToTTest::validate_test_results( int test_case_idx )
|
||||
EXPECT_LE(e, eps); // never true
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
|
||||
|
||||
for(int i = 0; i < (int)std::min((unsigned int)(cornersQuality.size()), (unsigned int)(cornersQuality.size())); i++) {
|
||||
int min_size = (int)std::min(cornersQuality.size(), RefcornersQuality.size());
|
||||
for(int i = 0; i < min_size; i++) {
|
||||
if (std::abs(cornersQuality[i] - RefcornersQuality[i]) > eps * std::max(cornersQuality[i], RefcornersQuality[i]))
|
||||
printf("i = %i Quality %2.6f Quality ref %2.6f\n", i, cornersQuality[i], RefcornersQuality[i]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
Mat CropMid(InputArray src, int w, int h)
|
||||
{
|
||||
Mat mat = src.getMat();
|
||||
return mat(Rect(mat.cols / 2 - w / 2, mat.rows / 2 - h / 2, w, h));
|
||||
}
|
||||
|
||||
Mat GenerateTestImage(Size size)
|
||||
{
|
||||
Mat image = Mat::zeros(size.height * 2, size.width * 2, CV_32F);
|
||||
rectangle(image,
|
||||
Point(static_cast<int>(size.width * 0.1), static_cast<int>(size.height * 0.1)),
|
||||
Point(static_cast<int>(size.width * 0.9), static_cast<int>(size.height * 0.9)),
|
||||
Scalar(1),
|
||||
-1);
|
||||
return image;
|
||||
}
|
||||
|
||||
void TestPhaseCorrelationIterative(const Size& size, const double maxShift)
|
||||
{
|
||||
const auto iters = std::max(201., maxShift * 10 + 1);
|
||||
const Point2d shiftOffset(-maxShift * 0.5, -maxShift * 0.5);
|
||||
Mat image1 = GenerateTestImage(size);
|
||||
Mat crop1 = CropMid(image1, size.width, size.height);
|
||||
Mat image2 = image1.clone();
|
||||
|
||||
std::vector<double> pcErrors;
|
||||
std::vector<double> ipcErrors;
|
||||
|
||||
for (int i = 0; i < iters; ++i)
|
||||
{
|
||||
const auto shift =
|
||||
Point2d(maxShift * i / (iters - 1), maxShift * i / (iters - 1)) + shiftOffset;
|
||||
const Mat Tmat = (Mat_<double>(2, 3) << 1., 0., shift.x, 0., 1., shift.y);
|
||||
warpAffine(image1, image2, Tmat, image2.size());
|
||||
Mat crop2 = CropMid(image2, size.width, size.height);
|
||||
const auto ipcshift = phaseCorrelateIterative(crop1, crop2);
|
||||
const auto pcshift = phaseCorrelate(crop1, crop2);
|
||||
|
||||
pcErrors.push_back(
|
||||
0.5 * std::abs(pcshift.x - shift.y) + 0.5 * std::abs(pcshift.y - shift.x));
|
||||
ipcErrors.push_back(
|
||||
0.5 * std::abs(ipcshift.x - shift.y) + 0.5 * std::abs(ipcshift.y - shift.x));
|
||||
|
||||
// error should be low
|
||||
EXPECT_NEAR(ipcshift.x - shift.x, 0.0, 0.1);
|
||||
EXPECT_NEAR(ipcshift.y - shift.y, 0.0, 0.1);
|
||||
}
|
||||
|
||||
cv::Scalar pcMean, pcStddev, ipcMean, ipcStddev;
|
||||
meanStdDev(ipcErrors, ipcMean, ipcStddev);
|
||||
meanStdDev(pcErrors, pcMean, pcStddev);
|
||||
|
||||
// average error should be low
|
||||
ASSERT_LT(ipcMean[0], 0.03);
|
||||
// average error should be less than non-iterative average error
|
||||
ASSERT_LT(ipcMean[0], pcMean[0]);
|
||||
// error stddev should be less than non-iterative error stddev
|
||||
ASSERT_LT(ipcStddev[0], pcStddev[0]);
|
||||
}
|
||||
|
||||
|
||||
TEST(Imgproc_PhaseCorrelationIterative, 256x128_accuracy)
|
||||
{
|
||||
TestPhaseCorrelationIterative(Size(256, 128), 1);
|
||||
}
|
||||
|
||||
TEST(Imgproc_PhaseCorrelationIterative, 64x64_accuracy_shift_1)
|
||||
{
|
||||
TestPhaseCorrelationIterative(Size(64, 64), 1);
|
||||
}
|
||||
|
||||
TEST(Imgproc_PhaseCorrelationIterative, 64x64_accuracy_shift_16)
|
||||
{
|
||||
TestPhaseCorrelationIterative(Size(64, 64), 16);
|
||||
}
|
||||
|
||||
TEST(Imgproc_PhaseCorrelationIterative, 0x0_image)
|
||||
{
|
||||
ASSERT_ANY_THROW(TestPhaseCorrelationIterative(Size(0, 0), 1));
|
||||
}
|
||||
|
||||
TEST(Imgproc_PhaseCorrelationIterative, 1x1_image)
|
||||
{
|
||||
ASSERT_ANY_THROW(TestPhaseCorrelationIterative(Size(1, 1), 1));
|
||||
}
|
||||
|
||||
TEST(Imgproc_PhaseCorrelationIterative, accuracy_real_img)
|
||||
{
|
||||
Mat img = imread(cvtest::TS::ptr()->get_data_path() + "shared/airplane.png", IMREAD_GRAYSCALE);
|
||||
if (img.empty())
|
||||
return;
|
||||
img.convertTo(img, CV_64FC1);
|
||||
|
||||
const int xLen = 256;
|
||||
const int yLen = 256;
|
||||
const int xShift = 40;
|
||||
const int yShift = 14;
|
||||
|
||||
Mat roi1 = img(Rect(xShift, yShift, xLen, yLen));
|
||||
Mat roi2 = img(Rect(0, 0, xLen, yLen));
|
||||
|
||||
const Point2d ipcShift = phaseCorrelateIterative(roi1, roi2);
|
||||
|
||||
ASSERT_NEAR(ipcShift.x, (double)xShift, 1.);
|
||||
ASSERT_NEAR(ipcShift.y, (double)yShift, 1.);
|
||||
}
|
||||
|
||||
}} // namespace opencv_test
|
||||
@@ -311,5 +311,18 @@ TEST_P(StackBlur_GaussianBlur, compare)
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Imgproc, StackBlur_GaussianBlur, testing::Values(CV_8U, CV_16S, CV_16U, CV_32F));
|
||||
|
||||
TEST(Imgproc_StackBlur, regression_28233)
|
||||
{
|
||||
Mat src1(1, 1, CV_8UC1, Scalar(123));
|
||||
Mat dst1;
|
||||
EXPECT_NO_THROW(stackBlur(src1, dst1, Size(9, 1)));
|
||||
EXPECT_EQ(dst1.at<uchar>(0, 0), 123);
|
||||
|
||||
Mat src2(3, 3, CV_8UC1, Scalar(50));
|
||||
Mat dst2;
|
||||
EXPECT_NO_THROW(stackBlur(src2, dst2, Size(11, 11)));
|
||||
EXPECT_EQ(dst2.at<uchar>(1, 1), 50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,24 @@ ocv_bindings_generator_populate_preprocessor_definitions(
|
||||
opencv_preprocessor_defs
|
||||
)
|
||||
|
||||
if(OPENCV_JAVA_CLEANING_API)
|
||||
if(OPENCV_JAVA_CLEANING_API STREQUAL "finalize")
|
||||
set(opencv_supported_cleaners "false")
|
||||
elseif(OPENCV_JAVA_CLEANING_API STREQUAL "cleaner")
|
||||
set(opencv_supported_cleaners "true")
|
||||
else()
|
||||
message(FATAL_ERROR "OPENCV_JAVA_CLEANING_API should be one of \"finalize\" or \"cleaner\"")
|
||||
endif()
|
||||
else()
|
||||
if(ANDROID OR (Java_VERSION VERSION_LESS 9))
|
||||
message(STATUS "Set Cleaners to False")
|
||||
set(opencv_supported_cleaners "false")
|
||||
else()
|
||||
message(STATUS "Set Cleaners to True")
|
||||
set(opencv_supported_cleaners "true")
|
||||
endif()
|
||||
endif(OPENCV_JAVA_CLEANING_API)
|
||||
|
||||
set(CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/gen_java.json")
|
||||
set(__config_str
|
||||
"{
|
||||
@@ -74,7 +92,8 @@ ${opencv_preprocessor_defs}
|
||||
},
|
||||
\"files_remap\": [
|
||||
${__remap_config}
|
||||
]
|
||||
],
|
||||
\"support_cleaners\": ${opencv_supported_cleaners}
|
||||
}
|
||||
")
|
||||
if(EXISTS "${CONFIG_FILE}")
|
||||
|
||||
@@ -23,6 +23,7 @@ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
# list of modules + files remap
|
||||
config = None
|
||||
ROOT_DIR = None
|
||||
USE_CLEANERS = True
|
||||
FILES_REMAP = {}
|
||||
def checkFileRemap(path):
|
||||
path = os.path.realpath(path)
|
||||
@@ -377,6 +378,7 @@ class ClassInfo(GeneralInfo):
|
||||
jmodule = make_jmodule(m),
|
||||
name = self.name,
|
||||
jname = self.jname,
|
||||
jcleaner = "long nativeObjCopy = nativeObj;\n org.opencv.core.Mat.cleaner.register(this, () -> delete(nativeObjCopy));" if USE_CLEANERS else "",
|
||||
imports = "\n".join(self.getAllImports(M)),
|
||||
docs = self.docstring,
|
||||
annotation = "\n" + "\n".join(self.annotation) if self.annotation else "",
|
||||
@@ -961,6 +963,7 @@ class JavaWrapperGenerator(object):
|
||||
tail = ")"
|
||||
else:
|
||||
ret_val = "nativeObj = "
|
||||
tail = ";\n long nativeObjCopy = nativeObj;\n org.opencv.core.Mat.cleaner.register(this, () -> delete(nativeObjCopy))" if USE_CLEANERS else ""
|
||||
ret = ""
|
||||
elif self.isWrapped(ret_type): # wrapped class
|
||||
constructor = self.getClass(ret_type).jname + "("
|
||||
@@ -1228,8 +1231,9 @@ JNIEXPORT $rtype JNICALL Java_org_opencv_${jmodule}_${clazz}_$fname
|
||||
ci.cpp_code.write("\n".join(fn["cpp_code"]))
|
||||
|
||||
if ci.name != self.Module or ci.base:
|
||||
# finalize()
|
||||
ci.j_code.write(
|
||||
# finalize() for old Java
|
||||
if not USE_CLEANERS:
|
||||
ci.j_code.write(
|
||||
"""
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
@@ -1239,7 +1243,7 @@ JNIEXPORT $rtype JNICALL Java_org_opencv_${jmodule}_${clazz}_$fname
|
||||
|
||||
ci.jn_code.write(
|
||||
"""
|
||||
// native support for java finalize()
|
||||
// native support for java finalize() or cleaner
|
||||
private static native void delete(long nativeObj);
|
||||
""" )
|
||||
|
||||
@@ -1247,7 +1251,7 @@ JNIEXPORT $rtype JNICALL Java_org_opencv_${jmodule}_${clazz}_$fname
|
||||
ci.cpp_code.write(
|
||||
"""
|
||||
//
|
||||
// native support for java finalize()
|
||||
// native support for java finalize() or cleaner
|
||||
// static void %(cls)s::delete( __int64 self )
|
||||
//
|
||||
JNIEXPORT void JNICALL Java_org_opencv_%(module)s_%(j_cls)s_delete(JNIEnv*, jclass, jlong);
|
||||
@@ -1468,6 +1472,12 @@ if __name__ == "__main__":
|
||||
FILES_REMAP = { os.path.realpath(os.path.join(ROOT_DIR, f['src'])): f['target'] for f in config['files_remap'] }
|
||||
logging.info("\nRemapped configured files (%d):\n%s", len(FILES_REMAP), pformat(FILES_REMAP))
|
||||
|
||||
USE_CLEANERS = config['support_cleaners']
|
||||
if (USE_CLEANERS):
|
||||
logging.info("\nUse Java 9+ cleaners\n")
|
||||
else:
|
||||
logging.info("\nUse old style Java finalize()\n")
|
||||
|
||||
dstdir = "./gen"
|
||||
jni_path = os.path.join(dstdir, 'cpp'); mkdir_p(jni_path)
|
||||
java_base_path = os.path.join(dstdir, 'java'); mkdir_p(java_base_path)
|
||||
@@ -1557,6 +1567,17 @@ if __name__ == "__main__":
|
||||
preprocessor_definitions)
|
||||
else:
|
||||
logging.info("No generated code for module: %s", module)
|
||||
|
||||
# Copy Cleaner / finalize() related files
|
||||
if USE_CLEANERS:
|
||||
cleaner_src = os.path.join(SCRIPT_DIR, "src", "java9", "CleanableMat.java")
|
||||
else:
|
||||
cleaner_src = os.path.join(SCRIPT_DIR, "src", "java_classic", "CleanableMat.java")
|
||||
|
||||
cleaner_dst = os.path.join(java_base_path, "org", "opencv", "core", "CleanableMat.java")
|
||||
print("cleaner_dst: ", cleaner_dst)
|
||||
copyfile(cleaner_src, cleaner_dst)
|
||||
|
||||
generator.finalize(jni_path)
|
||||
|
||||
print('Generated files: %d (updated %d)' % (total_files, updated_files))
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
#define LOG_TAG "org.opencv.core.CleanableMat"
|
||||
#include "common.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// native support for java finalize() or cleaners
|
||||
// static void CleanableMat::n_delete( __int64 self )
|
||||
//
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_opencv_core_CleanableMat_n_1delete
|
||||
(JNIEnv*, jclass, jlong self);
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_opencv_core_CleanableMat_n_1delete
|
||||
(JNIEnv*, jclass, jlong self)
|
||||
{
|
||||
// LOGD("CleanableMat.n_delete() called\n");
|
||||
delete (Mat*) self;
|
||||
}
|
||||
}
|
||||
@@ -2114,22 +2114,6 @@ JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1zeros__I_3II
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// native support for java finalize()
|
||||
// static void Mat::n_delete( __int64 self )
|
||||
//
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1delete
|
||||
(JNIEnv*, jclass, jlong self);
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1delete
|
||||
(JNIEnv*, jclass, jlong self)
|
||||
{
|
||||
delete (Mat*) self;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.opencv.core;
|
||||
|
||||
import java.lang.ref.Cleaner;
|
||||
|
||||
public abstract class CleanableMat {
|
||||
// A native memory cleaner for the OpenCV library
|
||||
public static Cleaner cleaner = Cleaner.create();
|
||||
|
||||
protected CleanableMat(long obj) {
|
||||
if (obj == 0)
|
||||
throw new UnsupportedOperationException("Native object address is NULL");
|
||||
|
||||
nativeObj = obj;
|
||||
|
||||
// The n_delete action must not refer to the object being registered. So, do not use nativeObj directly.
|
||||
long nativeObjCopy = nativeObj;
|
||||
cleaner.register(this, () -> n_delete(nativeObjCopy));
|
||||
}
|
||||
|
||||
private static native void n_delete(long nativeObj);
|
||||
|
||||
public final long nativeObj;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.opencv.core;
|
||||
|
||||
public abstract class CleanableMat {
|
||||
|
||||
protected CleanableMat(long obj) {
|
||||
if (obj == 0)
|
||||
throw new UnsupportedOperationException("Native object address is NULL");
|
||||
|
||||
nativeObj = obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
n_delete(nativeObj);
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
private static native void n_delete(long nativeObj);
|
||||
|
||||
public final long nativeObj;
|
||||
}
|
||||
@@ -9,7 +9,10 @@ $docs$annotation
|
||||
public class $jname {
|
||||
|
||||
protected final long nativeObj;
|
||||
protected $jname(long addr) { nativeObj = addr; }
|
||||
protected $jname(long addr) {
|
||||
nativeObj = addr;
|
||||
$jcleaner
|
||||
}
|
||||
|
||||
public long getNativeObjAddr() { return nativeObj; }
|
||||
|
||||
|
||||
@@ -74,6 +74,18 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Embind requires C++17 or newer from Emscripten 4.0.20.
|
||||
# See https://github.com/emscripten-core/emscripten/blob/main/ChangeLog.md#4020---111825
|
||||
if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.20")
|
||||
if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD STREQUAL "98"
|
||||
OR CMAKE_CXX_STANDARD STREQUAL "11" OR CMAKE_CXX_STANDARD STREQUAL "14")
|
||||
|
||||
message(FATAL_ERROR "[OpenCV.js Build Error] "
|
||||
"Emscripten ${EMSCRIPTEN_VERSION} requires C++17 or newer for Embind, "
|
||||
"but CMAKE_CXX_STANDARD is set to '${CMAKE_CXX_STANDARD}'.\n"
|
||||
"Please re-run emcmake with --cmake_option=\"-DCMAKE_CXX_STANDARD=17\"\n")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
ocv_add_module(js BINDINGS PRIVATE_REQUIRED opencv_js_bindings_generator)
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ if(DEFINED ENV{OPENCV_JS_WHITELIST})
|
||||
else()
|
||||
#generate white list from modules/<module_name>/misc/js/whitelist.json
|
||||
set(OPENCV_JS_WHITELIST_FILE "${CMAKE_CURRENT_BINARY_DIR}/whitelist.json")
|
||||
foreach(m in ${OPENCV_JS_MODULES})
|
||||
foreach(m IN LISTS OPENCV_JS_MODULES)
|
||||
set(js_whitelist "${OPENCV_MODULE_${m}_LOCATION}/misc/js/gen_dict.json")
|
||||
if (EXISTS "${js_whitelist}")
|
||||
file(READ "${js_whitelist}" whitelist_content)
|
||||
|
||||
@@ -523,13 +523,20 @@ class JSWrapperGenerator(object):
|
||||
|
||||
# Return type
|
||||
ret_type = 'void' if variant.rettype.strip() == '' else variant.rettype
|
||||
if ret_type.startswith('Ptr'): #smart pointer
|
||||
# FIX: Ensure namespaced smart-pointer return types in factory methods, e.g.:
|
||||
# Ptr<EdgeDrawing> → Ptr<cv::ximgproc::EdgeDrawing>
|
||||
if factory and class_info is not None and ret_type.startswith('Ptr<'):
|
||||
inner = ret_type[len('Ptr<'):-1].strip()
|
||||
if '::' not in inner and inner == class_info.name:
|
||||
ret_type = 'Ptr<%s>' % class_info.cname
|
||||
|
||||
if ret_type.startswith('Ptr'): # smart pointer
|
||||
ptr_type = ret_type.replace('Ptr<', '').replace('>', '')
|
||||
if ptr_type in type_dict:
|
||||
ret_type = type_dict[ptr_type]
|
||||
for key in type_dict:
|
||||
if key in ret_type:
|
||||
ret_type = re.sub(r"\b" + key + r"\b", type_dict[key], ret_type)
|
||||
for key in type_dict:
|
||||
if key in ret_type:
|
||||
ret_type = re.sub(r"\b" + key + r"\b", type_dict[key], ret_type)
|
||||
arg_types = []
|
||||
unwrapped_arg_types = []
|
||||
for arg in variant.args:
|
||||
@@ -708,6 +715,12 @@ class JSWrapperGenerator(object):
|
||||
ret_type = 'void' if variant.rettype.strip() == '' else variant.rettype
|
||||
|
||||
ret_type = ret_type.strip()
|
||||
# Same namespace fix for factory methods: Ptr<EdgeDrawing> -> Ptr<cv::ximgproc::EdgeDrawing>
|
||||
if factory and class_info is not None and ret_type.startswith('Ptr<'):
|
||||
inner = ret_type[len('Ptr<'):-1].strip()
|
||||
if '::' not in inner and inner == class_info.name:
|
||||
ret_type = 'Ptr<%s>' % class_info.cname
|
||||
|
||||
if ret_type.startswith('Ptr'): #smart pointer
|
||||
ptr_type = ret_type.replace('Ptr<', '').replace('>', '')
|
||||
if ptr_type in type_dict:
|
||||
|
||||
@@ -410,3 +410,19 @@ if (
|
||||
if (cv.UMat) cv.UMat.prototype[Symbol.dispose] = cv.UMat.prototype.delete;
|
||||
// Add more as OpenCV gains new manual-cleanup classes
|
||||
}
|
||||
|
||||
// Override Emscripten's shallow clone() with OpenCV's deep copy mat_clone()
|
||||
// This restores the expected behavior where clone() performs a deep copy.
|
||||
// Background: Emscripten 3.1.71+ added ClassHandle.clone() which only does shallow copy.
|
||||
// See: https://github.com/opencv/opencv/pull/26643
|
||||
// See: https://github.com/opencv/opencv/issues/27572
|
||||
var _opencv_onRuntimeInitialized_backup = Module['onRuntimeInitialized'];
|
||||
Module['onRuntimeInitialized'] = function() {
|
||||
if (_opencv_onRuntimeInitialized_backup) {
|
||||
_opencv_onRuntimeInitialized_backup();
|
||||
}
|
||||
if (typeof cv !== 'undefined' && cv.Mat &&
|
||||
typeof cv.Mat.prototype.mat_clone === 'function') {
|
||||
cv.Mat.prototype.clone = cv.Mat.prototype.mat_clone;
|
||||
}
|
||||
};
|
||||
@@ -552,7 +552,7 @@ QUnit.test('test_filter', function(assert) {
|
||||
cv.stackBlur(src, src, new cv.Size(3, 3));
|
||||
|
||||
// Verify result.
|
||||
let expected = new Uint8Array([22,29,36,38,43,50]);
|
||||
let expected = new Uint8Array([14,22,29,46,51,58]);
|
||||
|
||||
assert.deepEqual(src.data, expected);
|
||||
src.delete();
|
||||
|
||||
@@ -173,7 +173,7 @@ QUnit.test('test_mat_creation', function(assert) {
|
||||
// clone
|
||||
{
|
||||
let mat = cv.Mat.ones(5, 5, cv.CV_8UC1);
|
||||
let mat2 = mat.mat_clone();
|
||||
let mat2 = mat.clone();
|
||||
|
||||
assert.equal(mat.channels, mat2.channels);
|
||||
assert.equal(mat.size().height, mat2.size().height);
|
||||
|
||||
@@ -318,6 +318,33 @@ public:
|
||||
CV_WRAP void detectMarkers(InputArray image, OutputArrayOfArrays corners, OutputArray ids,
|
||||
OutputArrayOfArrays rejectedImgPoints = noArray()) const;
|
||||
|
||||
/** @brief Marker detection with confidence computation
|
||||
*
|
||||
* @param image input image
|
||||
* @param corners vector of detected marker corners. For each marker, its four corners
|
||||
* are provided, (e.g std::vector<std::vector<cv::Point2f> > ). For N detected markers,
|
||||
* the dimensions of this array is Nx4. The order of the corners is clockwise.
|
||||
* @param ids vector of identifiers of the detected markers. The identifier is of type int
|
||||
* (e.g. std::vector<int>). For N detected markers, the size of ids is also N.
|
||||
* The identifiers have the same order than the markers in the imgPoints array.
|
||||
* @param markersConfidence contains the normalized confidence [0;1] of the markers' detection,
|
||||
* defined as 1 minus the normalized uncertainty (percentage of incorrect pixel detections),
|
||||
* with 1 describing a pixel perfect detection. The confidence values are of type float
|
||||
* (e.g. std::vector<float>)
|
||||
* @param rejectedImgPoints contains the imgPoints of those squares whose inner code has not a
|
||||
* correct codification. Useful for debugging purposes.
|
||||
*
|
||||
* Performs marker detection in the input image. Only markers included in the first specified dictionary
|
||||
* are searched. For each detected marker, it returns the 2D position of its corner in the image
|
||||
* and its corresponding identifier.
|
||||
* Note that this function does not perform pose estimation.
|
||||
* @note The function does not correct lens distortion or takes it into account. It's recommended to undistort
|
||||
* input image with corresponding camera model, if camera parameters are known
|
||||
* @sa undistort, estimatePoseSingleMarkers, estimatePoseBoard
|
||||
*/
|
||||
CV_WRAP void detectMarkersWithConfidence(InputArray image, OutputArrayOfArrays corners, OutputArray ids, OutputArray markersConfidence,
|
||||
OutputArrayOfArrays rejectedImgPoints = noArray()) const;
|
||||
|
||||
/** @brief Refine not detected markers based on the already detected and the board layout
|
||||
*
|
||||
* @param image input image
|
||||
|
||||
@@ -71,7 +71,6 @@ class CV_EXPORTS_W_SIMPLE Dictionary {
|
||||
*/
|
||||
CV_WRAP int getDistanceToId(InputArray bits, int id, bool allRotations = true) const;
|
||||
|
||||
|
||||
/** @brief Generate a canonical marker image
|
||||
*/
|
||||
CV_WRAP void generateImageMarker(int id, int sidePixels, OutputArray _img, int borderBits = 1) const;
|
||||
@@ -84,7 +83,7 @@ class CV_EXPORTS_W_SIMPLE Dictionary {
|
||||
|
||||
/** @brief Transform list of bytes to matrix of bits
|
||||
*/
|
||||
CV_WRAP static Mat getBitsFromByteList(const Mat &byteList, int markerSize);
|
||||
CV_WRAP static Mat getBitsFromByteList(const Mat &byteList, int markerSize, int rotationId = 0);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief detect aruco markers and interpolate position of ChArUco board corners
|
||||
* @param image input image necesary for corner refinement. Note that markers are not detected and
|
||||
* @param image input image necessary for corner refinement. Note that markers are not detected and
|
||||
* should be sent in corners and ids parameters.
|
||||
* @param charucoCorners interpolated chessboard corners.
|
||||
* @param charucoIds interpolated chessboard corners identifiers.
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "../../precomp.hpp"
|
||||
#include "apriltag_quad_thresh.hpp"
|
||||
#include "unionfind.hpp"
|
||||
|
||||
//#define APRIL_DEBUG
|
||||
#ifdef APRIL_DEBUG
|
||||
@@ -93,7 +94,7 @@ void ptsort_(struct pt *pts, int sz)
|
||||
// a merge sort with temp storage.
|
||||
|
||||
// Use stack storage if it's not too big.
|
||||
cv::AutoBuffer<struct pt, 1024> _tmp_stack(sz);
|
||||
AutoBuffer<struct pt, 1024> _tmp_stack(sz);
|
||||
memcpy(_tmp_stack.data(), pts, sizeof(struct pt) * sz);
|
||||
|
||||
int asz = sz/2;
|
||||
@@ -571,31 +572,6 @@ int quad_segment_agg(int sz, struct line_fit_pt *lfps, int indices[4]){
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define DO_UNIONFIND(dx, dy) if (im.data[y*s + dy*s + x + dx] == v) unionfind_connect(uf, y*w + x, y*w + dy*w + x + dx);
|
||||
static void do_unionfind_line(unionfind_t *uf, Mat &im, int w, int s, int y){
|
||||
CV_Assert(y+1 < im.rows);
|
||||
CV_Assert(!im.empty());
|
||||
|
||||
for (int x = 1; x < w - 1; x++) {
|
||||
uint8_t v = im.data[y*s + x];
|
||||
|
||||
if (v == 127)
|
||||
continue;
|
||||
|
||||
// (dx,dy) pairs for 8 connectivity:
|
||||
// (REFERENCE) (1, 0)
|
||||
// (-1, 1) (0, 1) (1, 1)
|
||||
//
|
||||
DO_UNIONFIND(1, 0);
|
||||
DO_UNIONFIND(0, 1);
|
||||
if (v == 255) {
|
||||
DO_UNIONFIND(-1, 1);
|
||||
DO_UNIONFIND(1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef DO_UNIONFIND
|
||||
|
||||
/**
|
||||
* return 1 if the quad looks okay, 0 if it should be discarded
|
||||
* quad
|
||||
@@ -1309,11 +1285,11 @@ zarray_t *apriltag_quad_thresh(const DetectorParameters ¶meters, const Mat &
|
||||
////////////////////////////////////////////////////////
|
||||
// step 2. find connected components.
|
||||
|
||||
unionfind_t *uf = unionfind_create(w * h);
|
||||
UnionFind uf(w * h);
|
||||
|
||||
// TODO PARALLELIZE
|
||||
for (int y = 0; y < h - 1; y++) {
|
||||
do_unionfind_line(uf, thold, w, ts, y);
|
||||
uf.do_line(thold, w, ts, y);
|
||||
}
|
||||
|
||||
// XXX sizing??
|
||||
@@ -1329,7 +1305,7 @@ zarray_t *apriltag_quad_thresh(const DetectorParameters ¶meters, const Mat &
|
||||
continue;
|
||||
|
||||
// XXX don't query this until we know we need it?
|
||||
uint64_t rep0 = unionfind_get_representative(uf, y*w + x);
|
||||
uint64_t rep0 = uf.get_representative(y*w + x);
|
||||
|
||||
// whenever we find two adjacent pixels such that one is
|
||||
// white and the other black, we add the point half-way
|
||||
@@ -1356,7 +1332,7 @@ zarray_t *apriltag_quad_thresh(const DetectorParameters ¶meters, const Mat &
|
||||
uint8_t v1 = thold.data[y*ts + dy*ts + x + dx]; \
|
||||
\
|
||||
if (v0 + v1 == 255) { \
|
||||
uint64_t rep1 = unionfind_get_representative(uf, y*w + dy*w + x + dx); \
|
||||
uint64_t rep1 = uf.get_representative(y*w + dy*w + x + dx); \
|
||||
uint64_t clusterid; \
|
||||
if (rep0 < rep1) \
|
||||
clusterid = (rep1 << 32) + rep0; \
|
||||
@@ -1405,9 +1381,9 @@ uint32_t *colors = (uint32_t*) calloc(w*h, sizeof(*colors));
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
uint32_t v = unionfind_get_representative(uf, y*w+x);
|
||||
uint32_t v = uf.get_representative(y*w+x);
|
||||
|
||||
if (unionfind_get_set_size(uf, v) < parameters->aprilTagMinClusterPixels)
|
||||
if (uf.get_set_size(v) < parameters->aprilTagMinClusterPixels)
|
||||
continue;
|
||||
|
||||
uint32_t color = colors[v];
|
||||
@@ -1533,8 +1509,6 @@ for (int i = 0; i < _zarray_size(quads); i++) {
|
||||
imwrite("2.5 debug_lines.pnm", out);
|
||||
#endif
|
||||
|
||||
unionfind_destroy(uf);
|
||||
|
||||
for (int i = 0; i < _zarray_size(clusters); i++) {
|
||||
zarray_t *cluster;
|
||||
_zarray_get(clusters, i, &cluster);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#ifndef _OPENCV_APRIL_QUAD_THRESH_HPP_
|
||||
#define _OPENCV_APRIL_QUAD_THRESH_HPP_
|
||||
|
||||
#include "unionfind.hpp"
|
||||
#include "zmaxheap.hpp"
|
||||
#include "zarray.hpp"
|
||||
|
||||
|
||||
@@ -17,115 +17,115 @@
|
||||
namespace cv {
|
||||
namespace aruco {
|
||||
|
||||
typedef struct unionfind unionfind_t;
|
||||
struct unionfind{
|
||||
struct UnionFind {
|
||||
UnionFind(uint32_t _maxid)
|
||||
{
|
||||
maxid = _maxid;
|
||||
data.resize(maxid+1);
|
||||
for (unsigned int i = 0; i <= maxid; i++) {
|
||||
data[i].size = 1;
|
||||
data[i].parent = i;
|
||||
}
|
||||
};
|
||||
|
||||
inline uint32_t get_representative(uint32_t id) {
|
||||
uint32_t root = id;
|
||||
|
||||
// chase down the root
|
||||
while (data[root].parent != root) {
|
||||
root = data[root].parent;
|
||||
}
|
||||
|
||||
// go back and collapse the tree.
|
||||
//
|
||||
// XXX: on some of our workloads that have very shallow trees
|
||||
// (e.g. image segmentation), we are actually faster not doing
|
||||
// this...
|
||||
while (data[id].parent != root) {
|
||||
uint32_t tmp = data[id].parent;
|
||||
data[id].parent = root;
|
||||
id = tmp;
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
inline uint32_t get_set_size(uint32_t id) {
|
||||
uint32_t repid = get_representative(id);
|
||||
return data[repid].size;
|
||||
}
|
||||
|
||||
inline uint32_t connect(uint32_t aid, uint32_t bid) {
|
||||
uint32_t aroot = get_representative(aid);
|
||||
uint32_t broot = get_representative(bid);
|
||||
|
||||
if (aroot == broot)
|
||||
return aroot;
|
||||
|
||||
// we don't perform "union by rank", but we perform a similar
|
||||
// operation (but probably without the same asymptotic guarantee):
|
||||
// We join trees based on the number of *elements* (as opposed to
|
||||
// rank) contained within each tree. I.e., we use size as a proxy
|
||||
// for rank. In my testing, it's often *faster* to use size than
|
||||
// rank, perhaps because the rank of the tree isn't that critical
|
||||
// if there are very few nodes in it.
|
||||
uint32_t asize = data[aroot].size;
|
||||
uint32_t bsize = data[broot].size;
|
||||
|
||||
// optimization idea: We could shortcut some or all of the tree
|
||||
// that is grafted onto the other tree. Pro: those nodes were just
|
||||
// read and so are probably in cache. Con: it might end up being
|
||||
// wasted effort -- the tree might be grafted onto another tree in
|
||||
// a moment!
|
||||
if (asize > bsize) {
|
||||
data[broot].parent = aroot;
|
||||
data[aroot].size += bsize;
|
||||
return aroot;
|
||||
} else {
|
||||
data[aroot].parent = broot;
|
||||
data[broot].size += asize;
|
||||
return broot;
|
||||
}
|
||||
}
|
||||
|
||||
#define DO_UNIONFIND(dx, dy) if (im.data[y*s + dy*s + x + dx] == v) connect(y*w + x, y*w + dy*w + x + dx);
|
||||
void do_line(Mat &im, int w, int s, int y) {
|
||||
CV_Assert(y+1 < im.rows);
|
||||
CV_Assert(!im.empty());
|
||||
|
||||
for (int x = 1; x < w - 1; x++) {
|
||||
uint8_t v = im.data[y*s + x];
|
||||
|
||||
if (v == 127)
|
||||
continue;
|
||||
|
||||
// (dx,dy) pairs for 8 connectivity:
|
||||
// (REFERENCE) (1, 0)
|
||||
// (-1, 1) (0, 1) (1, 1)
|
||||
//
|
||||
DO_UNIONFIND(1, 0);
|
||||
DO_UNIONFIND(0, 1);
|
||||
if (v == 255) {
|
||||
DO_UNIONFIND(-1, 1);
|
||||
DO_UNIONFIND(1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef DO_UNIONFIND
|
||||
|
||||
struct ufrec {
|
||||
// the parent of this node. If a node's parent is its own index,
|
||||
// then it is a root.
|
||||
uint32_t parent;
|
||||
|
||||
// for the root of a connected component, the number of components
|
||||
// connected to it. For intermediate values, it's not meaningful.
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
uint32_t maxid;
|
||||
struct ufrec *data;
|
||||
std::vector<ufrec> data;
|
||||
};
|
||||
|
||||
struct ufrec{
|
||||
// the parent of this node. If a node's parent is its own index,
|
||||
// then it is a root.
|
||||
uint32_t parent;
|
||||
|
||||
// for the root of a connected component, the number of components
|
||||
// connected to it. For intermediate values, it's not meaningful.
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
static inline unionfind_t *unionfind_create(uint32_t maxid){
|
||||
unionfind_t *uf = (unionfind_t*) calloc(1, sizeof(unionfind_t));
|
||||
uf->maxid = maxid;
|
||||
uf->data = (struct ufrec*) malloc((maxid+1) * sizeof(struct ufrec));
|
||||
for (unsigned int i = 0; i <= maxid; i++) {
|
||||
uf->data[i].size = 1;
|
||||
uf->data[i].parent = i;
|
||||
}
|
||||
return uf;
|
||||
}
|
||||
|
||||
static inline void unionfind_destroy(unionfind_t *uf){
|
||||
free(uf->data);
|
||||
free(uf);
|
||||
}
|
||||
|
||||
/*
|
||||
static inline uint32_t unionfind_get_representative(unionfind_t *uf, uint32_t id)
|
||||
{
|
||||
// base case: a node is its own parent
|
||||
if (uf->data[id].parent == id)
|
||||
return id;
|
||||
|
||||
// otherwise, recurse
|
||||
uint32_t root = unionfind_get_representative(uf, uf->data[id].parent);
|
||||
|
||||
// short circuit the path. [XXX This write prevents tail recursion]
|
||||
uf->data[id].parent = root;
|
||||
|
||||
return root;
|
||||
}
|
||||
*/
|
||||
|
||||
// this one seems to be every-so-slightly faster than the recursive
|
||||
// version above.
|
||||
static inline uint32_t unionfind_get_representative(unionfind_t *uf, uint32_t id){
|
||||
uint32_t root = id;
|
||||
|
||||
// chase down the root
|
||||
while (uf->data[root].parent != root) {
|
||||
root = uf->data[root].parent;
|
||||
}
|
||||
|
||||
// go back and collapse the tree.
|
||||
//
|
||||
// XXX: on some of our workloads that have very shallow trees
|
||||
// (e.g. image segmentation), we are actually faster not doing
|
||||
// this...
|
||||
while (uf->data[id].parent != root) {
|
||||
uint32_t tmp = uf->data[id].parent;
|
||||
uf->data[id].parent = root;
|
||||
id = tmp;
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
static inline uint32_t unionfind_get_set_size(unionfind_t *uf, uint32_t id){
|
||||
uint32_t repid = unionfind_get_representative(uf, id);
|
||||
return uf->data[repid].size;
|
||||
}
|
||||
|
||||
static inline uint32_t unionfind_connect(unionfind_t *uf, uint32_t aid, uint32_t bid){
|
||||
uint32_t aroot = unionfind_get_representative(uf, aid);
|
||||
uint32_t broot = unionfind_get_representative(uf, bid);
|
||||
|
||||
if (aroot == broot)
|
||||
return aroot;
|
||||
|
||||
// we don't perform "union by rank", but we perform a similar
|
||||
// operation (but probably without the same asymptotic guarantee):
|
||||
// We join trees based on the number of *elements* (as opposed to
|
||||
// rank) contained within each tree. I.e., we use size as a proxy
|
||||
// for rank. In my testing, it's often *faster* to use size than
|
||||
// rank, perhaps because the rank of the tree isn't that critical
|
||||
// if there are very few nodes in it.
|
||||
uint32_t asize = uf->data[aroot].size;
|
||||
uint32_t bsize = uf->data[broot].size;
|
||||
|
||||
// optimization idea: We could shortcut some or all of the tree
|
||||
// that is grafted onto the other tree. Pro: those nodes were just
|
||||
// read and so are probably in cache. Con: it might end up being
|
||||
// wasted effort -- the tree might be grafted onto another tree in
|
||||
// a moment!
|
||||
if (asize > bsize) {
|
||||
uf->data[broot].parent = aroot;
|
||||
uf->data[aroot].size += bsize;
|
||||
return aroot;
|
||||
} else {
|
||||
uf->data[aroot].parent = broot;
|
||||
uf->data[broot].size += asize;
|
||||
return broot;
|
||||
}
|
||||
}
|
||||
}}
|
||||
#endif
|
||||
|
||||
@@ -84,7 +84,6 @@ void zmaxheap_destroy(zmaxheap_t *heap)
|
||||
{
|
||||
free(heap->values);
|
||||
free(heap->data);
|
||||
memset(heap, 0, sizeof(zmaxheap_t));
|
||||
free(heap);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "opencv2/objdetect/aruco_board.hpp"
|
||||
#include "apriltag/apriltag_quad_thresh.hpp"
|
||||
#include "aruco_utils.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
|
||||
@@ -124,7 +125,7 @@ static void _threshold(InputArray _in, OutputArray _out, int winSize, double con
|
||||
|
||||
|
||||
/**
|
||||
* @brief Given a tresholded image, find the contours, calculate their polygonal approximation
|
||||
* @brief Given a thresholded image, find the contours, calculate their polygonal approximation
|
||||
* and take those that accomplish some conditions
|
||||
*/
|
||||
static void _findMarkerContours(const Mat &in, vector<vector<Point2f> > &candidates,
|
||||
@@ -313,10 +314,11 @@ static void _detectInitialCandidates(const Mat &grey, vector<vector<Point2f> > &
|
||||
* the border bits
|
||||
*/
|
||||
static Mat _extractBits(InputArray _image, const vector<Point2f>& corners, int markerSize,
|
||||
int markerBorderBits, int cellSize, double cellMarginRate, double minStdDevOtsu) {
|
||||
int markerBorderBits, int cellSize, double cellMarginRate, double minStdDevOtsu,
|
||||
OutputArray _cellPixelRatio = noArray()) {
|
||||
CV_Assert(_image.getMat().channels() == 1);
|
||||
CV_Assert(corners.size() == 4ull);
|
||||
CV_Assert(markerBorderBits > 0 && cellSize > 0 && cellMarginRate >= 0 && cellMarginRate <= 1);
|
||||
CV_Assert(markerBorderBits > 0 && cellSize > 0 && cellMarginRate >= 0 && cellMarginRate <= 0.5);
|
||||
CV_Assert(minStdDevOtsu >= 0);
|
||||
|
||||
// number of bits in the marker
|
||||
@@ -353,9 +355,16 @@ static Mat _extractBits(InputArray _image, const vector<Point2f>& corners, int m
|
||||
bits.setTo(1);
|
||||
else
|
||||
bits.setTo(0);
|
||||
if(_cellPixelRatio.needed()) bits.convertTo(_cellPixelRatio, CV_32F);
|
||||
return bits;
|
||||
}
|
||||
|
||||
Mat cellPixelRatio;
|
||||
if (_cellPixelRatio.needed()) {
|
||||
_cellPixelRatio.create(markerSizeWithBorders, markerSizeWithBorders, CV_32FC1);
|
||||
cellPixelRatio = _cellPixelRatio.getMatRef();
|
||||
}
|
||||
|
||||
// now extract code, first threshold using Otsu
|
||||
threshold(resultImg, resultImg, 125, 255, THRESH_BINARY | THRESH_OTSU);
|
||||
|
||||
@@ -369,6 +378,9 @@ static Mat _extractBits(InputArray _image, const vector<Point2f>& corners, int m
|
||||
// count white pixels on each cell to assign its value
|
||||
size_t nZ = (size_t) countNonZero(square);
|
||||
if(nZ > square.total() / 2) bits.at<unsigned char>(y, x) = 1;
|
||||
|
||||
// define the cell pixel ratio as the ratio of the white pixels. For inverted markers, the ratio will be inverted.
|
||||
if(_cellPixelRatio.needed()) cellPixelRatio.at<float>(y, x) = (nZ / (float)square.total());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,6 +415,52 @@ static int _getBorderErrors(const Mat &bits, int markerSize, int borderSize) {
|
||||
}
|
||||
|
||||
|
||||
/** @brief Given a matrix containing the percentage of white pixels in each marker cell, returns the normalized marker confidence [0;1].
|
||||
* The confidence is defined as 1 - normalized uncertainty, where 1 describes a pixel perfect detection.
|
||||
* The rotation is set to 0,1,2,3 for [0, 90, 180, 270] deg CCW rotations.
|
||||
*/
|
||||
|
||||
static float _getMarkerConfidence(const Mat& groundTruthbits, const Mat &cellPixelRatio, const int markerSize, const int borderSize) {
|
||||
|
||||
CV_Assert(markerSize == groundTruthbits.cols && markerSize == groundTruthbits.rows);
|
||||
|
||||
const int sizeWithBorders = markerSize + 2 * borderSize;
|
||||
CV_Assert(markerSize > 0 && cellPixelRatio.cols == sizeWithBorders && cellPixelRatio.rows == sizeWithBorders);
|
||||
|
||||
// Get border uncertainty. cellPixelRatio has the opposite color as the borders --> it is the uncertainty.
|
||||
float tempBorderUnc = 0.f;
|
||||
for(int y = 0; y < sizeWithBorders; y++) {
|
||||
for(int k = 0; k < borderSize; k++) {
|
||||
// Left and right vertical sides
|
||||
tempBorderUnc += cellPixelRatio.ptr<float>(y)[k];
|
||||
tempBorderUnc += cellPixelRatio.ptr<float>(y)[sizeWithBorders - 1 - k];
|
||||
}
|
||||
}
|
||||
for(int x = borderSize; x < sizeWithBorders - borderSize; x++) {
|
||||
for(int k = 0; k < borderSize; k++) {
|
||||
// Top and bottom horizontal sides
|
||||
tempBorderUnc += cellPixelRatio.ptr<float>(k)[x];
|
||||
tempBorderUnc += cellPixelRatio.ptr<float>(sizeWithBorders - 1 - k)[x];
|
||||
}
|
||||
}
|
||||
|
||||
// Get the inner marker uncertainty. For a white or black cell, the uncertainty is the ratio of black or white pixels respectively.
|
||||
float tempInnerUnc = 0.f;
|
||||
for(int y = borderSize; y < markerSize + borderSize; y++) {
|
||||
for(int x = borderSize; x < markerSize + borderSize; x++) {
|
||||
tempInnerUnc += std::abs(groundTruthbits.ptr<float>(y - borderSize)[x - borderSize] - cellPixelRatio.ptr<float>(y)[x]);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the overall normalized marker uncertainty and convert it to confidence
|
||||
const float area = static_cast<float>(sizeWithBorders) * sizeWithBorders;
|
||||
const float normalizedMarkerUnc = (tempInnerUnc + tempBorderUnc) / area;
|
||||
const float normalizedMarkerConfidence = 1.f - normalizedMarkerUnc;
|
||||
|
||||
return std::max(0.f, std::min(1.f, normalizedMarkerConfidence));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Tries to identify one candidate given the dictionary
|
||||
* @return candidate typ. zero if the candidate is not valid,
|
||||
@@ -412,6 +470,7 @@ static int _getBorderErrors(const Mat &bits, int markerSize, int borderSize) {
|
||||
static uint8_t _identifyOneCandidate(const Dictionary& dictionary, const Mat& _image,
|
||||
const vector<Point2f>& _corners, int& idx,
|
||||
const DetectorParameters& params, int& rotation,
|
||||
float &markerConfidence, bool confidenceNeeded,
|
||||
const float scale = 1.f) {
|
||||
CV_DbgAssert(params.markerBorderBits > 0);
|
||||
uint8_t typ=1;
|
||||
@@ -423,10 +482,12 @@ static uint8_t _identifyOneCandidate(const Dictionary& dictionary, const Mat& _i
|
||||
scaled_corners[i].y = _corners[i].y * scale;
|
||||
}
|
||||
|
||||
Mat cellPixelRatio;
|
||||
Mat candidateBits =
|
||||
_extractBits(_image, scaled_corners, dictionary.markerSize, params.markerBorderBits,
|
||||
params.perspectiveRemovePixelPerCell,
|
||||
params.perspectiveRemoveIgnoredMarginPerCell, params.minOtsuStdDev);
|
||||
params.perspectiveRemoveIgnoredMarginPerCell, params.minOtsuStdDev,
|
||||
cellPixelRatio);
|
||||
|
||||
// analyze border bits
|
||||
int maximumErrorsInBorder =
|
||||
@@ -441,6 +502,7 @@ static uint8_t _identifyOneCandidate(const Dictionary& dictionary, const Mat& _i
|
||||
int invBError = _getBorderErrors(invertedImg, dictionary.markerSize, params.markerBorderBits);
|
||||
// white marker
|
||||
if(invBError<borderErrors){
|
||||
cellPixelRatio = 1.f - cellPixelRatio;
|
||||
borderErrors = invBError;
|
||||
invertedImg.copyTo(candidateBits);
|
||||
typ=2;
|
||||
@@ -458,6 +520,14 @@ static uint8_t _identifyOneCandidate(const Dictionary& dictionary, const Mat& _i
|
||||
if(!dictionary.identify(onlyBits, idx, rotation, params.errorCorrectionRate))
|
||||
return 0;
|
||||
|
||||
// compute the candidate's confidence
|
||||
if(confidenceNeeded) {
|
||||
Mat groundTruthbits;
|
||||
Mat bitsUints = dictionary.getBitsFromByteList(dictionary.bytesList.rowRange(idx, idx + 1), dictionary.markerSize, rotation);
|
||||
bitsUints.convertTo(groundTruthbits, CV_32F);
|
||||
markerConfidence = _getMarkerConfidence(groundTruthbits, cellPixelRatio, dictionary.markerSize, params.markerBorderBits);
|
||||
}
|
||||
|
||||
return typ;
|
||||
}
|
||||
|
||||
@@ -657,7 +727,7 @@ struct ArucoDetector::ArucoDetectorImpl {
|
||||
* @brief Detect markers either using multiple or just first dictionary
|
||||
*/
|
||||
void detectMarkers(InputArray _image, OutputArrayOfArrays _corners, OutputArray _ids,
|
||||
OutputArrayOfArrays _rejectedImgPoints, OutputArray _dictIndices, DictionaryMode dictMode) {
|
||||
OutputArrayOfArrays _rejectedImgPoints, OutputArray _dictIndices, OutputArray _markersConfidence, DictionaryMode dictMode) {
|
||||
CV_Assert(!_image.empty());
|
||||
|
||||
CV_Assert(detectorParams.markerBorderBits > 0);
|
||||
@@ -717,6 +787,7 @@ struct ArucoDetector::ArucoDetectorImpl {
|
||||
vector<vector<Point2f> > candidates;
|
||||
vector<vector<Point> > contours;
|
||||
vector<int> ids;
|
||||
vector<float> markersConfidence;
|
||||
|
||||
/// STEP 2.a Detect marker candidates :: using AprilTag
|
||||
if(detectorParams.cornerRefinementMethod == (int)CORNER_REFINE_APRILTAG){
|
||||
@@ -738,7 +809,7 @@ struct ArucoDetector::ArucoDetectorImpl {
|
||||
|
||||
/// STEP 2: Check candidate codification (identify markers)
|
||||
identifyCandidates(grey, grey_pyramid, selectedCandidates, candidates, contours,
|
||||
ids, dictionary, rejectedImgPoints);
|
||||
ids, dictionary, rejectedImgPoints, markersConfidence, _markersConfidence.needed());
|
||||
|
||||
/// STEP 3: Corner refinement :: use corner subpix
|
||||
if (detectorParams.cornerRefinementMethod == (int)CORNER_REFINE_SUBPIX) {
|
||||
@@ -766,7 +837,7 @@ struct ArucoDetector::ArucoDetectorImpl {
|
||||
// temporary variable to store the current candidates
|
||||
vector<vector<Point2f>> currentCandidates;
|
||||
identifyCandidates(grey, grey_pyramid, candidatesPerDictionarySize.at(currentDictionary.markerSize), currentCandidates, contours,
|
||||
ids, currentDictionary, rejectedImgPoints);
|
||||
ids, currentDictionary, rejectedImgPoints, markersConfidence, _markersConfidence.needed());
|
||||
if (_dictIndices.needed()) {
|
||||
dictIndices.insert(dictIndices.end(), currentCandidates.size(), dictIndex);
|
||||
}
|
||||
@@ -849,6 +920,9 @@ struct ArucoDetector::ArucoDetectorImpl {
|
||||
if (_dictIndices.needed()) {
|
||||
Mat(dictIndices).copyTo(_dictIndices);
|
||||
}
|
||||
if (_markersConfidence.needed()) {
|
||||
Mat(markersConfidence).copyTo(_markersConfidence);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -982,9 +1056,10 @@ struct ArucoDetector::ArucoDetectorImpl {
|
||||
*/
|
||||
void identifyCandidates(const Mat& grey, const vector<Mat>& image_pyr, vector<MarkerCandidateTree>& selectedContours,
|
||||
vector<vector<Point2f> >& accepted, vector<vector<Point> >& contours,
|
||||
vector<int>& ids, const Dictionary& currentDictionary, vector<vector<Point2f>>& rejected) const {
|
||||
vector<int>& ids, const Dictionary& currentDictionary, vector<vector<Point2f>>& rejected, vector<float>& markersConfidence, bool confidenceNeeded) const {
|
||||
size_t ncandidates = selectedContours.size();
|
||||
|
||||
vector<float> markersConfidenceTmp(ncandidates, 0.f);
|
||||
vector<int> idsTmp(ncandidates, -1);
|
||||
vector<int> rotated(ncandidates, 0);
|
||||
vector<uint8_t> validCandidates(ncandidates, 0);
|
||||
@@ -1018,11 +1093,11 @@ struct ArucoDetector::ArucoDetectorImpl {
|
||||
}
|
||||
const float scale = detectorParams.useAruco3Detection ? img.cols / static_cast<float>(grey.cols) : 1.f;
|
||||
|
||||
validCandidates[v] = _identifyOneCandidate(currentDictionary, img, selectedContours[v].corners, idsTmp[v], detectorParams, rotated[v], scale);
|
||||
validCandidates[v] = _identifyOneCandidate(currentDictionary, img, selectedContours[v].corners, idsTmp[v], detectorParams, rotated[v], markersConfidenceTmp[v], confidenceNeeded, scale);
|
||||
|
||||
if (validCandidates[v] == 0 && checkCloseContours) {
|
||||
for (const MarkerCandidate& closeMarkerCandidate: selectedContours[v].closeContours) {
|
||||
validCandidates[v] = _identifyOneCandidate(currentDictionary, img, closeMarkerCandidate.corners, idsTmp[v], detectorParams, rotated[v], scale);
|
||||
validCandidates[v] = _identifyOneCandidate(currentDictionary, img, closeMarkerCandidate.corners, idsTmp[v], detectorParams, rotated[v], markersConfidenceTmp[v], confidenceNeeded, scale);
|
||||
if (validCandidates[v] > 0) {
|
||||
selectedContours[v].corners = closeMarkerCandidate.corners;
|
||||
selectedContours[v].contour = closeMarkerCandidate.contour;
|
||||
@@ -1052,17 +1127,24 @@ struct ArucoDetector::ArucoDetectorImpl {
|
||||
|
||||
for (size_t i = 0ull; i < selectedContours.size(); i++) {
|
||||
if (validCandidates[i] > 0) {
|
||||
// shift corner positions to the correct rotation
|
||||
correctCornerPosition(selectedContours[i].corners, rotated[i]);
|
||||
// shift corner positions to the correct rotation
|
||||
correctCornerPosition(selectedContours[i].corners, rotated[i]);
|
||||
|
||||
accepted.push_back(selectedContours[i].corners);
|
||||
contours.push_back(selectedContours[i].contour);
|
||||
ids.push_back(idsTmp[i]);
|
||||
}
|
||||
else {
|
||||
accepted.push_back(selectedContours[i].corners);
|
||||
contours.push_back(selectedContours[i].contour);
|
||||
ids.push_back(idsTmp[i]);
|
||||
} else {
|
||||
rejected.push_back(selectedContours[i].corners);
|
||||
}
|
||||
}
|
||||
|
||||
if(confidenceNeeded) {
|
||||
for (size_t i = 0ull; i < selectedContours.size(); i++) {
|
||||
if (validCandidates[i] > 0) {
|
||||
markersConfidence.push_back(markersConfidenceTmp[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void performCornerSubpixRefinement(const Mat& grey, const vector<Mat>& grey_pyramid, int closest_pyr_image_idx, const vector<vector<Point2f>>& candidates, const Dictionary& dictionary) const {
|
||||
@@ -1103,14 +1185,19 @@ ArucoDetector::ArucoDetector(const vector<Dictionary> &_dictionaries,
|
||||
arucoDetectorImpl = makePtr<ArucoDetectorImpl>(_dictionaries, _detectorParams, _refineParams);
|
||||
}
|
||||
|
||||
void ArucoDetector::detectMarkersWithConfidence(InputArray _image, OutputArrayOfArrays _corners, OutputArray _ids, OutputArray _markersConfidence,
|
||||
OutputArrayOfArrays _rejectedImgPoints) const {
|
||||
arucoDetectorImpl->detectMarkers(_image, _corners, _ids, _rejectedImgPoints, noArray(), _markersConfidence, DictionaryMode::Single);
|
||||
}
|
||||
|
||||
void ArucoDetector::detectMarkers(InputArray _image, OutputArrayOfArrays _corners, OutputArray _ids,
|
||||
OutputArrayOfArrays _rejectedImgPoints) const {
|
||||
arucoDetectorImpl->detectMarkers(_image, _corners, _ids, _rejectedImgPoints, noArray(), DictionaryMode::Single);
|
||||
arucoDetectorImpl->detectMarkers(_image, _corners, _ids, _rejectedImgPoints, noArray(), noArray(), DictionaryMode::Single);
|
||||
}
|
||||
|
||||
void ArucoDetector::detectMarkersMultiDict(InputArray _image, OutputArrayOfArrays _corners, OutputArray _ids,
|
||||
OutputArrayOfArrays _rejectedImgPoints, OutputArray _dictIndices) const {
|
||||
arucoDetectorImpl->detectMarkers(_image, _corners, _ids, _rejectedImgPoints, _dictIndices, DictionaryMode::Multi);
|
||||
arucoDetectorImpl->detectMarkers(_image, _corners, _ids, _rejectedImgPoints, _dictIndices, noArray(), DictionaryMode::Multi);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -194,17 +194,24 @@ Mat Dictionary::getByteListFromBits(const Mat &bits) {
|
||||
}
|
||||
|
||||
|
||||
Mat Dictionary::getBitsFromByteList(const Mat &byteList, int markerSize) {
|
||||
Mat Dictionary::getBitsFromByteList(const Mat &byteList, int markerSize, int rotationId) {
|
||||
CV_Assert(byteList.total() > 0 &&
|
||||
byteList.total() >= (unsigned int)markerSize * markerSize / 8 &&
|
||||
byteList.total() <= (unsigned int)markerSize * markerSize / 8 + 1);
|
||||
|
||||
CV_Assert(rotationId >=0 && rotationId < 4);
|
||||
|
||||
Mat bits(markerSize, markerSize, CV_8UC1, Scalar::all(0));
|
||||
|
||||
unsigned char base2List[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
|
||||
|
||||
// Use a base offset for the selected rotation
|
||||
int nbytes = (bits.cols * bits.rows + 8 - 1) / 8; // integer ceil
|
||||
int base = rotationId * nbytes;
|
||||
int currentByteIdx = 0;
|
||||
// we only need the bytes in normal rotation
|
||||
unsigned char currentByte = byteList.ptr()[0];
|
||||
unsigned char currentByte = byteList.ptr()[base + currentByteIdx];
|
||||
int currentBit = 0;
|
||||
|
||||
for(int row = 0; row < bits.rows; row++) {
|
||||
for(int col = 0; col < bits.cols; col++) {
|
||||
if(currentByte >= base2List[currentBit]) {
|
||||
@@ -214,7 +221,7 @@ Mat Dictionary::getBitsFromByteList(const Mat &byteList, int markerSize) {
|
||||
currentBit++;
|
||||
if(currentBit == 8) {
|
||||
currentByteIdx++;
|
||||
currentByte = byteList.ptr()[currentByteIdx];
|
||||
currentByte = byteList.ptr()[base + currentByteIdx];
|
||||
// if not enough bits for one more byte, we are in the end
|
||||
// update bit position accordingly
|
||||
if(8 * (currentByteIdx + 1) > (int)bits.total())
|
||||
|
||||
@@ -316,8 +316,8 @@ struct CharucoDetector::CharucoDetectorImpl {
|
||||
CV_Assert((markerCorners.empty() && markerIds.empty() && !image.empty()) || (markerCorners.total() == markerIds.total()));
|
||||
vector<vector<Point2f>> tmpMarkerCorners;
|
||||
vector<int> tmpMarkerIds;
|
||||
InputOutputArrayOfArrays _markerCorners = markerCorners.needed() ? markerCorners : tmpMarkerCorners;
|
||||
InputOutputArray _markerIds = markerIds.needed() ? markerIds : tmpMarkerIds;
|
||||
InputOutputArrayOfArrays _markerCorners = markerCorners.needed() ? markerCorners : _InputOutputArray(tmpMarkerCorners);
|
||||
InputOutputArray _markerIds = markerIds.needed() ? markerIds : _InputOutputArray(tmpMarkerIds);
|
||||
|
||||
if (markerCorners.empty() && markerIds.empty()) {
|
||||
vector<vector<Point2f> > rejectedMarkers;
|
||||
@@ -341,8 +341,8 @@ struct CharucoDetector::CharucoDetectorImpl {
|
||||
InputOutputArrayOfArrays markerCorners, InputOutputArray markerIds) {
|
||||
vector<vector<Point2f>> tmpMarkerCorners;
|
||||
vector<int> tmpMarkerIds;
|
||||
InputOutputArrayOfArrays _markerCorners = markerCorners.needed() ? markerCorners : tmpMarkerCorners;
|
||||
InputOutputArray _markerIds = markerIds.needed() ? markerIds : tmpMarkerIds;
|
||||
InputOutputArrayOfArrays _markerCorners = markerCorners.needed() ? markerCorners : _InputOutputArray(tmpMarkerCorners);
|
||||
InputOutputArray _markerIds = markerIds.needed() ? markerIds : _InputOutputArray(tmpMarkerIds);
|
||||
detectBoard(image, charucoCorners, charucoIds, _markerCorners, _markerIds);
|
||||
if (charucoParameters.checkMarkers && checkBoard(_markerCorners, _markerIds, charucoCorners, charucoIds) == false) {
|
||||
CV_LOG_DEBUG(NULL, "ChArUco board is built incorrectly");
|
||||
@@ -402,8 +402,8 @@ void CharucoDetector::detectDiamonds(InputArray image, OutputArrayOfArrays _diam
|
||||
|
||||
vector<vector<Point2f>> tmpMarkerCorners;
|
||||
vector<int> tmpMarkerIds;
|
||||
InputOutputArrayOfArrays _markerCorners = inMarkerCorners.needed() ? inMarkerCorners : tmpMarkerCorners;
|
||||
InputOutputArray _markerIds = inMarkerIds.needed() ? inMarkerIds : tmpMarkerIds;
|
||||
InputOutputArrayOfArrays _markerCorners = inMarkerCorners.needed() ? inMarkerCorners : _InputOutputArray(tmpMarkerCorners);
|
||||
InputOutputArray _markerIds = inMarkerIds.needed() ? inMarkerIds : _InputOutputArray(tmpMarkerIds);
|
||||
if (_markerCorners.empty() && _markerIds.empty()) {
|
||||
charucoDetectorImpl->arucoDetector.detectMarkers(image, _markerCorners, _markerIds);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#ifndef __OPENCV_PRECOMP_H__
|
||||
#define __OPENCV_PRECOMP_H__
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/objdetect.hpp"
|
||||
#include "opencv2/objdetect/barcode.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
|
||||
@@ -80,8 +80,10 @@ static Point2f intersectionLines(Point2f a1, Point2f a2, Point2f b1, Point2f b2)
|
||||
// / |
|
||||
// a/ | c
|
||||
|
||||
static inline double getCosVectors(Point2f a, Point2f b, Point2f c)
|
||||
static inline double getCosVectors(Point a, Point b, Point c)
|
||||
{
|
||||
CV_DbgCheckNE(a, b, "Angle between vector and point is undetermined");
|
||||
CV_DbgCheckNE(b, c, "Angle between vector and point is undetermined");
|
||||
return ((a - b).x * (c - b).x + (a - b).y * (c - b).y) / (norm(a - b) * norm(c - b));
|
||||
}
|
||||
|
||||
@@ -407,9 +409,9 @@ void QRDetect::fixationPoints(vector<Point2f> &local_point)
|
||||
list_area_pnt.push_back(current_point);
|
||||
|
||||
vector<LineIterator> list_line_iter;
|
||||
list_line_iter.push_back(LineIterator(bin_barcode, current_point, left_point));
|
||||
list_line_iter.push_back(LineIterator(bin_barcode, current_point, central_point));
|
||||
list_line_iter.push_back(LineIterator(bin_barcode, current_point, right_point));
|
||||
list_line_iter.emplace_back(bin_barcode, current_point, left_point);
|
||||
list_line_iter.emplace_back(bin_barcode, current_point, central_point);
|
||||
list_line_iter.emplace_back(bin_barcode, current_point, right_point);
|
||||
|
||||
for (size_t k = 0; k < list_line_iter.size(); k++)
|
||||
{
|
||||
@@ -752,7 +754,7 @@ vector<Point2f> QRDetect::getQuadrilateral(vector<Point2f> angle_list)
|
||||
{
|
||||
int x = cvRound(angle_list[i].x);
|
||||
int y = cvRound(angle_list[i].y);
|
||||
locations.push_back(Point(x, y));
|
||||
locations.emplace_back(x,y);
|
||||
}
|
||||
|
||||
vector<Point> integer_hull;
|
||||
@@ -822,7 +824,11 @@ vector<Point2f> QRDetect::getQuadrilateral(vector<Point2f> angle_list)
|
||||
Point intrsc_line_hull =
|
||||
intersectionLines(hull[index_hull], hull[next_index_hull],
|
||||
angle_list[1], angle_list[2]);
|
||||
double temp_norm = getCosVectors(hull[index_hull], intrsc_line_hull, angle_closest_pnt);
|
||||
double temp_norm = min_norm;
|
||||
if (intrsc_line_hull != angle_closest_pnt)
|
||||
{
|
||||
temp_norm = getCosVectors(hull[index_hull], intrsc_line_hull, angle_closest_pnt);
|
||||
}
|
||||
if (min_norm > temp_norm &&
|
||||
norm(hull[index_hull] - hull[next_index_hull]) >
|
||||
norm(angle_list[1] - angle_list[2]) * 0.1)
|
||||
@@ -860,7 +866,11 @@ vector<Point2f> QRDetect::getQuadrilateral(vector<Point2f> angle_list)
|
||||
Point intrsc_line_hull =
|
||||
intersectionLines(hull[index_hull], hull[next_index_hull],
|
||||
angle_list[0], angle_list[1]);
|
||||
double temp_norm = getCosVectors(hull[index_hull], intrsc_line_hull, angle_closest_pnt);
|
||||
double temp_norm = min_norm;
|
||||
if (intrsc_line_hull != angle_closest_pnt)
|
||||
{
|
||||
temp_norm = getCosVectors(hull[index_hull], intrsc_line_hull, angle_closest_pnt);
|
||||
}
|
||||
if (min_norm > temp_norm &&
|
||||
norm(hull[index_hull] - hull[next_index_hull]) >
|
||||
norm(angle_list[0] - angle_list[1]) * 0.05)
|
||||
@@ -2204,13 +2214,13 @@ bool QRDecode::straightenQRCodeInParts()
|
||||
|
||||
vector<Point2f> perspective_points;
|
||||
|
||||
perspective_points.push_back(Point2f(0.0, start_cut));
|
||||
perspective_points.push_back(Point2f(perspective_curved_size, start_cut));
|
||||
perspective_points.emplace_back(0.0f, start_cut);
|
||||
perspective_points.emplace_back(perspective_curved_size, start_cut);
|
||||
|
||||
perspective_points.push_back(Point2f(perspective_curved_size, start_cut + dist));
|
||||
perspective_points.push_back(Point2f(0.0, start_cut+dist));
|
||||
perspective_points.emplace_back(perspective_curved_size, start_cut + dist);
|
||||
perspective_points.emplace_back(0.0f, start_cut+dist);
|
||||
|
||||
perspective_points.push_back(Point2f(perspective_curved_size * 0.5f, start_cut + dist * 0.5f));
|
||||
perspective_points.emplace_back(perspective_curved_size * 0.5f, start_cut + dist * 0.5f);
|
||||
|
||||
if (i == 1)
|
||||
{
|
||||
@@ -2281,13 +2291,13 @@ bool QRDecode::straightenQRCodeInParts()
|
||||
}
|
||||
|
||||
vector<Point2f> perspective_straight_points;
|
||||
perspective_straight_points.push_back(Point2f(0.f, 0.f));
|
||||
perspective_straight_points.push_back(Point2f(perspective_curved_size, 0.f));
|
||||
perspective_straight_points.emplace_back(0.f, 0.f);
|
||||
perspective_straight_points.emplace_back(perspective_curved_size, 0.f);
|
||||
|
||||
perspective_straight_points.push_back(Point2f(perspective_curved_size, perspective_curved_size));
|
||||
perspective_straight_points.push_back(Point2f(0.f, perspective_curved_size));
|
||||
perspective_straight_points.emplace_back(perspective_curved_size, perspective_curved_size);
|
||||
perspective_straight_points.emplace_back(0.f, perspective_curved_size);
|
||||
|
||||
perspective_straight_points.push_back(Point2f(perspective_curved_size * 0.5f, perspective_curved_size * 0.5f));
|
||||
perspective_straight_points.emplace_back(perspective_curved_size * 0.5f, perspective_curved_size * 0.5f);
|
||||
|
||||
Mat H = findHomography(original_curved_points, perspective_straight_points);
|
||||
if (H.empty())
|
||||
@@ -3272,9 +3282,9 @@ void QRDetectMulti::fixationPoints(vector<Point2f> &local_point)
|
||||
list_area_pnt.push_back(current_point);
|
||||
|
||||
vector<LineIterator> list_line_iter;
|
||||
list_line_iter.push_back(LineIterator(bin_barcode_temp, current_point, left_point));
|
||||
list_line_iter.push_back(LineIterator(bin_barcode_temp, current_point, central_point));
|
||||
list_line_iter.push_back(LineIterator(bin_barcode_temp, current_point, right_point));
|
||||
list_line_iter.emplace_back(bin_barcode_temp, current_point, left_point);
|
||||
list_line_iter.emplace_back(bin_barcode_temp, current_point, central_point);
|
||||
list_line_iter.emplace_back(bin_barcode_temp, current_point, right_point);
|
||||
|
||||
for (size_t k = 0; k < list_line_iter.size(); k++)
|
||||
{
|
||||
|
||||
@@ -321,6 +321,358 @@ void CV_ArucoDetectionPerspective::run(int) {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper struct and functions for CV_ArucoDetectionConfidence
|
||||
|
||||
// Inverts a square subregion inside selected cells of a marker to simulate a confidence drop
|
||||
enum class MarkerRegionToTemper {
|
||||
BORDER, // Only invert cells within the marker border bits
|
||||
INNER, // Only invert cells in the inner part of the marker (excluding borders)
|
||||
ALL // Invert any cells
|
||||
};
|
||||
|
||||
// Define the characteristics of cell inversions
|
||||
struct MarkerTemperingConfig {
|
||||
float cellRatioToTemper; // [0,1] ratio of the cell to invert
|
||||
int numCellsToTemper; // Number of cells to invert
|
||||
MarkerRegionToTemper markerRegionToTemper; // Which cells to invert (BORDER, INNER, ALL)
|
||||
};
|
||||
|
||||
// Test configs for CV_ArucoDetectionConfidence
|
||||
struct ArucoConfidenceTestConfig {
|
||||
MarkerTemperingConfig markerTemperingConfig; // Configuration of cells to invert (percentage, number and markerRegionToTemper)
|
||||
float perspectiveRemoveIgnoredMarginPerCell; // Width of the margin of pixels on each cell not considered for the marker identification
|
||||
int markerBorderBits; // Number of bits of the marker border
|
||||
float distortionRatio; // Percentage of offset used for perspective distortion, bigger means more distorted
|
||||
};
|
||||
|
||||
enum class markerRot
|
||||
{
|
||||
NONE = 0,
|
||||
ROT_90,
|
||||
ROT_180,
|
||||
ROT_270
|
||||
};
|
||||
|
||||
struct markerDetectionGT {
|
||||
int id; // Marker identification
|
||||
double confidence; // Pixel-based confidence defined as 1 - (inverted area / total area)
|
||||
bool expectDetection; // True if we expect to detect the marker
|
||||
};
|
||||
|
||||
struct MarkerCreationConfig {
|
||||
int id; // Marker identification
|
||||
int markerSidePixels; // Marker size (in pixels)
|
||||
markerRot rotation; // Rotation of the marker in degrees (0, 90, 180, 270)
|
||||
};
|
||||
|
||||
void rotateMarker(Mat &marker, const markerRot rotation)
|
||||
{
|
||||
if(rotation == markerRot::NONE)
|
||||
return;
|
||||
|
||||
if (rotation == markerRot::ROT_90) {
|
||||
cv::transpose(marker, marker);
|
||||
cv::flip(marker, marker, 0);
|
||||
} else if (rotation == markerRot::ROT_180) {
|
||||
cv::flip(marker, marker, -1);
|
||||
} else if (rotation == markerRot::ROT_270) {
|
||||
cv::transpose(marker, marker);
|
||||
cv::flip(marker, marker, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void distortMarker(Mat &marker, const float distortionRatio)
|
||||
{
|
||||
|
||||
if (distortionRatio < FLT_EPSILON)
|
||||
return;
|
||||
|
||||
// apply a distortion (a perspective warp) to simulate a non-ideal capture
|
||||
vector<Point2f> src = { {0, 0},
|
||||
{static_cast<float>(marker.cols), 0},
|
||||
{static_cast<float>(marker.cols), static_cast<float>(marker.rows)},
|
||||
{0, static_cast<float>(marker.rows)} };
|
||||
float offset = marker.cols * distortionRatio; // distortionRatio % offset for distortion
|
||||
vector<Point2f> dst = { {offset, offset},
|
||||
{marker.cols - offset, 0},
|
||||
{marker.cols - offset, marker.rows - offset},
|
||||
{0, marker.rows - offset} };
|
||||
Mat M = getPerspectiveTransform(src, dst);
|
||||
warpPerspective(marker, marker, M, marker.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(255));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inverts a square subregion inside selected cells of a marker image to simulate confidence degradation.
|
||||
*
|
||||
* The function computes the marker grid parameters and then applies a bitwise inversion
|
||||
* on a square markerRegionToTemper inside the chosen cells. The number of cells to be inverted is determined by
|
||||
* the parameter 'numCellsToTemper'. The candidate cells can be filtered to only include border cells,
|
||||
* inner cells, or all cells according to the parameter 'markerRegionToTemper'.
|
||||
*
|
||||
* @param marker The marker image
|
||||
* @param markerSidePixels The total size of the marker in pixels (inner and border).
|
||||
* @param markerId The id of the marker
|
||||
* @param params The Aruco detector configuration (provides border bits, margin ratios, etc.).
|
||||
* @param dictionary The Aruco marker dictionary (used to determine marker grid size).
|
||||
* @param cellTempConfig Cell tempering config as defined in MarkerTemperingConfig
|
||||
* @return Cell tempering ground truth as defined in markerDetectionGT
|
||||
*/
|
||||
markerDetectionGT applyTemperingToMarkerCells(cv::Mat &marker,
|
||||
const int markerSidePixels,
|
||||
const int markerId,
|
||||
const aruco::DetectorParameters ¶ms,
|
||||
const aruco::Dictionary &dictionary,
|
||||
const MarkerTemperingConfig &cellTempConfig)
|
||||
{
|
||||
|
||||
// nothing to invert
|
||||
if(cellTempConfig.numCellsToTemper <= 0 || cellTempConfig.cellRatioToTemper <= FLT_EPSILON)
|
||||
return {markerId, 1.0, true};
|
||||
|
||||
// compute the overall grid dimensions.
|
||||
const int markerSizeWithBorders = dictionary.markerSize + 2 * params.markerBorderBits;
|
||||
const int cellSidePixelsSize = markerSidePixels / markerSizeWithBorders;
|
||||
|
||||
// compute the margin within each cell used for identification.
|
||||
const int cellMarginPixels = static_cast<int>(params.perspectiveRemoveIgnoredMarginPerCell * cellSidePixelsSize);
|
||||
const int innerCellSizePixels = cellSidePixelsSize - 2 * cellMarginPixels;
|
||||
|
||||
// determine the size of the square that will be inverted in each cell.
|
||||
// (cellSidePixelsInvert / innerCellSizePixels)^2 should equal cellRatioToTemper.
|
||||
const int cellSidePixelsInvert = min(cellSidePixelsSize, static_cast<int>(innerCellSizePixels * std::sqrt(cellTempConfig.cellRatioToTemper)));
|
||||
const int inversionOffsetPixels = (cellSidePixelsSize - cellSidePixelsInvert) / 2;
|
||||
|
||||
// nothing to invert
|
||||
if(cellSidePixelsInvert <= 0)
|
||||
return {markerId, 1.0, true};
|
||||
|
||||
int cellsTempered = 0;
|
||||
int borderErrors = 0;
|
||||
int innerCellsErrors = 0;
|
||||
// iterate over each cell in the grid.
|
||||
for (int row = 0; row < markerSizeWithBorders; row++) {
|
||||
for (int col = 0; col < markerSizeWithBorders; col++) {
|
||||
|
||||
// decide if this cell falls in the markerRegionToTemper to temper.
|
||||
const bool isBorder = (row < params.markerBorderBits ||
|
||||
col < params.markerBorderBits ||
|
||||
row >= markerSizeWithBorders - params.markerBorderBits ||
|
||||
col >= markerSizeWithBorders - params.markerBorderBits);
|
||||
|
||||
const bool inRegion = (cellTempConfig.markerRegionToTemper == MarkerRegionToTemper::ALL ||
|
||||
(isBorder && cellTempConfig.markerRegionToTemper == MarkerRegionToTemper::BORDER) ||
|
||||
(!isBorder && cellTempConfig.markerRegionToTemper == MarkerRegionToTemper::INNER));
|
||||
|
||||
// apply the inversion to simulate tempering.
|
||||
if (inRegion && (cellsTempered < cellTempConfig.numCellsToTemper)) {
|
||||
const int xStart = col * cellSidePixelsSize + inversionOffsetPixels;
|
||||
const int yStart = row * cellSidePixelsSize + inversionOffsetPixels;
|
||||
cv::Rect cellRect(xStart, yStart, cellSidePixelsInvert, cellSidePixelsInvert);
|
||||
cv::Mat cellROI = marker(cellRect);
|
||||
cv::bitwise_not(cellROI, cellROI);
|
||||
++cellsTempered;
|
||||
|
||||
// cell too tempered, no detection expected
|
||||
if(cellTempConfig.cellRatioToTemper > 0.5f) {
|
||||
if(isBorder){
|
||||
++borderErrors;
|
||||
} else {
|
||||
++innerCellsErrors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(cellsTempered >= cellTempConfig.numCellsToTemper)
|
||||
break;
|
||||
}
|
||||
|
||||
if(cellsTempered >= cellTempConfig.numCellsToTemper)
|
||||
break;
|
||||
}
|
||||
|
||||
// compute the ground-truth confidence
|
||||
const double invertedArea = cellsTempered * cellSidePixelsInvert * cellSidePixelsInvert;
|
||||
const double totalDetectionArea = markerSizeWithBorders * innerCellSizePixels * markerSizeWithBorders * innerCellSizePixels;
|
||||
const double groundTruthConfidence = std::max(0.0, 1.0 - invertedArea / totalDetectionArea);
|
||||
|
||||
// check if marker is expected to be detected
|
||||
const int maximumErrorsInBorder = static_cast<int>(dictionary.markerSize * dictionary.markerSize * params.maxErroneousBitsInBorderRate);
|
||||
const int maxCorrectionRecalculed = static_cast<int>(dictionary.maxCorrectionBits * params.errorCorrectionRate);
|
||||
const bool expectDetection = static_cast<bool>(borderErrors <= maximumErrorsInBorder && innerCellsErrors <= maxCorrectionRecalculed);
|
||||
|
||||
return {markerId, groundTruthConfidence, expectDetection};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create an image of a marker with inverted (tempered) regions to simulate detection confidence
|
||||
*
|
||||
* Applies an optional rotation and an optional perspective warp to simulate a distorted marker.
|
||||
* Inverts a square subregion inside selected cells of a marker image to simulate a drop in confidence.
|
||||
* Computes the ground-truth confidence as one minus the ratio of inverted area to the total marker area used for identification.
|
||||
*
|
||||
*/
|
||||
markerDetectionGT generateTemperedMarkerImage(Mat &marker, const MarkerCreationConfig &markerConfig, const MarkerTemperingConfig &markerTemperingConfig,
|
||||
const aruco::DetectorParameters ¶ms, const aruco::Dictionary &dictionary, const float distortionRatio = 0.f)
|
||||
{
|
||||
// generate the synthetic marker image
|
||||
aruco::generateImageMarker(dictionary, markerConfig.id, markerConfig.markerSidePixels,
|
||||
marker, params.markerBorderBits);
|
||||
|
||||
// rotate marker if necessary
|
||||
rotateMarker(marker, markerConfig.rotation);
|
||||
|
||||
// temper with cells to simulate detection confidence drops
|
||||
markerDetectionGT groundTruth = applyTemperingToMarkerCells(marker, markerConfig.markerSidePixels, markerConfig.id, params, dictionary, markerTemperingConfig);
|
||||
|
||||
// apply a distortion (a perspective warp) to simulate a non-ideal capture
|
||||
distortMarker(marker, distortionRatio);
|
||||
|
||||
return groundTruth;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Copies a marker image into a larger image at the given top-left position.
|
||||
*/
|
||||
void placeMarker(Mat &img, const Mat &marker, const Point2f &topLeft)
|
||||
{
|
||||
Rect roi(Point(static_cast<int>(topLeft.x), static_cast<int>(topLeft.y)), marker.size());
|
||||
marker.copyTo(img(roi));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Test the marker confidence computations
|
||||
*
|
||||
* Loops over a set of detector configurations (e.g. expected confidence, distortion, DetectorParameters)
|
||||
* For each configuration, it creates a synthetic image containing four markers arranged in a 2x2 grid.
|
||||
* Each marker is generated with its own configuration (id, size, rotation).
|
||||
* Finally, it runs the detector and checks that each marker is detected and
|
||||
* that its computed confidence is close to the ground truth value.
|
||||
*
|
||||
*/
|
||||
static void runArucoDetectionConfidence(ArucoAlgParams arucoAlgParam) {
|
||||
aruco::DetectorParameters params;
|
||||
// make sure there are no bits have any detection errors
|
||||
params.maxErroneousBitsInBorderRate = 0.0;
|
||||
params.errorCorrectionRate = 0.0;
|
||||
params.perspectiveRemovePixelPerCell = 8; // esnsure that there is enough resolution to properly handle distortions
|
||||
aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_6X6_250), params);
|
||||
|
||||
const bool detectInvertedMarker = (arucoAlgParam == ArucoAlgParams::DETECT_INVERTED_MARKER);
|
||||
|
||||
// define several detector configurations to test different settings
|
||||
// {{MarkerTemperingConfig}, perspectiveRemoveIgnoredMarginPerCell, markerBorderBits, distortionRatio}
|
||||
vector<ArucoConfidenceTestConfig> detectorConfigs = {
|
||||
// No margins, No distortion
|
||||
{{0.f, 64, MarkerRegionToTemper::ALL}, 0.0f, 1, 0.f},
|
||||
{{0.01f, 64, MarkerRegionToTemper::ALL}, 0.0f, 1, 0.f},
|
||||
{{0.05f, 100, MarkerRegionToTemper::ALL}, 0.0f, 2, 0.f},
|
||||
{{0.1f, 64, MarkerRegionToTemper::ALL}, 0.0f, 1, 0.f},
|
||||
{{0.15f, 30, MarkerRegionToTemper::ALL}, 0.0f, 1, 0.f},
|
||||
{{0.20f, 55, MarkerRegionToTemper::ALL}, 0.0f, 2, 0.f},
|
||||
// Margins, No distortion
|
||||
{{0.f, 26, MarkerRegionToTemper::BORDER}, 0.05f, 1, 0.f},
|
||||
{{0.01f, 56, MarkerRegionToTemper::BORDER}, 0.05f, 2, 0.f},
|
||||
{{0.05f, 144, MarkerRegionToTemper::ALL}, 0.1f, 3, 0.f},
|
||||
{{0.10f, 49, MarkerRegionToTemper::ALL}, 0.15f, 1, 0.f},
|
||||
// No margins, distortion
|
||||
{{0.f, 36, MarkerRegionToTemper::INNER}, 0.0f, 1, 0.01f},
|
||||
{{0.01f, 36, MarkerRegionToTemper::INNER}, 0.0f, 1, 0.02f},
|
||||
{{0.05f, 12, MarkerRegionToTemper::INNER}, 0.0f, 2, 0.05f},
|
||||
{{0.1f, 64, MarkerRegionToTemper::ALL}, 0.0f, 1, 0.1f},
|
||||
{{0.1f, 81, MarkerRegionToTemper::ALL}, 0.0f, 2, 0.2f},
|
||||
// Margins, distortion
|
||||
{{0.f, 81, MarkerRegionToTemper::ALL}, 0.05f, 2, 0.01f},
|
||||
{{0.01f, 64, MarkerRegionToTemper::ALL}, 0.05f, 1, 0.02f},
|
||||
{{0.05f, 81, MarkerRegionToTemper::ALL}, 0.1f, 2, 0.05f},
|
||||
{{0.1f, 64, MarkerRegionToTemper::ALL}, 0.15f, 1, 0.1f},
|
||||
{{0.1f, 64, MarkerRegionToTemper::ALL}, 0.0f, 1, 0.2f},
|
||||
// no marker detection, too much tempering
|
||||
{{0.9f, 1, MarkerRegionToTemper::ALL}, 0.05f, 2, 0.0f},
|
||||
{{0.9f, 1, MarkerRegionToTemper::BORDER}, 0.05f, 2, 0.0f},
|
||||
{{0.9f, 1, MarkerRegionToTemper::INNER}, 0.05f, 2, 0.0f},
|
||||
};
|
||||
|
||||
// define marker configurations for the 4 markers in each image
|
||||
const int markerSidePixels = 480; // To simplify the cell division, markerSidePixels is a multiple of 8. (6x6 dict + 2 border bits)
|
||||
vector<MarkerCreationConfig> markerCreationConfig = {
|
||||
{0, markerSidePixels, markerRot::ROT_90}, // {id, markerSidePixels, rotation}
|
||||
{1, markerSidePixels, markerRot::ROT_270},
|
||||
{2, markerSidePixels, markerRot::NONE},
|
||||
{3, markerSidePixels, markerRot::ROT_180}
|
||||
};
|
||||
|
||||
// loop over each detector configuration
|
||||
for (size_t cfgIdx = 0; cfgIdx < detectorConfigs.size(); cfgIdx++) {
|
||||
ArucoConfidenceTestConfig detCfg = detectorConfigs[cfgIdx];
|
||||
SCOPED_TRACE(cv::format("detectorConfig=%zu", cfgIdx));
|
||||
|
||||
// update detector parameters
|
||||
params.perspectiveRemoveIgnoredMarginPerCell = detCfg.perspectiveRemoveIgnoredMarginPerCell;
|
||||
params.markerBorderBits = detCfg.markerBorderBits;
|
||||
params.detectInvertedMarker = detectInvertedMarker;
|
||||
detector.setDetectorParameters(params);
|
||||
|
||||
// create a blank image large enough to hold 4 markers in a 2x2 grid
|
||||
const int margin = markerSidePixels / 2;
|
||||
const int imageSize = (markerSidePixels * 2) + margin * 3;
|
||||
Mat img(imageSize, imageSize, CV_8UC1, Scalar(255));
|
||||
|
||||
vector<markerDetectionGT> groundTruths;
|
||||
const aruco::Dictionary &dictionary = detector.getDictionary();
|
||||
|
||||
// place each marker into the image
|
||||
for (int row = 0; row < 2; row++) {
|
||||
for (int col = 0; col < 2; col++) {
|
||||
int index = row * 2 + col;
|
||||
MarkerCreationConfig markerCfg = markerCreationConfig[index];
|
||||
// adjust marker id to be unique for each detector configuration
|
||||
markerCfg.id += static_cast<int>(cfgIdx * markerCreationConfig.size());
|
||||
|
||||
// generate img
|
||||
Mat markerImg;
|
||||
markerDetectionGT gt = generateTemperedMarkerImage(markerImg, markerCfg, detCfg.markerTemperingConfig, params, dictionary, detCfg.distortionRatio);
|
||||
groundTruths.push_back(gt);
|
||||
|
||||
// place marker in the image
|
||||
Point2f topLeft(static_cast<float>(margin + col * (markerSidePixels + margin)),
|
||||
static_cast<float>(margin + row * (markerSidePixels + margin)));
|
||||
placeMarker(img, markerImg, topLeft);
|
||||
}
|
||||
}
|
||||
|
||||
// if testing inverted markers globally, invert the whole image
|
||||
if (detectInvertedMarker) {
|
||||
bitwise_not(img, img);
|
||||
}
|
||||
|
||||
// run detection.
|
||||
vector<vector<Point2f>> corners, rejected;
|
||||
vector<int> ids;
|
||||
vector<float> markerConfidence;
|
||||
detector.detectMarkersWithConfidence(img, corners, ids, markerConfidence, rejected);
|
||||
|
||||
ASSERT_EQ(ids.size(), corners.size());
|
||||
ASSERT_EQ(ids.size(), markerConfidence.size());
|
||||
|
||||
std::map<int, float> confidenceById;
|
||||
for (size_t i = 0; i < ids.size(); i++) {
|
||||
confidenceById[ids[i]] = markerConfidence[i];
|
||||
}
|
||||
|
||||
// verify that every marker is detected and its confidence is within tolerance
|
||||
for (const auto& currentGT : groundTruths) {
|
||||
const bool detected = confidenceById.find(currentGT.id) != confidenceById.end();
|
||||
EXPECT_EQ(currentGT.expectDetection, detected) << "Marker id: " << currentGT.id;
|
||||
|
||||
if (currentGT.expectDetection && detected) {
|
||||
EXPECT_NEAR(currentGT.confidence, confidenceById[currentGT.id], 0.05)
|
||||
<< "Marker id: " << currentGT.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check max and min size in marker detection parameters
|
||||
@@ -552,6 +904,83 @@ TEST(CV_ArucoBitCorrection, algorithmic) {
|
||||
test.safe_run();
|
||||
}
|
||||
|
||||
TEST(CV_ArucoDetectionConfidence, algorithmic) {
|
||||
runArucoDetectionConfidence(ArucoAlgParams::USE_DEFAULT);
|
||||
}
|
||||
|
||||
TEST(CV_InvertedArucoDetectionConfidence, algorithmic) {
|
||||
runArucoDetectionConfidence(ArucoAlgParams::DETECT_INVERTED_MARKER);
|
||||
}
|
||||
|
||||
TEST(CV_InvertedFlagArucoDetectionConfidence, algorithmic) {
|
||||
aruco::DetectorParameters params;
|
||||
params.maxErroneousBitsInBorderRate = 0.0;
|
||||
params.errorCorrectionRate = 0.0;
|
||||
params.perspectiveRemovePixelPerCell = 8;
|
||||
params.detectInvertedMarker = false;
|
||||
|
||||
const aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
|
||||
|
||||
// create a blank image large enough to hold 4 markers in a 2x2 grid
|
||||
const int markerSidePixels = 480;
|
||||
const int margin = markerSidePixels / 2;
|
||||
const int imageSize = (markerSidePixels * 2) + margin * 3;
|
||||
Mat img(imageSize, imageSize, CV_8UC1, Scalar(255));
|
||||
|
||||
// place 4 markers into the image
|
||||
for (int row = 0; row < 2; row++) {
|
||||
for (int col = 0; col < 2; col++) {
|
||||
const int id = row * 2 + col;
|
||||
Mat markerImg;
|
||||
aruco::generateImageMarker(dictionary, id, markerSidePixels, markerImg, params.markerBorderBits);
|
||||
|
||||
Point2f topLeft(static_cast<float>(margin + col * (markerSidePixels + margin)),
|
||||
static_cast<float>(margin + row * (markerSidePixels + margin)));
|
||||
placeMarker(img, markerImg, topLeft);
|
||||
}
|
||||
}
|
||||
|
||||
// run detection with detectInvertedMarker = false (baseline)
|
||||
aruco::ArucoDetector detector(dictionary, params);
|
||||
vector<vector<Point2f>> corners, rejected;
|
||||
vector<int> ids;
|
||||
vector<float> confidenceDefault;
|
||||
detector.detectMarkersWithConfidence(img, corners, ids, confidenceDefault, rejected);
|
||||
ASSERT_EQ(ids.size(), corners.size());
|
||||
ASSERT_EQ(ids.size(), confidenceDefault.size());
|
||||
|
||||
std::map<int, float> confidenceByIdDefault;
|
||||
for (size_t i = 0; i < ids.size(); i++) {
|
||||
confidenceByIdDefault[ids[i]] = confidenceDefault[i];
|
||||
}
|
||||
|
||||
// run detection with detectInvertedMarker = true, without inverting the image
|
||||
params.detectInvertedMarker = true;
|
||||
aruco::ArucoDetector detectorInvertedFlag(dictionary, params);
|
||||
vector<float> confidenceInvertedFlag;
|
||||
detectorInvertedFlag.detectMarkersWithConfidence(img, corners, ids, confidenceInvertedFlag, rejected);
|
||||
ASSERT_EQ(ids.size(), corners.size());
|
||||
ASSERT_EQ(ids.size(), confidenceInvertedFlag.size());
|
||||
|
||||
std::map<int, float> confidenceByIdInvertedFlag;
|
||||
for (size_t i = 0; i < ids.size(); i++) {
|
||||
confidenceByIdInvertedFlag[ids[i]] = confidenceInvertedFlag[i];
|
||||
}
|
||||
|
||||
// detectInvertedMarker should not invert/flip confidence for non-inverted markers.
|
||||
for (int id = 0; id < 4; id++) {
|
||||
ASSERT_NE(confidenceByIdDefault.find(id), confidenceByIdDefault.end()) << "Marker id: " << id;
|
||||
ASSERT_NE(confidenceByIdInvertedFlag.find(id), confidenceByIdInvertedFlag.end()) << "Marker id: " << id;
|
||||
|
||||
const float confDefault = confidenceByIdDefault[id];
|
||||
const float confInvertedFlag = confidenceByIdInvertedFlag[id];
|
||||
|
||||
EXPECT_GT(confDefault, 0.8f) << "Marker id: " << id;
|
||||
EXPECT_GT(confInvertedFlag, 0.8f) << "Marker id: " << id;
|
||||
EXPECT_NEAR(confDefault, confInvertedFlag, 0.2f) << "Marker id: " << id;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CV_ArucoDetectMarkers, regression_3192)
|
||||
{
|
||||
aruco::ArucoDetector detector(aruco::getPredefinedDictionary(aruco::DICT_4X4_50));
|
||||
|
||||
@@ -59,16 +59,17 @@ void checkImageDimensions(const std::vector<Mat>& images)
|
||||
}
|
||||
}
|
||||
|
||||
Mat triangleWeights()
|
||||
Mat triangleWeights(int length)
|
||||
{
|
||||
// hat function
|
||||
Mat w(LDR_SIZE, 1, CV_32F);
|
||||
int half = LDR_SIZE / 2;
|
||||
int maxVal = LDR_SIZE - 1;
|
||||
CV_Assert(length >= 2);
|
||||
Mat w(length, 1, CV_32F);
|
||||
int half = length / 2;
|
||||
int maxVal = length - 1;
|
||||
float epsilon = 1e-6f;
|
||||
w.at<float>(0) = epsilon;
|
||||
w.at<float>(LDR_SIZE-1) = epsilon;
|
||||
for (int i = 1; i < LDR_SIZE-1; i++){
|
||||
w.at<float>(length - 1) = epsilon;
|
||||
for (int i = 1; i < length - 1; i++){
|
||||
w.at<float>(i) = (i < half)
|
||||
? static_cast<float>(i)
|
||||
: static_cast<float>(maxVal - i);
|
||||
@@ -76,15 +77,16 @@ Mat triangleWeights()
|
||||
return w;
|
||||
}
|
||||
|
||||
Mat RobertsonWeights()
|
||||
Mat RobertsonWeights(int length)
|
||||
{
|
||||
Mat weight(LDR_SIZE, 1, CV_32FC3);
|
||||
float q = (LDR_SIZE - 1) / 4.0f;
|
||||
CV_Assert(length >= 1);
|
||||
Mat weight(length, 1, CV_32FC3);
|
||||
float q = (length - 1) / 4.0f;
|
||||
float e4 = exp(4.f);
|
||||
float scale = e4/(e4 - 1.f);
|
||||
float shift = 1 / (1.f - e4);
|
||||
|
||||
for(int i = 0; i < LDR_SIZE; i++) {
|
||||
for(int i = 0; i < length; i++) {
|
||||
float value = i / q - 2.0f;
|
||||
value = scale*exp(-value * value) + shift;
|
||||
weight.at<Vec3f>(i) = Vec3f::all(value);
|
||||
@@ -104,11 +106,28 @@ void mapLuminance(Mat src, Mat dst, Mat lum, Mat new_lum, float saturation)
|
||||
merge(channels, dst);
|
||||
}
|
||||
|
||||
Mat linearResponse(int channels)
|
||||
Mat linearResponse(int channels, int length)
|
||||
{
|
||||
Mat response = Mat(LDR_SIZE, 1, CV_MAKETYPE(CV_32F, channels));
|
||||
for(int i = 0; i < LDR_SIZE; i++) {
|
||||
response.at<Vec3f>(i) = Vec3f::all(static_cast<float>(i));
|
||||
CV_Assert(length >= 1);
|
||||
Mat response = Mat(length, 1, CV_MAKETYPE(CV_32F, channels));
|
||||
|
||||
if (channels == 1)
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
response.at<float>(i) = static_cast<float>(i);
|
||||
}
|
||||
}
|
||||
else if (channels == 3)
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
response.at<Vec3f>(i) = Vec3f::all(static_cast<float>(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Error(Error::StsBadArg, "Unsupported number of channels in linearResponse");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -50,13 +50,13 @@ namespace cv
|
||||
|
||||
void checkImageDimensions(const std::vector<Mat>& images);
|
||||
|
||||
Mat triangleWeights();
|
||||
Mat triangleWeights(int length = LDR_SIZE);
|
||||
|
||||
void mapLuminance(Mat src, Mat dst, Mat lum, Mat new_lum, float saturation);
|
||||
|
||||
Mat RobertsonWeights();
|
||||
Mat RobertsonWeights(int length = LDR_SIZE);
|
||||
|
||||
Mat linearResponse(int channels);
|
||||
Mat linearResponse(int channels, int length = LDR_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+61
-12
@@ -66,25 +66,46 @@ public:
|
||||
|
||||
CV_Assert(images.size() == times.total());
|
||||
checkImageDimensions(images);
|
||||
CV_Assert(images[0].depth() == CV_8U);
|
||||
int depth = images[0].depth();
|
||||
CV_Assert(depth == CV_8U || depth == CV_16U || depth == CV_32F);
|
||||
|
||||
int channels = images[0].channels();
|
||||
Size size = images[0].size();
|
||||
int CV_32FCC = CV_MAKETYPE(CV_32F, channels);
|
||||
|
||||
const bool use16bitLUT = (depth == CV_16U || depth == CV_32F);
|
||||
const int lutLength = use16bitLUT ? 65536 : LDR_SIZE;
|
||||
|
||||
std::vector<Mat> lutImages(images.size());
|
||||
if (depth == CV_8U || depth == CV_16U)
|
||||
{
|
||||
lutImages = images;
|
||||
}
|
||||
else
|
||||
{
|
||||
const double scale = static_cast<double>(lutLength - 1);
|
||||
for (size_t i = 0; i < images.size(); ++i)
|
||||
{
|
||||
Mat clipped;
|
||||
cv::max(images[i], 0.0, clipped);
|
||||
cv::min(clipped, 1.0, clipped);
|
||||
clipped.convertTo(lutImages[i], CV_16U, scale);
|
||||
}
|
||||
}
|
||||
|
||||
dst.create(images[0].size(), CV_32FCC);
|
||||
Mat result = dst.getMat();
|
||||
|
||||
Mat response = input_response.getMat();
|
||||
|
||||
if(response.empty()) {
|
||||
response = linearResponse(channels);
|
||||
response = linearResponse(channels, lutLength);
|
||||
response.at<Vec3f>(0) = response.at<Vec3f>(1);
|
||||
}
|
||||
|
||||
Mat log_response;
|
||||
log(response, log_response);
|
||||
CV_Assert(log_response.rows == LDR_SIZE && log_response.cols == 1 &&
|
||||
CV_Assert(log_response.rows == lutLength && log_response.cols == 1 &&
|
||||
log_response.channels() == channels);
|
||||
|
||||
Mat exp_values(times.clone());
|
||||
@@ -95,19 +116,23 @@ public:
|
||||
split(result, result_split);
|
||||
Mat weight_sum = Mat::zeros(size, CV_32F);
|
||||
|
||||
Mat weights_lut = use16bitLUT
|
||||
? triangleWeights(lutLength)
|
||||
: weights;
|
||||
|
||||
for(size_t i = 0; i < images.size(); i++) {
|
||||
std::vector<Mat> splitted;
|
||||
split(images[i], splitted);
|
||||
split(lutImages[i], splitted);
|
||||
|
||||
Mat w = Mat::zeros(size, CV_32F);
|
||||
for(int c = 0; c < channels; c++) {
|
||||
LUT(splitted[c], weights, splitted[c]);
|
||||
LUT(splitted[c], weights_lut, splitted[c]);
|
||||
w += splitted[c];
|
||||
}
|
||||
w /= channels;
|
||||
|
||||
Mat response_img;
|
||||
LUT(images[i], log_response, response_img);
|
||||
LUT(lutImages[i], log_response, response_img);
|
||||
split(response_img, splitted);
|
||||
for(int c = 0; c < channels; c++) {
|
||||
result_split[c] += w.mul(splitted[c] - exp_values.at<float>((int)i));
|
||||
@@ -328,28 +353,52 @@ public:
|
||||
|
||||
CV_Assert(images.size() == times.total());
|
||||
checkImageDimensions(images);
|
||||
CV_Assert(images[0].depth() == CV_8U);
|
||||
int depth = images[0].depth();
|
||||
CV_Assert(depth == CV_8U || depth == CV_16U || depth == CV_32F);
|
||||
|
||||
int channels = images[0].channels();
|
||||
int CV_32FCC = CV_MAKETYPE(CV_32F, channels);
|
||||
|
||||
const bool use16bitLUT = (depth == CV_16U || depth == CV_32F);
|
||||
const int lutLength = use16bitLUT ? 65536 : LDR_SIZE;
|
||||
|
||||
// Build LUT index images (see MergeDebevecImpl for details).
|
||||
std::vector<Mat> lutImages(images.size());
|
||||
if (depth == CV_8U || depth == CV_16U)
|
||||
{
|
||||
lutImages = images;
|
||||
}
|
||||
else // CV_32F
|
||||
{
|
||||
const double scale = static_cast<double>(lutLength - 1);
|
||||
for (size_t i = 0; i < images.size(); ++i)
|
||||
{
|
||||
images[i].convertTo(lutImages[i], CV_16U, scale);
|
||||
}
|
||||
}
|
||||
|
||||
dst.create(images[0].size(), CV_32FCC);
|
||||
Mat result = dst.getMat();
|
||||
|
||||
Mat response = input_response.getMat();
|
||||
if(response.empty()) {
|
||||
float middle = static_cast<float>(LDR_SIZE) / 2.0f;
|
||||
response = linearResponse(channels) / middle;
|
||||
float middle = static_cast<float>(lutLength) / 2.0f;
|
||||
response = linearResponse(channels, lutLength) / middle;
|
||||
}
|
||||
CV_Assert(response.rows == LDR_SIZE && response.cols == 1 &&
|
||||
CV_Assert(response.rows == lutLength && response.cols == 1 &&
|
||||
response.channels() == channels);
|
||||
|
||||
result = Mat::zeros(images[0].size(), CV_32FCC);
|
||||
Mat wsum = Mat::zeros(images[0].size(), CV_32FCC);
|
||||
|
||||
Mat weight_lut = use16bitLUT
|
||||
? RobertsonWeights(lutLength)
|
||||
: weight;
|
||||
|
||||
for(size_t i = 0; i < images.size(); i++) {
|
||||
Mat im, w;
|
||||
LUT(images[i], weight, w);
|
||||
LUT(images[i], response, im);
|
||||
LUT(lutImages[i], weight_lut, w);
|
||||
LUT(lutImages[i], response, im);
|
||||
|
||||
result += times.at<float>((int)i) * w.mul(im);
|
||||
wsum += times.at<float>((int)i) * times.at<float>((int)i) * w;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user