Merge pull request #25902 from asmorkalov:as/core_mask_cvbool

Mask support with CV_Bool in ts and core #25902

Partially cover https://github.com/opencv/opencv/issues/25895

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
pull/25953/head
Alexander Smorkalov 9 months ago committed by GitHub
parent 8ba70194b1
commit 459a9c60ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 28
      modules/core/include/opencv2/core.hpp
  2. 6
      modules/core/include/opencv2/core/mat.hpp
  3. 6
      modules/core/src/arithm.cpp
  4. 5
      modules/core/src/copy.cpp
  5. 8
      modules/core/src/mean.dispatch.cpp
  6. 6
      modules/core/src/minmax.dispatch.cpp
  7. 4
      modules/core/src/norm.cpp
  8. 2
      modules/core/src/sum.dispatch.cpp
  9. 4
      modules/core/src/umatrix.cpp
  10. 196
      modules/core/test/test_arithm.cpp
  11. 8
      modules/ts/src/ts_func.cpp

@ -352,8 +352,8 @@ result of an incorrect sign in the case of overflow.
@param src2 second input array or a scalar.
@param dst output array that has the same size and number of channels as the input array(s); the
depth is defined by dtype or src1/src2.
@param mask optional operation mask - 8-bit single channel array, that specifies elements of the
output array to be changed.
@param mask optional operation mask - CV_8U, CV_8S or CV_Bool single channel array, that specifies elements
of the output array to be changed.
@param dtype optional depth of the output array (see the discussion below).
@sa subtract, addWeighted, scaleAdd, Mat::convertTo
*/
@ -395,7 +395,7 @@ result of an incorrect sign in the case of overflow.
@param src1 first input array or a scalar.
@param src2 second input array or a scalar.
@param dst output array of the same size and the same number of channels as the input array.
@param mask optional operation mask; this is an 8-bit single channel array that specifies elements
@param mask optional operation mask; this is CV_8U, CV8S or CV_Bool single channel array that specifies elements
of the output array to be changed.
@param dtype optional depth of the output array
@sa add, addWeighted, scaleAdd, Mat::convertTo
@ -669,7 +669,7 @@ independently for each channel, and return it:
When all the mask elements are 0's, the function returns Scalar::all(0)
@param src input array that should have from 1 to 4 channels so that the result can be stored in
Scalar_ .
@param mask optional operation mask.
@param mask optional operation mask ot type CV_8U, CV_8S or CV_Bool.
@sa countNonZero, meanStdDev, norm, minMaxLoc
*/
CV_EXPORTS_W Scalar mean(InputArray src, InputArray mask = noArray());
@ -691,7 +691,7 @@ then pass the matrix to calcCovarMatrix .
Scalar_ 's.
@param mean output parameter: calculated mean value.
@param stddev output parameter: calculated standard deviation.
@param mask optional operation mask.
@param mask optional operation mask of type CV_8U, CV_8S or CV_Bool.
@sa countNonZero, mean, norm, minMaxLoc, calcCovarMatrix
*/
CV_EXPORTS_W void meanStdDev(InputArray src, OutputArray mean, OutputArray stddev,
@ -731,7 +731,7 @@ Hamming norms can only be calculated with CV_8U depth arrays.
@param src1 first input array.
@param normType type of the norm (see #NormTypes).
@param mask optional operation mask; it must have the same size as src1 and CV_8UC1 type.
@param mask optional operation mask; it must have the same size as src1 and type CV_8UC1, CV_8SC1 or CV_BoolC1.
*/
CV_EXPORTS_W double norm(InputArray src1, int normType = NORM_L2, InputArray mask = noArray());
@ -744,7 +744,7 @@ The type of norm to calculate is specified using #NormTypes.
@param src1 first input array.
@param src2 second input array of the same size and the same type as src1.
@param normType type of the norm (see #NormTypes).
@param mask optional operation mask; it must have the same size as src1 and CV_8UC1 type.
@param mask optional operation mask; it must have the same size as src1 and type CV_8UC1, CV_8S1 or CV_BoolC1.
*/
CV_EXPORTS_W double norm(InputArray src1, InputArray src2,
int normType = NORM_L2, InputArray mask = noArray());
@ -841,7 +841,7 @@ normalization.
@param norm_type normalization type (see cv::NormTypes).
@param dtype when negative, the output array has the same type as src; otherwise, it has the same
number of channels as src and the depth =CV_MAT_DEPTH(dtype).
@param mask optional operation mask.
@param mask optional operation mask of type CV_8U, CV_8S or CV_Bool.
@sa norm, Mat::convertTo, SparseMat::convertTo
*/
CV_EXPORTS_W void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0,
@ -872,7 +872,7 @@ mixChannels, or split.
@param maxVal pointer to the returned maximum value; NULL is used if not required.
@param minLoc pointer to the returned minimum location (in 2D case); NULL is used if not required.
@param maxLoc pointer to the returned maximum location (in 2D case); NULL is used if not required.
@param mask optional mask used to select a sub-array.
@param mask optional mask used to select a sub-array of type CV_8U, CV_8S or CV_Bool.
@sa max, min, reduceArgMin, reduceArgMax, compare, inRange, extractImageCOI, mixChannels, split, Mat::reshape
*/
CV_EXPORTS_W void minMaxLoc(InputArray src, CV_OUT double* minVal,
@ -1359,7 +1359,7 @@ converted to the array type.
@param src2 second input array or a scalar.
@param dst output array that has the same size and type as the input
arrays.
@param mask optional operation mask, 8-bit single channel array, that
@param mask optional operation mask, CV_8U, CV_8S or CV_Bool single channel array, that
specifies elements of the output array to be changed.
*/
CV_EXPORTS_W void bitwise_and(InputArray src1, InputArray src2,
@ -1386,7 +1386,7 @@ converted to the array type.
@param src2 second input array or a scalar.
@param dst output array that has the same size and type as the input
arrays.
@param mask optional operation mask, 8-bit single channel array, that
@param mask optional operation mask, CV_8U, CV_8S or CV_Bool single channel array, that
specifies elements of the output array to be changed.
*/
CV_EXPORTS_W void bitwise_or(InputArray src1, InputArray src2,
@ -1414,7 +1414,7 @@ converted to the array type.
@param src2 second input array or a scalar.
@param dst output array that has the same size and type as the input
arrays.
@param mask optional operation mask, 8-bit single channel array, that
@param mask optional operation mask, CV_8U, CV_8S or CV_Bool single channel array, that
specifies elements of the output array to be changed.
*/
CV_EXPORTS_W void bitwise_xor(InputArray src1, InputArray src2,
@ -1431,7 +1431,7 @@ case of multi-channel arrays, each channel is processed independently.
@param src input array.
@param dst output array that has the same size and type as the input
array.
@param mask optional operation mask, 8-bit single channel array, that
@param mask optional operation mask, CV_8U, CV_8S or CV_Bool single channel array, that
specifies elements of the output array to be changed.
*/
CV_EXPORTS_W void bitwise_not(InputArray src, OutputArray dst,
@ -1472,7 +1472,7 @@ When the operation mask is specified, if the Mat::create call shown above reallo
@param dst Destination matrix. If it does not have a proper size or type before the operation, it is
reallocated.
@param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix
elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels.
elements need to be copied. The mask has to be of type CV_8U, CV_8S or CV_Bool and can have 1 or multiple channels.
*/
void CV_EXPORTS_W copyTo(InputArray src, OutputArray dst, InputArray mask);

@ -1232,7 +1232,8 @@ public:
@param m Destination matrix. If it does not have a proper size or type before the operation, it is
reallocated.
@param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix
elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels.
elements need to be copied. The mask has to be of type CV_8U, CV_8S or CV_Bool and can have 1 or
multiple channels.
*/
void copyTo( OutputArray m, InputArray mask ) const;
@ -1269,7 +1270,8 @@ public:
This is an advanced variant of the Mat::operator=(const Scalar& s) operator.
@param value Assigned scalar converted to the actual array type.
@param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix
elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels
elements need to be copied. The mask has to be of type CV_8U, CV_8S or CV_Bool and can have 1 or
multiple channels.
*/
Mat& setTo(InputArray value, InputArray mask=noArray());

@ -227,7 +227,7 @@ static void binary_op( InputArray _src1, InputArray _src2, OutputArray _dst,
if( haveMask )
{
int mtype = _mask.type();
CV_Assert( (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1));
CV_Assert( (mtype == CV_8U || mtype == CV_8S || mtype == CV_Bool) && _mask.sameSize(*psrc1));
copymask = getCopyMaskFunc(esz);
reallocate = !_dst.sameSize(*psrc1) || _dst.type() != type1;
}
@ -739,7 +739,7 @@ static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
if( haveMask )
{
int mtype = _mask.type();
CV_Assert( (mtype == CV_8UC1 || mtype == CV_8SC1) && _mask.sameSize(*psrc1) );
CV_Assert( (mtype == CV_8UC1 || mtype == CV_8SC1 || mtype == CV_Bool) && _mask.sameSize(*psrc1) );
reallocate = !_dst.sameSize(*psrc1) || _dst.type() != dtype;
}
@ -1261,7 +1261,7 @@ static BinaryFuncC getCmpFunc(int depth)
(BinaryFuncC)cv::hal::cmp64f,
(BinaryFuncC)cv::hal::cmp16f,
(BinaryFuncC)cv::hal::cmp16bf,
0,
(BinaryFuncC)GET_OPTIMIZED(cv::hal::cmp8u),
(BinaryFuncC)cv::hal::cmp64u,
(BinaryFuncC)cv::hal::cmp64s,
(BinaryFuncC)cv::hal::cmp32u,

@ -454,7 +454,7 @@ void Mat::copyTo( OutputArray _dst, InputArray _mask ) const
}
int cn = channels(), mcn = mask.channels();
CV_Assert( mask.depth() == CV_8U && (mcn == 1 || mcn == cn) );
CV_Assert( (mask.depth() == CV_8U || mask.depth() == CV_8S || mask.depth() == CV_Bool) && (mcn == 1 || mcn == cn) );
bool colorMask = mcn > 1;
if( dims <= 2 )
{
@ -643,7 +643,8 @@ Mat& Mat::setTo(InputArray _value, InputArray _mask)
CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::MAT ));
int cn = channels(), mcn = mask.channels();
CV_Assert( mask.empty() || (mask.depth() == CV_8U && (mcn == 1 || mcn == cn) && size == mask.size) );
CV_Assert( mask.empty() || ((mask.depth() == CV_8U || mask.depth() == CV_8S || mask.depth() == CV_Bool) &&
(mcn == 1 || mcn == cn) && size == mask.size) );
CV_IPP_RUN_FAST(ipp_Mat_setTo_Mat(*this, value, mask), *this)

@ -126,7 +126,7 @@ Scalar mean(InputArray _src, InputArray _mask)
CV_INSTRUMENT_REGION();
Mat src = _src.getMat(), mask = _mask.getMat();
CV_Assert( mask.empty() || mask.type() == CV_8U );
CV_Assert( mask.empty() || mask.type() == CV_8U || mask.type() == CV_8S || mask.type() == CV_Bool);
int k, cn = src.channels(), depth = src.depth();
Scalar s;
@ -227,7 +227,7 @@ static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv
int ddepth = std::max(CV_32S, depth), sqddepth = std::max(CV_32F, depth),
dtype = CV_MAKE_TYPE(ddepth, cn),
sqdtype = CV_MAKETYPE(sqddepth, cn);
CV_Assert(!haveMask || _mask.type() == CV_8UC1);
CV_Assert(!haveMask || _mask.type() == CV_8U || _mask.type() == CV_8S || _mask.type() == CV_Bool);
int wgs2_aligned = 1;
while (wgs2_aligned < (int)wgs)
@ -461,14 +461,14 @@ void meanStdDev(InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
CV_Assert( _mask.empty() || _mask.type() == CV_8UC1 );
CV_Assert( _mask.empty() || _mask.type() == CV_8U || _mask.type() == CV_8S || _mask.type() == CV_Bool );
CV_OCL_RUN(OCL_PERFORMANCE_CHECK(_src.isUMat()) && _src.dims() <= 2,
ocl_meanStdDev(_src, _mean, _sdv, _mask))
Mat src = _src.getMat(), mask = _mask.getMat();
CV_Assert(mask.empty() || src.size == mask.size);
CV_Assert(mask.empty() || ((mask.type() == CV_8U || mask.type() == CV_8S || mask.type() == CV_Bool) && src.size == mask.size));
CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_meanStdDev(src, _mean, _sdv, mask));

@ -171,7 +171,7 @@ bool ocl_minMaxIdx( InputArray _src, double* minVal, double* maxVal, int* minLoc
if ((haveMask || type == CV_32FC1) && dev.isAMD())
return false;
CV_Assert( (cn == 1 && (!haveMask || _mask.type() == CV_8U)) ||
CV_Assert( (cn == 1 && (!haveMask || _mask.type() == CV_8U || _mask.type() == CV_8S || _mask.type() == CV_Bool)) ||
(cn >= 1 && !minLoc && !maxLoc) );
if (ddepth < 0)
@ -302,8 +302,8 @@ void cv::minMaxIdx(InputArray _src, double* minVal,
CV_INSTRUMENT_REGION();
int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
CV_Assert( (cn == 1 && (_mask.empty() || _mask.type() == CV_8U)) ||
(cn > 1 && _mask.empty() && !minIdx && !maxIdx) );
CV_Assert( (cn == 1 && (_mask.empty() || _mask.type() == CV_8U || _mask.type() == CV_8S || _mask.type() == CV_Bool)) ||
(cn > 1 && _mask.empty() && !minIdx && !maxIdx) );
CV_OCL_RUN(OCL_PERFORMANCE_CHECK(_src.isUMat()) && _src.dims() <= 2 && (_mask.empty() || _src.size() == _mask.size()),
ocl_minMaxIdx(_src, minVal, maxVal, minIdx, maxIdx, _mask))

@ -744,7 +744,7 @@ double norm( InputArray _src, int normType, InputArray _mask )
}
}
CV_Assert( mask.empty() || mask.type() == CV_8U );
CV_Assert( mask.empty() || mask.type() == CV_8U || mask.type() == CV_8S || mask.type() == CV_Bool );
if( normType == NORM_HAMMING || normType == NORM_HAMMING2 )
{
@ -1197,7 +1197,7 @@ double norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask
}
}
CV_Assert( mask.empty() || mask.type() == CV_8U );
CV_Assert( mask.empty() || mask.type() == CV_8U || mask.type() == CV_8S || mask.type() == CV_Bool );
if( normType == NORM_HAMMING || normType == NORM_HAMMING2 )
{

@ -56,7 +56,7 @@ bool ocl_sum( InputArray _src, Scalar & res, int sum_op, InputArray _mask,
int ddepth = std::max(sum_op == OCL_OP_SUM_SQR ? CV_32F : CV_32S, depth),
dtype = CV_MAKE_TYPE(ddepth, cn);
CV_Assert(!haveMask || _mask.type() == CV_8UC1);
CV_Assert(!haveMask || _mask.type() == CV_8U || _mask.type() == CV_8S || _mask.type() == CV_Bool);
int wgs2_aligned = 1;
while (wgs2_aligned < (int)wgs)

@ -1230,7 +1230,7 @@ void UMat::copyTo(OutputArray _dst, InputArray _mask) const
}
#ifdef HAVE_OPENCL
int cn = channels(), mtype = _mask.type(), mdepth = CV_MAT_DEPTH(mtype), mcn = CV_MAT_CN(mtype);
CV_Assert( mdepth == CV_8U && (mcn == 1 || mcn == cn) );
CV_Assert( (mdepth == CV_8U || mdepth == CV_8S || mdepth == CV_Bool) && (mcn == 1 || mcn == cn) );
if (ocl::useOpenCL() && _dst.isUMat() && dims <= 2)
{
@ -1307,7 +1307,7 @@ UMat& UMat::setTo(InputArray _value, InputArray _mask)
if( haveMask )
{
mask = _mask.getUMat();
CV_Assert( mask.size() == size() && mask.type() == CV_8UC1 );
CV_Assert( mask.size() == size() && (mask.type() == CV_8U || mask.type() == CV_8S || mask.type() == CV_Bool) );
ocl::KernelArg maskarg = ocl::KernelArg::ReadOnlyNoSize(mask),
dstarg = ocl::KernelArg::ReadWrite(*this);
setK.args(maskarg, dstarg, scalararg);

@ -2462,23 +2462,22 @@ TEST(Compare, regression_16F_do_not_crash)
EXPECT_NO_THROW(cv::compare(mat1, mat2, dst, cv::CMP_EQ));
}
TEST(Core_minMaxIdx, regression_9207_1)
{
const int rows = 4;
const int cols = 3;
uchar mask_[rows*cols] = {
255, 255, 255,
255, 0, 255,
0, 255, 255,
0, 0, 255
};
255, 255, 255,
255, 0, 255,
0, 255, 255,
0, 0, 255
};
uchar src_[rows*cols] = {
1, 1, 1,
1, 1, 1,
2, 1, 1,
2, 2, 1
};
1, 1, 1,
1, 1, 1,
2, 1, 1,
2, 2, 1
};
Mat mask(Size(cols, rows), CV_8UC1, mask_);
Mat src(Size(cols, rows), CV_8UC1, src_);
double minVal = -0.0, maxVal = -0.0;
@ -2490,7 +2489,6 @@ TEST(Core_minMaxIdx, regression_9207_1)
EXPECT_EQ(0, maxIdx[1]);
}
class TransposeND : public testing::TestWithParam< tuple<std::vector<int>, perf::MatType> >
{
public:
@ -2886,11 +2884,11 @@ TEST(Core_Norm, IPP_regression_NORM_L1_16UC3_small)
Mat a(sz, CV_MAKE_TYPE(CV_16U, cn), Scalar::all(1));
Mat b(sz, CV_MAKE_TYPE(CV_16U, cn), Scalar::all(2));
uchar mask_[9*4] = {
255, 255, 255, 0, 255, 255, 0, 255, 0,
0, 255, 0, 0, 255, 255, 255, 255, 0,
0, 0, 0, 255, 0, 255, 0, 255, 255,
0, 0, 255, 0, 255, 255, 255, 0, 255
};
255, 255, 255, 0, 255, 255, 0, 255, 0,
0, 255, 0, 0, 255, 255, 255, 255, 0,
0, 0, 0, 255, 0, 255, 0, 255, 255,
0, 0, 255, 0, 255, 255, 255, 0, 255
};
Mat mask(sz, CV_8UC1, mask_);
EXPECT_EQ((double)9*4*cn, cv::norm(a, b, NORM_L1)); // without mask, IPP works well
@ -3622,7 +3620,169 @@ TEST_P(Core_LUT, accuracy_multi)
ASSERT_EQ(0, cv::norm(output, gt, cv::NORM_INF));
}
INSTANTIATE_TEST_CASE_P(/**/, Core_LUT, perf::MatDepth::all());
CV_ENUM(MaskType, CV_8U, CV_8S, CV_Bool)
typedef testing::TestWithParam<MaskType> Core_MaskTypeTest;
TEST_P(Core_MaskTypeTest, BasicArithm)
{
int mask_type = GetParam();
RNG& rng = theRNG();
const int MAX_DIM=3;
int sizes[MAX_DIM];
for( int iter = 0; iter < 100; iter++ )
{
int dims = rng.uniform(1, MAX_DIM+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, depth < CV_32F ? 5 : 2); // don't run binary operations between floating-point values
int depth1 = op <= 1 ? CV_64F : depth;
for (int k = 0; k < MAX_DIM; k++)
{
sizes[k] = k < dims ? rng.uniform(1, 30) : 0;
}
Mat a(dims, sizes, type), a1;
Mat b(dims, sizes, type), b1;
Mat mask(dims, sizes, mask_type);
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
cv::compare(mask, 0, mask1, CMP_EQ);
a1.setTo(0, mask1);
b1.setTo(0, mask1);
if( op == 0 )
{
cv::add(a, b, c, mask);
cv::add(a1, b1, d);
}
else if( op == 1 )
{
cv::subtract(a, b, c, mask);
cv::subtract(a1, b1, d);
}
else if( op == 2 )
{
cv::bitwise_and(a, b, c, mask);
cv::bitwise_and(a1, b1, d);
}
else if( op == 3 )
{
cv::bitwise_or(a, b, c, mask);
cv::bitwise_or(a1, b1, d);
}
else if( op == 4 )
{
cv::bitwise_xor(a, b, c, mask);
cv::bitwise_xor(a1, b1, d);
}
Mat d1;
d.convertTo(d1, depth);
EXPECT_LE(cvtest::norm(c, d1, NORM_INF), DBL_EPSILON);
}
}
TEST_P(Core_MaskTypeTest, MinMaxIdx)
{
int mask_type = GetParam();
const int rows = 4;
const int cols = 3;
uchar mask_[rows*cols] = {
255, 255, 1,
255, 0, 255,
0, 1, 255,
0, 0, 255
};
uchar src_[rows*cols] = {
1, 1, 1,
1, 1, 1,
2, 1, 1,
2, 2, 1
};
Mat mask(Size(cols, rows), mask_type, mask_);
Mat src(Size(cols, rows), CV_8UC1, src_);
double minVal = -0.0, maxVal = -0.0;
int minIdx[2] = { -2, -2 }, maxIdx[2] = { -2, -2 };
cv::minMaxIdx(src, &minVal, &maxVal, minIdx, maxIdx, mask);
EXPECT_EQ(0, minIdx[0]);
EXPECT_EQ(0, minIdx[1]);
EXPECT_EQ(0, maxIdx[0]);
EXPECT_EQ(0, maxIdx[1]);
}
TEST_P(Core_MaskTypeTest, Norm)
{
int mask_type = GetParam();
int cn = 3;
Size sz(9, 4); // width < 16
Mat a(sz, CV_MAKE_TYPE(CV_16U, cn), Scalar::all(1));
Mat b(sz, CV_MAKE_TYPE(CV_16U, cn), Scalar::all(2));
uchar mask_[9*4] = {
255, 255, 255, 0, 1, 255, 0, 255, 0,
0, 255, 0, 0, 255, 255, 255, 255, 0,
0, 0, 0, 255, 0, 1, 0, 255, 255,
0, 0, 255, 0, 255, 255, 1, 0, 255
};
Mat mask(sz, mask_type, mask_);
EXPECT_EQ((double)9*4*cn, cv::norm(a, b, NORM_L1)); // without mask, IPP works well
EXPECT_EQ((double)20*cn, cv::norm(a, b, NORM_L1, mask));
}
TEST_P(Core_MaskTypeTest, Mean)
{
int mask_type = GetParam();
Size sz(9, 4);
Mat a(sz, CV_16UC1, Scalar::all(1));
uchar mask_[9*4] = {
255, 255, 255, 0, 1, 255, 0, 255, 0,
0, 255, 0, 0, 255, 255, 255, 255, 0,
0, 0, 0, 1, 0, 255, 0, 1, 255,
0, 0, 255, 0, 255, 255, 255, 0, 255
};
Mat mask(sz, mask_type, mask_);
a.setTo(2, mask);
Scalar result = cv::mean(a, mask);
EXPECT_NEAR(result[0], 2, 1e-6);
}
TEST_P(Core_MaskTypeTest, MeanStdDev)
{
int mask_type = GetParam();
Size sz(9, 4);
Mat a(sz, CV_16UC1, Scalar::all(1));
uchar mask_[9*4] = {
255, 255, 255, 0, 1, 255, 0, 255, 0,
0, 255, 0, 0, 255, 255, 255, 255, 0,
0, 0, 0, 1, 0, 255, 0, 1, 255,
0, 0, 255, 0, 255, 255, 255, 0, 255
};
Mat mask(sz, mask_type, mask_);
a.setTo(2, mask);
Scalar m, stddev;
cv::meanStdDev(a, m, stddev, mask);
EXPECT_NEAR(m[0], 2, 1e-6);
EXPECT_NEAR(stddev[0], 0, 1e-6);
}
INSTANTIATE_TEST_CASE_P(/**/, Core_MaskTypeTest, MaskType::all());
}} // namespace

@ -431,7 +431,7 @@ void copy(const Mat& src, Mat& dst, const Mat& mask, bool invertMask)
}
int mcn = mask.channels();
CV_Assert( src.size == mask.size && mask.depth() == CV_8U
CV_Assert( src.size == mask.size && (mask.depth() == CV_8U || mask.depth() == CV_Bool)
&& (mcn == 1 || mcn == src.channels()) );
const Mat *arrays[]={&src, &dst, &mask, 0};
@ -1397,7 +1397,7 @@ double norm(InputArray _src, int normType, InputArray _mask)
int normType0 = normType;
normType = normType == NORM_L2SQR ? NORM_L2 : normType;
CV_Assert( mask.empty() || (src.size == mask.size && mask.type() == CV_8U) );
CV_Assert( mask.empty() || (src.size == mask.size && (mask.type() == CV_8U || mask.type() == CV_Bool)) );
CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 );
const Mat *arrays[]={&src, &mask, 0};
@ -1506,7 +1506,7 @@ double norm(InputArray _src1, InputArray _src2, int normType, InputArray _mask)
CV_CheckTypeEQ(src1.type(), src2.type(), "");
CV_Assert(src1.size == src2.size);
CV_Assert( mask.empty() || (src1.size == mask.size && mask.type() == CV_8U) );
CV_Assert( mask.empty() || (src1.size == mask.size && (mask.type() == CV_8U || mask.type() == CV_Bool)) );
CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 );
const Mat *arrays[]={&src1, &src2, &mask, 0};
Mat planes[3];
@ -2937,7 +2937,7 @@ mean_(const _Tp* src, const uchar* mask, size_t total, int cn, Scalar& sum, int&
Scalar mean(const Mat& src, const Mat& mask)
{
CV_Assert(mask.empty() || (mask.type() == CV_8U && mask.size == src.size));
CV_Assert(mask.empty() || ((mask.type() == CV_8U || mask.type() == CV_Bool) && mask.size == src.size));
Scalar sum;
int nz = 0;

Loading…
Cancel
Save