@ -15,7 +15,12 @@ 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 , SUPPORT_MULTICHANNELMASK = 64 } ;
enum
{
FIX_ALPHA = 1 , FIX_BETA = 2 , FIX_GAMMA = 4 , REAL_GAMMA = 8 ,
SUPPORT_MASK = 16 , SCALAR_OUTPUT = 32 , SUPPORT_MULTICHANNELMASK = 64 ,
MIXED_TYPE = 128
} ;
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 ) { }
@ -101,14 +106,15 @@ struct BaseAddOp : public BaseElemWiseOp
void refop ( const vector < Mat > & src , Mat & dst , const Mat & mask )
{
Ma t temp ;
int dstType = ( flags & MIXED_TYPE ) ? ds t . typ e ( ) : src [ 0 ] . type ( ) ;
if ( ! mask . empty ( ) )
{
cvtest : : add ( src [ 0 ] , alpha , src . size ( ) > 1 ? src [ 1 ] : Mat ( ) , beta , gamma , temp , src [ 0 ] . type ( ) ) ;
Mat temp ;
cvtest : : add ( src [ 0 ] , alpha , src . size ( ) > 1 ? src [ 1 ] : Mat ( ) , beta , gamma , temp , dstType ) ;
cvtest : : copy ( temp , dst , mask ) ;
}
else
cvtest : : add ( src [ 0 ] , alpha , src . size ( ) > 1 ? src [ 1 ] : Mat ( ) , beta , gamma , dst , src [ 0 ] . type ( ) ) ;
cvtest : : add ( src [ 0 ] , alpha , src . size ( ) > 1 ? src [ 1 ] : Mat ( ) , beta , gamma , dst , dstType ) ;
}
} ;
@ -118,10 +124,8 @@ 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 ( ) )
cv : : add ( src [ 0 ] , src [ 1 ] , dst ) ;
else
cv : : add ( src [ 0 ] , src [ 1 ] , dst , mask ) ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cv : : add ( src [ 0 ] , src [ 1 ] , dst , mask , dtype ) ;
}
} ;
@ -131,10 +135,8 @@ 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 ( ) )
cv : : subtract ( src [ 0 ] , src [ 1 ] , dst ) ;
else
cv : : subtract ( src [ 0 ] , src [ 1 ] , dst , mask ) ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cv : : subtract ( src [ 0 ] , src [ 1 ] , dst , mask , dtype ) ;
}
} ;
@ -144,10 +146,8 @@ 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 ( ) )
cv : : add ( src [ 0 ] , gamma , dst ) ;
else
cv : : add ( src [ 0 ] , gamma , dst , mask ) ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cv : : add ( src [ 0 ] , gamma , dst , mask , dtype ) ;
}
} ;
@ -157,10 +157,8 @@ 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 ( ) )
cv : : subtract ( gamma , src [ 0 ] , dst ) ;
else
cv : : subtract ( gamma , src [ 0 ] , dst , mask ) ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cv : : subtract ( gamma , src [ 0 ] , dst , mask , dtype ) ;
}
} ;
@ -174,7 +172,7 @@ struct ScaleAddOp : public BaseAddOp
}
double getMaxErr ( int depth )
{
return depth < = CV_32S ? 2 : depth < CV_64F ? 1e-4 : 1e-12 ;
return depth < CV_32F ? 1 : depth = = CV_32F ? 3e-5 : 1e-12 ;
}
} ;
@ -184,11 +182,8 @@ struct AddWeightedOp : public BaseAddOp
AddWeightedOp ( ) : BaseAddOp ( 2 , REAL_GAMMA , 1 , 1 , Scalar : : all ( 0 ) ) { }
void op ( const vector < Mat > & src , Mat & dst , const Mat & )
{
cv : : 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 ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cv : : addWeighted ( src [ 0 ] , alpha , src [ 1 ] , beta , gamma [ 0 ] , dst , dtype ) ;
}
} ;
@ -204,15 +199,35 @@ struct MulOp : public BaseElemWiseOp
}
void op ( const vector < Mat > & src , Mat & dst , const Mat & )
{
cv : : multiply ( src [ 0 ] , src [ 1 ] , dst , alpha ) ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cv : : multiply ( src [ 0 ] , src [ 1 ] , dst , alpha , dtype ) ;
}
void refop ( const vector < Mat > & src , Mat & dst , const Mat & )
{
cvtest : : multiply ( src [ 0 ] , src [ 1 ] , dst , alpha ) ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cvtest : : multiply ( src [ 0 ] , src [ 1 ] , dst , alpha , dtype ) ;
}
double getMaxErr ( int depth )
} ;
struct MulSOp : public BaseElemWiseOp
{
MulSOp ( ) : BaseElemWiseOp ( 1 , FIX_BETA + FIX_GAMMA , 1 , 1 , Scalar : : all ( 0 ) ) { }
void getValueRange ( int depth , double & minval , double & maxval )
{
return depth < = CV_32S ? 2 : depth < CV_64F ? 1e-5 : 1e-12 ;
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 & )
{
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cv : : multiply ( src [ 0 ] , alpha , dst , /* scale */ 1.0 , dtype ) ;
}
void refop ( const vector < Mat > & src , Mat & dst , const Mat & )
{
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cvtest : : multiply ( Mat ( ) , src [ 0 ] , dst , alpha , dtype ) ;
}
} ;
@ -221,15 +236,20 @@ 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 ) ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cv : : divide ( src [ 0 ] , src [ 1 ] , dst , alpha , dtype ) ;
if ( flags & MIXED_TYPE )
{
// div by zero result is implementation-defined
// since it may involve conversions to/from intermediate format
Mat zeroMask = src [ 1 ] = = 0 ;
dst . setTo ( 0 , zeroMask ) ;
}
}
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 ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cvtest : : divide ( src [ 0 ] , src [ 1 ] , dst , alpha , dtype ) ;
}
} ;
@ -238,15 +258,20 @@ 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 ) ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cv : : divide ( alpha , src [ 0 ] , dst , dtype ) ;
if ( flags & MIXED_TYPE )
{
// div by zero result is implementation-defined
// since it may involve conversions to/from intermediate format
Mat zeroMask = src [ 0 ] = = 0 ;
dst . setTo ( 0 , zeroMask ) ;
}
}
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 ;
int dtype = ( flags & MIXED_TYPE ) ? dst . type ( ) : - 1 ;
cvtest : : divide ( Mat ( ) , src [ 0 ] , dst , alpha , dtype ) ;
}
} ;
@ -1613,6 +1638,107 @@ INSTANTIATE_TEST_CASE_P(Core_MinMaxLoc, ElemWiseTest, ::testing::Values(ElemWise
INSTANTIATE_TEST_CASE_P ( Core_reduceArgMinMax , ElemWiseTest , : : testing : : Values ( ElemWiseOpPtr ( new reduceArgMinMaxOp ) ) ) ;
INSTANTIATE_TEST_CASE_P ( Core_CartToPolarToCart , ElemWiseTest , : : testing : : Values ( ElemWiseOpPtr ( new CartToPolarToCartOp ) ) ) ;
// Mixed Type Arithmetic Operations
typedef std : : tuple < ElemWiseOpPtr , std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > > SomeType ;
class ArithmMixedTest : public : : testing : : TestWithParam < SomeType > { } ;
TEST_P ( ArithmMixedTest , accuracy )
{
auto p = GetParam ( ) ;
ElemWiseOpPtr op = std : : get < 0 > ( p ) ;
int srcDepth = std : : get < 0 > ( std : : get < 1 > ( p ) ) ;
int dstDepth = std : : get < 1 > ( std : : get < 1 > ( p ) ) ;
op - > flags | = BaseElemWiseOp : : MIXED_TYPE ;
int testIdx = 0 ;
RNG rng ( ( uint64 ) ARITHM_RNG_SEED ) ;
for ( testIdx = 0 ; testIdx < ARITHM_NTESTS ; testIdx + + )
{
vector < int > size ;
op - > getRandomSize ( rng , size ) ;
bool haveMask = ( ( op - > flags & BaseElemWiseOp : : SUPPORT_MASK ) ! = 0 ) & & rng . uniform ( 0 , 4 ) = = 0 ;
double minval = 0 , maxval = 0 ;
op - > getValueRange ( srcDepth , minval , maxval ) ;
int ninputs = op - > ninputs ;
vector < Mat > src ( ninputs ) ;
for ( int i = 0 ; i < ninputs ; i + + )
src [ i ] = cvtest : : randomMat ( rng , size , srcDepth , minval , maxval , true ) ;
Mat dst0 , dst , mask ;
if ( haveMask )
{
mask = cvtest : : randomMat ( rng , size , CV_8UC1 , 0 , 2 , true ) ;
}
dst0 = cvtest : : randomMat ( rng , size , dstDepth , minval , maxval , false ) ;
dst = cvtest : : randomMat ( rng , size , dstDepth , minval , maxval , true ) ;
cvtest : : copy ( dst , dst0 ) ;
op - > generateScalars ( dstDepth , rng ) ;
op - > refop ( src , dst0 , mask ) ;
op - > op ( src , dst , mask ) ;
double maxErr = op - > getMaxErr ( dstDepth ) ;
ASSERT_PRED_FORMAT2 ( cvtest : : MatComparator ( maxErr , op - > context ) , dst0 , dst ) < < " \n src[0] ~ " < <
cvtest : : MatInfo ( ! src . empty ( ) ? src [ 0 ] : Mat ( ) ) < < " \n testCase # " < < testIdx < < " \n " ;
}
}
INSTANTIATE_TEST_CASE_P ( Core_AddMixed , ArithmMixedTest ,
: : testing : : Combine ( : : testing : : Values ( ElemWiseOpPtr ( new AddOp ) ) ,
: : testing : : Values ( std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_16U } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_16S } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_32F } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_32F } ) ) ) ;
INSTANTIATE_TEST_CASE_P ( Core_AddScalarMixed , ArithmMixedTest ,
: : testing : : Combine ( : : testing : : Values ( ElemWiseOpPtr ( new AddSOp ) ) ,
: : testing : : Values ( std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_16U } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_16S } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_32F } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_32F } ) ) ) ;
INSTANTIATE_TEST_CASE_P ( Core_AddWeightedMixed , ArithmMixedTest ,
: : testing : : Combine ( : : testing : : Values ( ElemWiseOpPtr ( new AddWeightedOp ) ) ,
: : testing : : Values ( std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_16U } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_16S } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_32F } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_32F } ) ) ) ;
INSTANTIATE_TEST_CASE_P ( Core_SubMixed , ArithmMixedTest ,
: : testing : : Combine ( : : testing : : Values ( ElemWiseOpPtr ( new SubOp ) ) ,
: : testing : : Values ( std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_16U } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_16S } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_32F } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_32F } ) ) ) ;
INSTANTIATE_TEST_CASE_P ( Core_SubScalarMinusArgMixed , ArithmMixedTest ,
: : testing : : Combine ( : : testing : : Values ( ElemWiseOpPtr ( new SubRSOp ) ) ,
: : testing : : Values ( std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_16U } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_16S } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_32F } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_32F } ) ) ) ;
INSTANTIATE_TEST_CASE_P ( Core_MulMixed , ArithmMixedTest ,
: : testing : : Combine ( : : testing : : Values ( ElemWiseOpPtr ( new MulOp ) ) ,
: : testing : : Values ( std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_16U } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_16S } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_32F } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_32F } ) ) ) ;
INSTANTIATE_TEST_CASE_P ( Core_MulScalarMixed , ArithmMixedTest ,
: : testing : : Combine ( : : testing : : Values ( ElemWiseOpPtr ( new MulSOp ) ) ,
: : testing : : Values ( std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_16U } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_16S } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_32F } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_32F } ) ) ) ;
INSTANTIATE_TEST_CASE_P ( Core_DivMixed , ArithmMixedTest ,
: : testing : : Combine ( : : testing : : Values ( ElemWiseOpPtr ( new DivOp ) ) ,
: : testing : : Values ( std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_16U } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_16S } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_32F } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_32F } ) ) ) ;
INSTANTIATE_TEST_CASE_P ( Core_RecipMixed , ArithmMixedTest ,
: : testing : : Combine ( : : testing : : Values ( ElemWiseOpPtr ( new RecipOp ) ) ,
: : testing : : Values ( std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8U , CV_32F } ,
std : : tuple < cvtest : : MatDepth , cvtest : : MatDepth > { CV_8S , CV_32F } ) ) ) ;
TEST ( Core_ArithmMask , uninitialized )
{