aa5326c231
Conflicts: modules/core/src/stat.cpp
1582 lines
48 KiB
C++
1582 lines
48 KiB
C++
#include "test_precomp.hpp"
|
|
|
|
using namespace cv;
|
|
using namespace std;
|
|
|
|
namespace cvtest
|
|
{
|
|
|
|
const int ARITHM_NTESTS = 1000;
|
|
const int ARITHM_RNG_SEED = -1;
|
|
const int ARITHM_MAX_CHANNELS = 4;
|
|
const int ARITHM_MAX_NDIMS = 4;
|
|
const int ARITHM_MAX_SIZE_LOG = 10;
|
|
|
|
struct BaseElemWiseOp
|
|
{
|
|
enum { FIX_ALPHA=1, FIX_BETA=2, FIX_GAMMA=4, REAL_GAMMA=8, SUPPORT_MASK=16, SCALAR_OUTPUT=32 };
|
|
BaseElemWiseOp(int _ninputs, int _flags, double _alpha, double _beta,
|
|
Scalar _gamma=Scalar::all(0), int _context=1)
|
|
: ninputs(_ninputs), flags(_flags), alpha(_alpha), beta(_beta), gamma(_gamma), context(_context) {}
|
|
BaseElemWiseOp() { flags = 0; alpha = beta = 0; gamma = Scalar::all(0); ninputs = 0; context = 1; }
|
|
virtual ~BaseElemWiseOp() {}
|
|
virtual void op(const vector<Mat>&, Mat&, const Mat&) {}
|
|
virtual void refop(const vector<Mat>&, Mat&, const Mat&) {}
|
|
virtual void getValueRange(int depth, double& minval, double& maxval)
|
|
{
|
|
minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.;
|
|
maxval = depth < CV_32S ? cvtest::getMaxVal(depth) : depth == CV_32S ? 1000000 : 1000.;
|
|
}
|
|
|
|
virtual void getRandomSize(RNG& rng, vector<int>& size)
|
|
{
|
|
cvtest::randomSize(rng, 2, ARITHM_MAX_NDIMS, cvtest::ARITHM_MAX_SIZE_LOG, size);
|
|
}
|
|
|
|
virtual int getRandomType(RNG& rng)
|
|
{
|
|
return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL_BUT_8S, 1,
|
|
ninputs > 1 ? ARITHM_MAX_CHANNELS : 4);
|
|
}
|
|
|
|
virtual double getMaxErr(int depth) { return depth < CV_32F ? 1 : depth == CV_32F ? 1e-5 : 1e-12; }
|
|
virtual void generateScalars(int depth, RNG& rng)
|
|
{
|
|
const double m = 3.;
|
|
|
|
if( !(flags & FIX_ALPHA) )
|
|
{
|
|
alpha = exp(rng.uniform(-0.5, 0.1)*m*2*CV_LOG2);
|
|
alpha *= rng.uniform(0, 2) ? 1 : -1;
|
|
}
|
|
if( !(flags & FIX_BETA) )
|
|
{
|
|
beta = exp(rng.uniform(-0.5, 0.1)*m*2*CV_LOG2);
|
|
beta *= rng.uniform(0, 2) ? 1 : -1;
|
|
}
|
|
|
|
if( !(flags & FIX_GAMMA) )
|
|
{
|
|
for( int i = 0; i < 4; i++ )
|
|
{
|
|
gamma[i] = exp(rng.uniform(-1, 6)*m*CV_LOG2);
|
|
gamma[i] *= rng.uniform(0, 2) ? 1 : -1;
|
|
}
|
|
if( flags & REAL_GAMMA )
|
|
gamma = Scalar::all(gamma[0]);
|
|
}
|
|
|
|
if( depth == CV_32F )
|
|
{
|
|
Mat fl, db;
|
|
|
|
db = Mat(1, 1, CV_64F, &alpha);
|
|
db.convertTo(fl, CV_32F);
|
|
fl.convertTo(db, CV_64F);
|
|
|
|
db = Mat(1, 1, CV_64F, &beta);
|
|
db.convertTo(fl, CV_32F);
|
|
fl.convertTo(db, CV_64F);
|
|
|
|
db = Mat(1, 4, CV_64F, &gamma[0]);
|
|
db.convertTo(fl, CV_32F);
|
|
fl.convertTo(db, CV_64F);
|
|
}
|
|
}
|
|
|
|
int ninputs;
|
|
int flags;
|
|
double alpha;
|
|
double beta;
|
|
Scalar gamma;
|
|
int context;
|
|
};
|
|
|
|
|
|
struct BaseAddOp : public BaseElemWiseOp
|
|
{
|
|
BaseAddOp(int _ninputs, int _flags, double _alpha, double _beta, Scalar _gamma=Scalar::all(0))
|
|
: BaseElemWiseOp(_ninputs, _flags, _alpha, _beta, _gamma) {}
|
|
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
Mat temp;
|
|
if( !mask.empty() )
|
|
{
|
|
cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, temp, src[0].type());
|
|
cvtest::copy(temp, dst, mask);
|
|
}
|
|
else
|
|
cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, dst, src[0].type());
|
|
}
|
|
};
|
|
|
|
|
|
struct AddOp : public BaseAddOp
|
|
{
|
|
AddOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
if( mask.empty() )
|
|
add(src[0], src[1], dst);
|
|
else
|
|
add(src[0], src[1], dst, mask);
|
|
}
|
|
};
|
|
|
|
|
|
struct SubOp : public BaseAddOp
|
|
{
|
|
SubOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, -1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
if( mask.empty() )
|
|
subtract(src[0], src[1], dst);
|
|
else
|
|
subtract(src[0], src[1], dst, mask);
|
|
}
|
|
};
|
|
|
|
|
|
struct AddSOp : public BaseAddOp
|
|
{
|
|
AddSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 0, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
if( mask.empty() )
|
|
add(src[0], gamma, dst);
|
|
else
|
|
add(src[0], gamma, dst, mask);
|
|
}
|
|
};
|
|
|
|
|
|
struct SubRSOp : public BaseAddOp
|
|
{
|
|
SubRSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, -1, 0, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
if( mask.empty() )
|
|
subtract(gamma, src[0], dst);
|
|
else
|
|
subtract(gamma, src[0], dst, mask);
|
|
}
|
|
};
|
|
|
|
|
|
struct ScaleAddOp : public BaseAddOp
|
|
{
|
|
ScaleAddOp() : BaseAddOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
scaleAdd(src[0], alpha, src[1], dst);
|
|
}
|
|
double getMaxErr(int depth)
|
|
{
|
|
return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-4 : 1e-12;
|
|
}
|
|
};
|
|
|
|
|
|
struct AddWeightedOp : public BaseAddOp
|
|
{
|
|
AddWeightedOp() : BaseAddOp(2, REAL_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
addWeighted(src[0], alpha, src[1], beta, gamma[0], dst);
|
|
}
|
|
double getMaxErr(int depth)
|
|
{
|
|
return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-10;
|
|
}
|
|
};
|
|
|
|
struct MulOp : public BaseElemWiseOp
|
|
{
|
|
MulOp() : BaseElemWiseOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void getValueRange(int depth, double& minval, double& maxval)
|
|
{
|
|
minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.;
|
|
maxval = depth < CV_32S ? cvtest::getMaxVal(depth) : depth == CV_32S ? 1000000 : 1000.;
|
|
minval = std::max(minval, -30000.);
|
|
maxval = std::min(maxval, 30000.);
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::multiply(src[0], src[1], dst, alpha);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::multiply(src[0], src[1], dst, alpha);
|
|
}
|
|
double getMaxErr(int depth)
|
|
{
|
|
return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
|
|
}
|
|
};
|
|
|
|
struct DivOp : public BaseElemWiseOp
|
|
{
|
|
DivOp() : BaseElemWiseOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::divide(src[0], src[1], dst, alpha);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::divide(src[0], src[1], dst, alpha);
|
|
}
|
|
double getMaxErr(int depth)
|
|
{
|
|
return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
|
|
}
|
|
};
|
|
|
|
struct RecipOp : public BaseElemWiseOp
|
|
{
|
|
RecipOp() : BaseElemWiseOp(1, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::divide(alpha, src[0], dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::divide(Mat(), src[0], dst, alpha);
|
|
}
|
|
double getMaxErr(int depth)
|
|
{
|
|
return depth <= CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12;
|
|
}
|
|
};
|
|
|
|
struct AbsDiffOp : public BaseAddOp
|
|
{
|
|
AbsDiffOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, -1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
absdiff(src[0], src[1], dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::add(src[0], 1, src[1], -1, Scalar::all(0), dst, src[0].type(), true);
|
|
}
|
|
};
|
|
|
|
struct AbsDiffSOp : public BaseAddOp
|
|
{
|
|
AbsDiffSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA, 1, 0, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
absdiff(src[0], gamma, dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::add(src[0], 1, Mat(), 0, -gamma, dst, src[0].type(), true);
|
|
}
|
|
};
|
|
|
|
struct LogicOp : public BaseElemWiseOp
|
|
{
|
|
LogicOp(char _opcode) : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)), opcode(_opcode) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
if( opcode == '&' )
|
|
bitwise_and(src[0], src[1], dst, mask);
|
|
else if( opcode == '|' )
|
|
bitwise_or(src[0], src[1], dst, mask);
|
|
else
|
|
bitwise_xor(src[0], src[1], dst, mask);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
Mat temp;
|
|
if( !mask.empty() )
|
|
{
|
|
cvtest::logicOp(src[0], src[1], temp, opcode);
|
|
cvtest::copy(temp, dst, mask);
|
|
}
|
|
else
|
|
cvtest::logicOp(src[0], src[1], dst, opcode);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
char opcode;
|
|
};
|
|
|
|
struct LogicSOp : public BaseElemWiseOp
|
|
{
|
|
LogicSOp(char _opcode)
|
|
: BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+(_opcode != '~' ? SUPPORT_MASK : 0), 1, 1, Scalar::all(0)), opcode(_opcode) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
if( opcode == '&' )
|
|
bitwise_and(src[0], gamma, dst, mask);
|
|
else if( opcode == '|' )
|
|
bitwise_or(src[0], gamma, dst, mask);
|
|
else if( opcode == '^' )
|
|
bitwise_xor(src[0], gamma, dst, mask);
|
|
else
|
|
bitwise_not(src[0], dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
Mat temp;
|
|
if( !mask.empty() )
|
|
{
|
|
cvtest::logicOp(src[0], gamma, temp, opcode);
|
|
cvtest::copy(temp, dst, mask);
|
|
}
|
|
else
|
|
cvtest::logicOp(src[0], gamma, dst, opcode);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
char opcode;
|
|
};
|
|
|
|
struct MinOp : public BaseElemWiseOp
|
|
{
|
|
MinOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::min(src[0], src[1], dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::min(src[0], src[1], dst);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
struct MaxOp : public BaseElemWiseOp
|
|
{
|
|
MaxOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::max(src[0], src[1], dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::max(src[0], src[1], dst);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
struct MinSOp : public BaseElemWiseOp
|
|
{
|
|
MinSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::min(src[0], gamma[0], dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::min(src[0], gamma[0], dst);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
struct MaxSOp : public BaseElemWiseOp
|
|
{
|
|
MaxSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::max(src[0], gamma[0], dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::max(src[0], gamma[0], dst);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
struct CmpOp : public BaseElemWiseOp
|
|
{
|
|
CmpOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) { cmpop = 0; }
|
|
void generateScalars(int depth, RNG& rng)
|
|
{
|
|
BaseElemWiseOp::generateScalars(depth, rng);
|
|
cmpop = rng.uniform(0, 6);
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::compare(src[0], src[1], dst, cmpop);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::compare(src[0], src[1], dst, cmpop);
|
|
}
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL_BUT_8S, 1, 1);
|
|
}
|
|
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
int cmpop;
|
|
};
|
|
|
|
struct CmpSOp : public BaseElemWiseOp
|
|
{
|
|
CmpSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) { cmpop = 0; }
|
|
void generateScalars(int depth, RNG& rng)
|
|
{
|
|
BaseElemWiseOp::generateScalars(depth, rng);
|
|
cmpop = rng.uniform(0, 6);
|
|
if( depth < CV_32F )
|
|
gamma[0] = cvRound(gamma[0]);
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::compare(src[0], gamma[0], dst, cmpop);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::compare(src[0], gamma[0], dst, cmpop);
|
|
}
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL_BUT_8S, 1, 1);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
int cmpop;
|
|
};
|
|
|
|
|
|
struct CopyOp : public BaseElemWiseOp
|
|
{
|
|
CopyOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) { }
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
src[0].copyTo(dst, mask);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
cvtest::copy(src[0], dst, mask);
|
|
}
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
|
|
struct SetOp : public BaseElemWiseOp
|
|
{
|
|
SetOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>&, Mat& dst, const Mat& mask)
|
|
{
|
|
dst.setTo(gamma, mask);
|
|
}
|
|
void refop(const vector<Mat>&, Mat& dst, const Mat& mask)
|
|
{
|
|
cvtest::set(dst, gamma, mask);
|
|
}
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
template<typename _Tp, typename _WTp> static void
|
|
inRangeS_(const _Tp* src, const _WTp* a, const _WTp* b, uchar* dst, size_t total, int cn)
|
|
{
|
|
size_t i;
|
|
int c;
|
|
for( i = 0; i < total; i++ )
|
|
{
|
|
_Tp val = src[i*cn];
|
|
dst[i] = (a[0] <= val && val <= b[0]) ? uchar(255) : 0;
|
|
}
|
|
for( c = 1; c < cn; c++ )
|
|
{
|
|
for( i = 0; i < total; i++ )
|
|
{
|
|
_Tp val = src[i*cn + c];
|
|
dst[i] = a[c] <= val && val <= b[c] ? dst[i] : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename _Tp> static void inRange_(const _Tp* src, const _Tp* a, const _Tp* b, uchar* dst, size_t total, int cn)
|
|
{
|
|
size_t i;
|
|
int c;
|
|
for( i = 0; i < total; i++ )
|
|
{
|
|
_Tp val = src[i*cn];
|
|
dst[i] = a[i*cn] <= val && val <= b[i*cn] ? 255 : 0;
|
|
}
|
|
for( c = 1; c < cn; c++ )
|
|
{
|
|
for( i = 0; i < total; i++ )
|
|
{
|
|
_Tp val = src[i*cn + c];
|
|
dst[i] = a[i*cn + c] <= val && val <= b[i*cn + c] ? dst[i] : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void inRange(const Mat& src, const Mat& lb, const Mat& rb, Mat& dst)
|
|
{
|
|
CV_Assert( src.type() == lb.type() && src.type() == rb.type() &&
|
|
src.size == lb.size && src.size == rb.size );
|
|
dst.create( src.dims, &src.size[0], CV_8U );
|
|
const Mat *arrays[]={&src, &lb, &rb, &dst, 0};
|
|
Mat planes[4];
|
|
|
|
NAryMatIterator it(arrays, planes);
|
|
size_t total = planes[0].total();
|
|
size_t i, nplanes = it.nplanes;
|
|
int depth = src.depth(), cn = src.channels();
|
|
|
|
for( i = 0; i < nplanes; i++, ++it )
|
|
{
|
|
const uchar* sptr = planes[0].data;
|
|
const uchar* aptr = planes[1].data;
|
|
const uchar* bptr = planes[2].data;
|
|
uchar* dptr = planes[3].data;
|
|
|
|
switch( depth )
|
|
{
|
|
case CV_8U:
|
|
inRange_((const uchar*)sptr, (const uchar*)aptr, (const uchar*)bptr, dptr, total, cn);
|
|
break;
|
|
case CV_8S:
|
|
inRange_((const schar*)sptr, (const schar*)aptr, (const schar*)bptr, dptr, total, cn);
|
|
break;
|
|
case CV_16U:
|
|
inRange_((const ushort*)sptr, (const ushort*)aptr, (const ushort*)bptr, dptr, total, cn);
|
|
break;
|
|
case CV_16S:
|
|
inRange_((const short*)sptr, (const short*)aptr, (const short*)bptr, dptr, total, cn);
|
|
break;
|
|
case CV_32S:
|
|
inRange_((const int*)sptr, (const int*)aptr, (const int*)bptr, dptr, total, cn);
|
|
break;
|
|
case CV_32F:
|
|
inRange_((const float*)sptr, (const float*)aptr, (const float*)bptr, dptr, total, cn);
|
|
break;
|
|
case CV_64F:
|
|
inRange_((const double*)sptr, (const double*)aptr, (const double*)bptr, dptr, total, cn);
|
|
break;
|
|
default:
|
|
CV_Error(CV_StsUnsupportedFormat, "");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void inRangeS(const Mat& src, const Scalar& lb, const Scalar& rb, Mat& dst)
|
|
{
|
|
dst.create( src.dims, &src.size[0], CV_8U );
|
|
const Mat *arrays[]={&src, &dst, 0};
|
|
Mat planes[2];
|
|
|
|
NAryMatIterator it(arrays, planes);
|
|
size_t total = planes[0].total();
|
|
size_t i, nplanes = it.nplanes;
|
|
int depth = src.depth(), cn = src.channels();
|
|
union { double d[4]; float f[4]; int i[4];} lbuf, rbuf;
|
|
int wtype = CV_MAKETYPE(depth <= CV_32S ? CV_32S : depth, cn);
|
|
scalarToRawData(lb, lbuf.d, wtype, cn);
|
|
scalarToRawData(rb, rbuf.d, wtype, cn);
|
|
|
|
for( i = 0; i < nplanes; i++, ++it )
|
|
{
|
|
const uchar* sptr = planes[0].data;
|
|
uchar* dptr = planes[1].data;
|
|
|
|
switch( depth )
|
|
{
|
|
case CV_8U:
|
|
inRangeS_((const uchar*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
|
|
break;
|
|
case CV_8S:
|
|
inRangeS_((const schar*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
|
|
break;
|
|
case CV_16U:
|
|
inRangeS_((const ushort*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
|
|
break;
|
|
case CV_16S:
|
|
inRangeS_((const short*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
|
|
break;
|
|
case CV_32S:
|
|
inRangeS_((const int*)sptr, lbuf.i, rbuf.i, dptr, total, cn);
|
|
break;
|
|
case CV_32F:
|
|
inRangeS_((const float*)sptr, lbuf.f, rbuf.f, dptr, total, cn);
|
|
break;
|
|
case CV_64F:
|
|
inRangeS_((const double*)sptr, lbuf.d, rbuf.d, dptr, total, cn);
|
|
break;
|
|
default:
|
|
CV_Error(CV_StsUnsupportedFormat, "");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
struct InRangeSOp : public BaseElemWiseOp
|
|
{
|
|
InRangeSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::inRange(src[0], gamma, gamma1, dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::inRangeS(src[0], gamma, gamma1, dst);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
void generateScalars(int depth, RNG& rng)
|
|
{
|
|
BaseElemWiseOp::generateScalars(depth, rng);
|
|
Scalar temp = gamma;
|
|
BaseElemWiseOp::generateScalars(depth, rng);
|
|
for( int i = 0; i < 4; i++ )
|
|
{
|
|
gamma1[i] = std::max(gamma[i], temp[i]);
|
|
gamma[i] = std::min(gamma[i], temp[i]);
|
|
}
|
|
}
|
|
Scalar gamma1;
|
|
};
|
|
|
|
|
|
struct InRangeOp : public BaseElemWiseOp
|
|
{
|
|
InRangeOp() : BaseElemWiseOp(3, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
Mat lb, rb;
|
|
cvtest::min(src[1], src[2], lb);
|
|
cvtest::max(src[1], src[2], rb);
|
|
|
|
cv::inRange(src[0], lb, rb, dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
Mat lb, rb;
|
|
cvtest::min(src[1], src[2], lb);
|
|
cvtest::max(src[1], src[2], rb);
|
|
|
|
cvtest::inRange(src[0], lb, rb, dst);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
|
|
struct ConvertScaleOp : public BaseElemWiseOp
|
|
{
|
|
ConvertScaleOp() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)), ddepth(0) { }
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
src[0].convertTo(dst, ddepth, alpha, gamma[0]);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::convert(src[0], dst, CV_MAKETYPE(ddepth, src[0].channels()), alpha, gamma[0]);
|
|
}
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
int srctype = cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
|
|
ddepth = cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1, 1);
|
|
return srctype;
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return ddepth <= CV_32S ? 2 : ddepth < CV_64F ? 1e-3 : 1e-12;
|
|
}
|
|
void generateScalars(int depth, RNG& rng)
|
|
{
|
|
if( rng.uniform(0, 2) )
|
|
BaseElemWiseOp::generateScalars(depth, rng);
|
|
else
|
|
{
|
|
alpha = 1;
|
|
gamma = Scalar::all(0);
|
|
}
|
|
}
|
|
int ddepth;
|
|
};
|
|
|
|
|
|
struct ConvertScaleAbsOp : public BaseElemWiseOp
|
|
{
|
|
ConvertScaleAbsOp() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::convertScaleAbs(src[0], dst, alpha, gamma[0]);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::add(src[0], alpha, Mat(), 0, Scalar::all(gamma[0]), dst, CV_8UC(src[0].channels()), true);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 1;
|
|
}
|
|
void generateScalars(int depth, RNG& rng)
|
|
{
|
|
if( rng.uniform(0, 2) )
|
|
BaseElemWiseOp::generateScalars(depth, rng);
|
|
else
|
|
{
|
|
alpha = 1;
|
|
gamma = Scalar::all(0);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
static void flip(const Mat& src, Mat& dst, int flipcode)
|
|
{
|
|
CV_Assert(src.dims == 2);
|
|
dst.create(src.size(), src.type());
|
|
int i, j, k, esz = (int)src.elemSize(), width = src.cols*esz;
|
|
|
|
for( i = 0; i < dst.rows; i++ )
|
|
{
|
|
const uchar* sptr = src.ptr(flipcode == 1 ? i : dst.rows - i - 1);
|
|
uchar* dptr = dst.ptr(i);
|
|
if( flipcode == 0 )
|
|
memcpy(dptr, sptr, width);
|
|
else
|
|
{
|
|
for( j = 0; j < width; j += esz )
|
|
for( k = 0; k < esz; k++ )
|
|
dptr[j + k] = sptr[width - j - esz + k];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void setIdentity(Mat& dst, const Scalar& s)
|
|
{
|
|
CV_Assert( dst.dims == 2 && dst.channels() <= 4 );
|
|
double buf[4];
|
|
scalarToRawData(s, buf, dst.type(), 0);
|
|
int i, k, esz = (int)dst.elemSize(), width = dst.cols*esz;
|
|
|
|
for( i = 0; i < dst.rows; i++ )
|
|
{
|
|
uchar* dptr = dst.ptr(i);
|
|
memset( dptr, 0, width );
|
|
if( i < dst.cols )
|
|
for( k = 0; k < esz; k++ )
|
|
dptr[i*esz + k] = ((uchar*)buf)[k];
|
|
}
|
|
}
|
|
|
|
|
|
struct FlipOp : public BaseElemWiseOp
|
|
{
|
|
FlipOp() : 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, cvtest::ARITHM_MAX_SIZE_LOG, size);
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::flip(src[0], dst, flipcode);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::flip(src[0], dst, flipcode);
|
|
}
|
|
void generateScalars(int, RNG& rng)
|
|
{
|
|
flipcode = rng.uniform(0, 3) - 1;
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
int flipcode;
|
|
};
|
|
|
|
struct TransposeOp : public BaseElemWiseOp
|
|
{
|
|
TransposeOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void getRandomSize(RNG& rng, vector<int>& size)
|
|
{
|
|
cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size);
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::transpose(src[0], dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::transpose(src[0], dst);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
struct SetIdentityOp : public BaseElemWiseOp
|
|
{
|
|
SetIdentityOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA, 1, 1, Scalar::all(0)) {}
|
|
void getRandomSize(RNG& rng, vector<int>& size)
|
|
{
|
|
cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size);
|
|
}
|
|
void op(const vector<Mat>&, Mat& dst, const Mat&)
|
|
{
|
|
cv::setIdentity(dst, gamma);
|
|
}
|
|
void refop(const vector<Mat>&, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::setIdentity(dst, gamma);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
struct SetZeroOp : public BaseElemWiseOp
|
|
{
|
|
SetZeroOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
void op(const vector<Mat>&, Mat& dst, const Mat&)
|
|
{
|
|
dst = Scalar::all(0);
|
|
}
|
|
void refop(const vector<Mat>&, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::set(dst, Scalar::all(0));
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
|
|
static void exp(const Mat& src, Mat& dst)
|
|
{
|
|
dst.create( src.dims, &src.size[0], src.type() );
|
|
const Mat *arrays[]={&src, &dst, 0};
|
|
Mat planes[2];
|
|
|
|
NAryMatIterator it(arrays, planes);
|
|
size_t j, total = planes[0].total()*src.channels();
|
|
size_t i, nplanes = it.nplanes;
|
|
int depth = src.depth();
|
|
|
|
for( i = 0; i < nplanes; i++, ++it )
|
|
{
|
|
const uchar* sptr = planes[0].data;
|
|
uchar* dptr = planes[1].data;
|
|
|
|
if( depth == CV_32F )
|
|
{
|
|
for( j = 0; j < total; j++ )
|
|
((float*)dptr)[j] = std::exp(((const float*)sptr)[j]);
|
|
}
|
|
else if( depth == CV_64F )
|
|
{
|
|
for( j = 0; j < total; j++ )
|
|
((double*)dptr)[j] = std::exp(((const double*)sptr)[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void log(const Mat& src, Mat& dst)
|
|
{
|
|
dst.create( src.dims, &src.size[0], src.type() );
|
|
const Mat *arrays[]={&src, &dst, 0};
|
|
Mat planes[2];
|
|
|
|
NAryMatIterator it(arrays, planes);
|
|
size_t j, total = planes[0].total()*src.channels();
|
|
size_t i, nplanes = it.nplanes;
|
|
int depth = src.depth();
|
|
|
|
for( i = 0; i < nplanes; i++, ++it )
|
|
{
|
|
const uchar* sptr = planes[0].data;
|
|
uchar* dptr = planes[1].data;
|
|
|
|
if( depth == CV_32F )
|
|
{
|
|
for( j = 0; j < total; j++ )
|
|
((float*)dptr)[j] = (float)std::log(fabs(((const float*)sptr)[j]));
|
|
}
|
|
else if( depth == CV_64F )
|
|
{
|
|
for( j = 0; j < total; j++ )
|
|
((double*)dptr)[j] = std::log(fabs(((const double*)sptr)[j]));
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ExpOp : public BaseElemWiseOp
|
|
{
|
|
ExpOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_FLT, 1, ARITHM_MAX_CHANNELS);
|
|
}
|
|
void getValueRange(int depth, double& minval, double& maxval)
|
|
{
|
|
maxval = depth == CV_32F ? 50 : 100;
|
|
minval = -maxval;
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cv::exp(src[0], dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
cvtest::exp(src[0], dst);
|
|
}
|
|
double getMaxErr(int depth)
|
|
{
|
|
return depth == CV_32F ? 1e-5 : 1e-12;
|
|
}
|
|
};
|
|
|
|
|
|
struct LogOp : public BaseElemWiseOp
|
|
{
|
|
LogOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {}
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_FLT, 1, ARITHM_MAX_CHANNELS);
|
|
}
|
|
void getValueRange(int depth, double& minval, double& maxval)
|
|
{
|
|
maxval = depth == CV_32F ? 50 : 100;
|
|
minval = -maxval;
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
Mat temp;
|
|
cvtest::exp(src[0], temp);
|
|
cv::log(temp, dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
Mat temp;
|
|
cvtest::exp(src[0], temp);
|
|
cvtest::log(temp, dst);
|
|
}
|
|
double getMaxErr(int depth)
|
|
{
|
|
return depth == CV_32F ? 1e-5 : 1e-12;
|
|
}
|
|
};
|
|
|
|
|
|
static void cartToPolar(const Mat& mx, const Mat& my, Mat& mmag, Mat& mangle, bool angleInDegrees)
|
|
{
|
|
CV_Assert( (mx.type() == CV_32F || mx.type() == CV_64F) &&
|
|
mx.type() == my.type() && mx.size == my.size );
|
|
mmag.create( mx.dims, &mx.size[0], mx.type() );
|
|
mangle.create( mx.dims, &mx.size[0], mx.type() );
|
|
const Mat *arrays[]={&mx, &my, &mmag, &mangle, 0};
|
|
Mat planes[4];
|
|
|
|
NAryMatIterator it(arrays, planes);
|
|
size_t j, total = planes[0].total();
|
|
size_t i, nplanes = it.nplanes;
|
|
int depth = mx.depth();
|
|
double scale = angleInDegrees ? 180/CV_PI : 1;
|
|
|
|
for( i = 0; i < nplanes; i++, ++it )
|
|
{
|
|
if( depth == CV_32F )
|
|
{
|
|
const float* xptr = (const float*)planes[0].data;
|
|
const float* yptr = (const float*)planes[1].data;
|
|
float* mptr = (float*)planes[2].data;
|
|
float* aptr = (float*)planes[3].data;
|
|
|
|
for( j = 0; j < total; j++ )
|
|
{
|
|
mptr[j] = std::sqrt(xptr[j]*xptr[j] + yptr[j]*yptr[j]);
|
|
double a = atan2((double)yptr[j], (double)xptr[j]);
|
|
if( a < 0 ) a += CV_PI*2;
|
|
aptr[j] = (float)(a*scale);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const double* xptr = (const double*)planes[0].data;
|
|
const double* yptr = (const double*)planes[1].data;
|
|
double* mptr = (double*)planes[2].data;
|
|
double* aptr = (double*)planes[3].data;
|
|
|
|
for( j = 0; j < total; j++ )
|
|
{
|
|
mptr[j] = std::sqrt(xptr[j]*xptr[j] + yptr[j]*yptr[j]);
|
|
double a = atan2(yptr[j], xptr[j]);
|
|
if( a < 0 ) a += CV_PI*2;
|
|
aptr[j] = a*scale;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
struct CartToPolarToCartOp : public BaseElemWiseOp
|
|
{
|
|
CartToPolarToCartOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0))
|
|
{
|
|
context = 3;
|
|
angleInDegrees = true;
|
|
}
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_FLT, 1, 1);
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
Mat mag, angle, x, y;
|
|
|
|
cv::cartToPolar(src[0], src[1], mag, angle, angleInDegrees);
|
|
cv::polarToCart(mag, angle, x, y, angleInDegrees);
|
|
|
|
Mat msrc[] = {mag, angle, x, y};
|
|
int pairs[] = {0, 0, 1, 1, 2, 2, 3, 3};
|
|
dst.create(src[0].dims, src[0].size, CV_MAKETYPE(src[0].depth(), 4));
|
|
cv::mixChannels(msrc, 4, &dst, 1, pairs, 4);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
Mat mag, angle;
|
|
cvtest::cartToPolar(src[0], src[1], mag, angle, angleInDegrees);
|
|
Mat msrc[] = {mag, angle, src[0], src[1]};
|
|
int pairs[] = {0, 0, 1, 1, 2, 2, 3, 3};
|
|
dst.create(src[0].dims, src[0].size, CV_MAKETYPE(src[0].depth(), 4));
|
|
cv::mixChannels(msrc, 4, &dst, 1, pairs, 4);
|
|
}
|
|
void generateScalars(int, RNG& rng)
|
|
{
|
|
angleInDegrees = rng.uniform(0, 2) != 0;
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 1e-3;
|
|
}
|
|
bool angleInDegrees;
|
|
};
|
|
|
|
|
|
struct MeanOp : public BaseElemWiseOp
|
|
{
|
|
MeanOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
|
|
{
|
|
context = 3;
|
|
};
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
dst.create(1, 1, CV_64FC4);
|
|
dst.at<Scalar>(0,0) = cv::mean(src[0], mask);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
dst.create(1, 1, CV_64FC4);
|
|
dst.at<Scalar>(0,0) = cvtest::mean(src[0], mask);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 1e-5;
|
|
}
|
|
};
|
|
|
|
|
|
struct SumOp : public BaseElemWiseOp
|
|
{
|
|
SumOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
|
|
{
|
|
context = 3;
|
|
};
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
dst.create(1, 1, CV_64FC4);
|
|
dst.at<Scalar>(0,0) = cv::sum(src[0]);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat&)
|
|
{
|
|
dst.create(1, 1, CV_64FC4);
|
|
dst.at<Scalar>(0,0) = cvtest::mean(src[0])*(double)src[0].total();
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 1e-5;
|
|
}
|
|
};
|
|
|
|
|
|
struct CountNonZeroOp : public BaseElemWiseOp
|
|
{
|
|
CountNonZeroOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SCALAR_OUTPUT+SUPPORT_MASK, 1, 1, Scalar::all(0))
|
|
{}
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL, 1, 1);
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
Mat temp;
|
|
src[0].copyTo(temp);
|
|
if( !mask.empty() )
|
|
temp.setTo(Scalar::all(0), mask);
|
|
dst.create(1, 1, CV_32S);
|
|
dst.at<int>(0,0) = cv::countNonZero(temp);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
Mat temp;
|
|
cvtest::compare(src[0], 0, temp, CMP_NE);
|
|
if( !mask.empty() )
|
|
cvtest::set(temp, Scalar::all(0), mask);
|
|
dst.create(1, 1, CV_32S);
|
|
dst.at<int>(0,0) = saturate_cast<int>(cvtest::mean(temp)[0]/255*temp.total());
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
|
|
struct MeanStdDevOp : public BaseElemWiseOp
|
|
{
|
|
Scalar sqmeanRef;
|
|
int cn;
|
|
|
|
MeanStdDevOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
|
|
{
|
|
cn = 0;
|
|
context = 7;
|
|
};
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
dst.create(1, 2, CV_64FC4);
|
|
cv::meanStdDev(src[0], dst.at<Scalar>(0,0), dst.at<Scalar>(0,1), mask);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
Mat temp;
|
|
cvtest::convert(src[0], temp, CV_64F);
|
|
cvtest::multiply(temp, temp, temp);
|
|
Scalar mean = cvtest::mean(src[0], mask);
|
|
Scalar sqmean = cvtest::mean(temp, mask);
|
|
|
|
sqmeanRef = sqmean;
|
|
cn = temp.channels();
|
|
|
|
for( int c = 0; c < 4; c++ )
|
|
sqmean[c] = std::sqrt(std::max(sqmean[c] - mean[c]*mean[c], 0.));
|
|
|
|
dst.create(1, 2, CV_64FC4);
|
|
dst.at<Scalar>(0,0) = mean;
|
|
dst.at<Scalar>(0,1) = sqmean;
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
CV_Assert(cn > 0);
|
|
double err = sqmeanRef[0];
|
|
for(int i = 1; i < cn; ++i)
|
|
err = std::max(err, sqmeanRef[i]);
|
|
return 3e-7 * err;
|
|
}
|
|
};
|
|
|
|
|
|
struct NormOp : public BaseElemWiseOp
|
|
{
|
|
NormOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
|
|
{
|
|
context = 1;
|
|
normType = 0;
|
|
};
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
int type = cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL_BUT_8S, 1, 4);
|
|
for(;;)
|
|
{
|
|
normType = rng.uniform(1, 8);
|
|
if( normType == NORM_INF || normType == NORM_L1 ||
|
|
normType == NORM_L2 || normType == NORM_L2SQR ||
|
|
normType == NORM_HAMMING || normType == NORM_HAMMING2 )
|
|
break;
|
|
}
|
|
if( normType == NORM_HAMMING || normType == NORM_HAMMING2 )
|
|
{
|
|
type = CV_8U;
|
|
}
|
|
return type;
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
dst.create(1, 2, CV_64FC1);
|
|
dst.at<double>(0,0) = cv::norm(src[0], normType, mask);
|
|
dst.at<double>(0,1) = cv::norm(src[0], src[1], normType, mask);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
dst.create(1, 2, CV_64FC1);
|
|
dst.at<double>(0,0) = cvtest::norm(src[0], normType, mask);
|
|
dst.at<double>(0,1) = cvtest::norm(src[0], src[1], normType, mask);
|
|
}
|
|
void generateScalars(int, RNG& /*rng*/)
|
|
{
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 1e-6;
|
|
}
|
|
int normType;
|
|
};
|
|
|
|
|
|
struct MinMaxLocOp : public BaseElemWiseOp
|
|
{
|
|
MinMaxLocOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
|
|
{
|
|
context = ARITHM_MAX_NDIMS*2 + 2;
|
|
};
|
|
int getRandomType(RNG& rng)
|
|
{
|
|
return cvtest::randomType(rng, _OutputArray::DEPTH_MASK_ALL_BUT_8S, 1, 1);
|
|
}
|
|
void saveOutput(const vector<int>& minidx, const vector<int>& maxidx,
|
|
double minval, double maxval, Mat& dst)
|
|
{
|
|
int i, ndims = (int)minidx.size();
|
|
dst.create(1, ndims*2 + 2, CV_64FC1);
|
|
|
|
for( i = 0; i < ndims; i++ )
|
|
{
|
|
dst.at<double>(0,i) = minidx[i];
|
|
dst.at<double>(0,i+ndims) = maxidx[i];
|
|
}
|
|
dst.at<double>(0,ndims*2) = minval;
|
|
dst.at<double>(0,ndims*2+1) = maxval;
|
|
}
|
|
void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
int ndims = src[0].dims;
|
|
vector<int> minidx(ndims), maxidx(ndims);
|
|
double minval=0, maxval=0;
|
|
cv::minMaxIdx(src[0], &minval, &maxval, &minidx[0], &maxidx[0], mask);
|
|
saveOutput(minidx, maxidx, minval, maxval, dst);
|
|
}
|
|
void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
|
|
{
|
|
int ndims=src[0].dims;
|
|
vector<int> minidx(ndims), maxidx(ndims);
|
|
double minval=0, maxval=0;
|
|
cvtest::minMaxLoc(src[0], &minval, &maxval, &minidx, &maxidx, mask);
|
|
saveOutput(minidx, maxidx, minval, maxval, dst);
|
|
}
|
|
double getMaxErr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
|
|
}
|
|
|
|
typedef Ptr<cvtest::BaseElemWiseOp> ElemWiseOpPtr;
|
|
class ElemWiseTest : public ::testing::TestWithParam<ElemWiseOpPtr> {};
|
|
|
|
TEST_P(ElemWiseTest, accuracy)
|
|
{
|
|
ElemWiseOpPtr op = GetParam();
|
|
|
|
int testIdx = 0;
|
|
RNG rng((uint64)cvtest::ARITHM_RNG_SEED);
|
|
for( testIdx = 0; testIdx < cvtest::ARITHM_NTESTS; testIdx++ )
|
|
{
|
|
vector<int> size;
|
|
op->getRandomSize(rng, size);
|
|
int type = op->getRandomType(rng);
|
|
int depth = CV_MAT_DEPTH(type);
|
|
bool haveMask = (op->flags & cvtest::BaseElemWiseOp::SUPPORT_MASK) != 0 && rng.uniform(0, 4) == 0;
|
|
|
|
double minval=0, maxval=0;
|
|
op->getValueRange(depth, minval, maxval);
|
|
int i, ninputs = op->ninputs;
|
|
vector<Mat> src(ninputs);
|
|
for( i = 0; i < ninputs; i++ )
|
|
src[i] = cvtest::randomMat(rng, size, type, minval, maxval, true);
|
|
Mat dst0, dst, mask;
|
|
if( haveMask )
|
|
mask = cvtest::randomMat(rng, size, CV_8U, 0, 2, true);
|
|
|
|
if( (haveMask || ninputs == 0) && !(op->flags & cvtest::BaseElemWiseOp::SCALAR_OUTPUT))
|
|
{
|
|
dst0 = cvtest::randomMat(rng, size, type, minval, maxval, false);
|
|
dst = cvtest::randomMat(rng, size, type, minval, maxval, true);
|
|
cvtest::copy(dst, dst0);
|
|
}
|
|
op->generateScalars(depth, rng);
|
|
|
|
op->refop(src, dst0, mask);
|
|
op->op(src, dst, mask);
|
|
|
|
double maxErr = op->getMaxErr(depth);
|
|
vector<int> pos;
|
|
ASSERT_PRED_FORMAT2(cvtest::MatComparator(maxErr, op->context), dst0, dst) << "\nsrc[0] ~ " <<
|
|
cvtest::MatInfo(!src.empty() ? src[0] : Mat()) << "\ntestCase #" << testIdx << "\n";
|
|
}
|
|
}
|
|
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_Copy, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CopyOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_Set, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_SetZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetZeroOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_ConvertScale, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_ConvertScaleAbs, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleAbsOp)));
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_Add, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_Sub, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SubOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_AddS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddSOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_SubRS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SubRSOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_ScaleAdd, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ScaleAddOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_AddWeighted, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddWeightedOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_AbsDiff, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AbsDiffOp)));
|
|
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_AbsDiffS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AbsDiffSOp)));
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_And, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('&'))));
|
|
INSTANTIATE_TEST_CASE_P(Core_AndS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('&'))));
|
|
INSTANTIATE_TEST_CASE_P(Core_Or, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('|'))));
|
|
INSTANTIATE_TEST_CASE_P(Core_OrS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('|'))));
|
|
INSTANTIATE_TEST_CASE_P(Core_Xor, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('^'))));
|
|
INSTANTIATE_TEST_CASE_P(Core_XorS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('^'))));
|
|
INSTANTIATE_TEST_CASE_P(Core_Not, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('~'))));
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_Max, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MaxOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_MaxS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MaxSOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_Min, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_MinS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinSOp)));
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_Mul, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MulOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_Div, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::DivOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_Recip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::RecipOp)));
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_Cmp, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CmpOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_CmpS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CmpSOp)));
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_InRangeS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::InRangeSOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_InRange, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::InRangeOp)));
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_Flip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::FlipOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_Transpose, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::TransposeOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_SetIdentity, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetIdentityOp)));
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_Exp, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ExpOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_Log, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogOp)));
|
|
|
|
INSTANTIATE_TEST_CASE_P(Core_CountNonZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CountNonZeroOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_Mean, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MeanOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_MeanStdDev, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MeanStdDevOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_Sum, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SumOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_Norm, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::NormOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_MinMaxLoc, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinMaxLocOp)));
|
|
INSTANTIATE_TEST_CASE_P(Core_CartToPolarToCart, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CartToPolarToCartOp)));
|
|
|
|
|
|
class CV_ArithmMaskTest : public cvtest::BaseTest
|
|
{
|
|
public:
|
|
CV_ArithmMaskTest() {}
|
|
~CV_ArithmMaskTest() {}
|
|
protected:
|
|
void run(int)
|
|
{
|
|
try
|
|
{
|
|
RNG& rng = theRNG();
|
|
const int MAX_DIM=3;
|
|
int sizes[MAX_DIM];
|
|
for( int iter = 0; iter < 100; iter++ )
|
|
{
|
|
//ts->printf(cvtest::TS::LOG, ".");
|
|
|
|
ts->update_context(this, iter, true);
|
|
int k, dims = rng.uniform(1, MAX_DIM+1), p = 1;
|
|
int depth = rng.uniform(CV_8U, CV_64F+1);
|
|
int cn = rng.uniform(1, 6);
|
|
int type = CV_MAKETYPE(depth, cn);
|
|
int op = rng.uniform(0, 5);
|
|
int depth1 = op <= 1 ? CV_64F : depth;
|
|
for( k = 0; k < dims; k++ )
|
|
{
|
|
sizes[k] = rng.uniform(1, 30);
|
|
p *= sizes[k];
|
|
}
|
|
Mat a(dims, sizes, type), a1;
|
|
Mat b(dims, sizes, type), b1;
|
|
Mat mask(dims, sizes, CV_8U);
|
|
Mat mask1;
|
|
Mat c, d;
|
|
|
|
rng.fill(a, RNG::UNIFORM, 0, 100);
|
|
rng.fill(b, RNG::UNIFORM, 0, 100);
|
|
|
|
// [-2,2) range means that the each generated random number
|
|
// will be one of -2, -1, 0, 1. Saturated to [0,255], it will become
|
|
// 0, 0, 0, 1 => the mask will be filled by ~25%.
|
|
rng.fill(mask, RNG::UNIFORM, -2, 2);
|
|
|
|
a.convertTo(a1, depth1);
|
|
b.convertTo(b1, depth1);
|
|
// invert the mask
|
|
compare(mask, 0, mask1, CMP_EQ);
|
|
a1.setTo(0, mask1);
|
|
b1.setTo(0, mask1);
|
|
|
|
if( op == 0 )
|
|
{
|
|
add(a, b, c, mask);
|
|
add(a1, b1, d);
|
|
}
|
|
else if( op == 1 )
|
|
{
|
|
subtract(a, b, c, mask);
|
|
subtract(a1, b1, d);
|
|
}
|
|
else if( op == 2 )
|
|
{
|
|
bitwise_and(a, b, c, mask);
|
|
bitwise_and(a1, b1, d);
|
|
}
|
|
else if( op == 3 )
|
|
{
|
|
bitwise_or(a, b, c, mask);
|
|
bitwise_or(a1, b1, d);
|
|
}
|
|
else if( op == 4 )
|
|
{
|
|
bitwise_xor(a, b, c, mask);
|
|
bitwise_xor(a1, b1, d);
|
|
}
|
|
Mat d1;
|
|
d.convertTo(d1, depth);
|
|
CV_Assert( cvtest::norm(c, d1, CV_C) <= DBL_EPSILON );
|
|
}
|
|
|
|
Mat_<uchar> tmpSrc(100,100);
|
|
tmpSrc = 124;
|
|
Mat_<uchar> tmpMask(100,100);
|
|
tmpMask = 255;
|
|
Mat_<uchar> tmpDst(100,100);
|
|
tmpDst = 2;
|
|
tmpSrc.copyTo(tmpDst,tmpMask);
|
|
}
|
|
catch(...)
|
|
{
|
|
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
|
|
}
|
|
}
|
|
};
|
|
|
|
TEST(Core_ArithmMask, uninitialized) { CV_ArithmMaskTest test; test.safe_run(); }
|
|
|
|
TEST(Multiply, FloatingPointRounding)
|
|
{
|
|
cv::Mat src(1, 1, CV_8UC1, cv::Scalar::all(110)), dst;
|
|
cv::Scalar s(147.286359696927, 1, 1 ,1);
|
|
|
|
cv::multiply(src, s, dst, 1, CV_16U);
|
|
// with CV_32F this produce result 16202
|
|
ASSERT_EQ(dst.at<ushort>(0,0), 16201);
|
|
}
|
|
|
|
TEST(Core_Add, AddToColumnWhen3Rows)
|
|
{
|
|
cv::Mat m1 = (cv::Mat_<double>(3, 2) << 1, 2, 3, 4, 5, 6);
|
|
m1.col(1) += 10;
|
|
|
|
cv::Mat m2 = (cv::Mat_<double>(3, 2) << 1, 12, 3, 14, 5, 16);
|
|
|
|
ASSERT_EQ(0, countNonZero(m1 - m2));
|
|
}
|
|
|
|
TEST(Core_Add, AddToColumnWhen4Rows)
|
|
{
|
|
cv::Mat m1 = (cv::Mat_<double>(4, 2) << 1, 2, 3, 4, 5, 6, 7, 8);
|
|
m1.col(1) += 10;
|
|
|
|
cv::Mat m2 = (cv::Mat_<double>(4, 2) << 1, 12, 3, 14, 5, 16, 7, 18);
|
|
|
|
ASSERT_EQ(0, countNonZero(m1 - m2));
|
|
}
|
|
|
|
TEST(Core_round, CvRound)
|
|
{
|
|
ASSERT_EQ(2, cvRound(2.0));
|
|
ASSERT_EQ(2, cvRound(2.1));
|
|
ASSERT_EQ(-2, cvRound(-2.1));
|
|
ASSERT_EQ(3, cvRound(2.8));
|
|
ASSERT_EQ(-3, cvRound(-2.8));
|
|
ASSERT_EQ(2, cvRound(2.5));
|
|
ASSERT_EQ(4, cvRound(3.5));
|
|
ASSERT_EQ(-2, cvRound(-2.5));
|
|
ASSERT_EQ(-4, cvRound(-3.5));
|
|
}
|
|
|
|
|
|
typedef testing::TestWithParam<Size> Mul1;
|
|
|
|
TEST_P(Mul1, One)
|
|
{
|
|
Size size = GetParam();
|
|
cv::Mat src(size, CV_32FC1, cv::Scalar::all(2)), dst,
|
|
ref_dst(size, CV_32FC1, cv::Scalar::all(6));
|
|
|
|
cv::multiply(3, src, dst);
|
|
|
|
ASSERT_EQ(0, cvtest::norm(dst, ref_dst, cv::NORM_INF));
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(Arithm, Mul1, testing::Values(Size(2, 2), Size(1, 1)));
|