diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index 31d182c713..2e927c498c 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -1192,8 +1192,8 @@ public: /** @overload @param m Destination matrix. If it does not have a proper size or type before the operation, it is reallocated. - @param mask Operation mask. 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. + @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. */ void copyTo( OutputArray m, InputArray mask ) const; @@ -1229,7 +1229,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. + @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 */ Mat& setTo(InputArray value, InputArray mask=noArray()); diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index e07a75f947..d22e762b1f 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -336,7 +336,7 @@ static bool ipp_copyTo(const Mat &src, Mat &dst, const Mat &mask) #ifdef HAVE_IPP_IW CV_INSTRUMENT_REGION_IPP() - if(mask.channels() > 1 && mask.depth() != CV_8U) + if(mask.channels() > 1 || mask.depth() != CV_8U) return false; if (src.dims <= 2) @@ -512,20 +512,23 @@ Mat& Mat::setTo(InputArray _value, InputArray _mask) Mat value = _value.getMat(), mask = _mask.getMat(); CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::MAT )); - CV_Assert( mask.empty() || (mask.type() == CV_8U && size == mask.size) ); + int cn = channels(), mcn = mask.channels(); + CV_Assert( mask.empty() || (mask.depth() == CV_8U && (mcn == 1 || mcn == cn) && size == mask.size) ); CV_IPP_RUN_FAST(ipp_Mat_setTo_Mat(*this, value, mask), *this) - size_t esz = elemSize(); + size_t esz = mcn > 1 ? elemSize1() : elemSize(); BinaryFunc copymask = getCopyMaskFunc(esz); const Mat* arrays[] = { this, !mask.empty() ? &mask : 0, 0 }; uchar* ptrs[2]={0,0}; NAryMatIterator it(arrays, ptrs); - int totalsz = (int)it.size, blockSize0 = std::min(totalsz, (int)((BLOCK_SIZE + esz-1)/esz)); + int totalsz = (int)it.size*mcn; + int blockSize0 = std::min(totalsz, (int)((BLOCK_SIZE + esz-1)/esz)); + blockSize0 -= blockSize0 % mcn; // must be divisible without remainder for unrolling and advancing AutoBuffer _scbuf(blockSize0*esz + 32); uchar* scbuf = alignPtr((uchar*)_scbuf, (int)sizeof(double)); - convertAndUnrollScalar( value, type(), scbuf, blockSize0 ); + convertAndUnrollScalar( value, type(), scbuf, blockSize0/mcn ); for( size_t i = 0; i < it.nplanes; i++, ++it ) { diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index 78c0689852..ae5e4a7728 100644 --- a/modules/core/test/test_arithm.cpp +++ b/modules/core/test/test_arithm.cpp @@ -1,4 +1,4 @@ -#include "test_precomp.hpp" +#include "test_precomp.hpp" #include using namespace cv; @@ -15,7 +15,7 @@ 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 }; + enum { FIX_ALPHA=1, FIX_BETA=2, FIX_GAMMA=4, REAL_GAMMA=8, SUPPORT_MASK=16, SCALAR_OUTPUT=32, SUPPORT_MULTICHANNELMASK=64 }; 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) {} @@ -467,7 +467,7 @@ struct CmpSOp : public BaseElemWiseOp struct CopyOp : public BaseElemWiseOp { - CopyOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) { } + CopyOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SUPPORT_MULTICHANNELMASK, 1, 1, Scalar::all(0)) { } void op(const vector& src, Mat& dst, const Mat& mask) { src[0].copyTo(dst, mask); @@ -489,7 +489,7 @@ struct CopyOp : public BaseElemWiseOp struct SetOp : public BaseElemWiseOp { - SetOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {} + SetOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+SUPPORT_MASK+SUPPORT_MULTICHANNELMASK, 1, 1, Scalar::all(0)) {} void op(const vector&, Mat& dst, const Mat& mask) { dst.setTo(gamma, mask); @@ -1394,7 +1394,8 @@ TEST_P(ElemWiseTest, accuracy) 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; + bool haveMask = ((op->flags & cvtest::BaseElemWiseOp::SUPPORT_MASK) != 0 + || (op->flags & cvtest::BaseElemWiseOp::SUPPORT_MULTICHANNELMASK) != 0) && rng.uniform(0, 4) == 0; double minval=0, maxval=0; op->getValueRange(depth, minval, maxval); @@ -1403,8 +1404,12 @@ TEST_P(ElemWiseTest, accuracy) 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 ) { + bool multiChannelMask = (op->flags & cvtest::BaseElemWiseOp::SUPPORT_MULTICHANNELMASK) != 0 + && rng.uniform(0, 2) == 0; + int masktype = CV_8UC(multiChannelMask ? CV_MAT_CN(type) : 1); + mask = cvtest::randomMat(rng, size, masktype, 0, 2, true); + } if( (haveMask || ninputs == 0) && !(op->flags & cvtest::BaseElemWiseOp::SCALAR_OUTPUT)) { diff --git a/modules/ts/src/ts_func.cpp b/modules/ts/src/ts_func.cpp index 5d229cf89d..be9bcf5549 100644 --- a/modules/ts/src/ts_func.cpp +++ b/modules/ts/src/ts_func.cpp @@ -353,26 +353,38 @@ void copy(const Mat& src, Mat& dst, const Mat& mask, bool invertMask) return; } - CV_Assert( src.size == mask.size && mask.type() == CV_8U ); + int mcn = mask.channels(); + CV_Assert( src.size == mask.size && mask.depth() == CV_8U + && (mcn == 1 || mcn == src.channels()) ); const Mat *arrays[]={&src, &dst, &mask, 0}; Mat planes[3]; NAryMatIterator it(arrays, planes); - size_t j, k, elemSize = src.elemSize(), total = planes[0].total(); + size_t j, k, elemSize = src.elemSize(), maskElemSize = mask.elemSize(), total = planes[0].total(); size_t i, nplanes = it.nplanes; + size_t elemSize1 = src.elemSize1(); for( i = 0; i < nplanes; i++, ++it) { const uchar* sptr = planes[0].ptr(); uchar* dptr = planes[1].ptr(); const uchar* mptr = planes[2].ptr(); - - for( j = 0; j < total; j++, sptr += elemSize, dptr += elemSize ) + for( j = 0; j < total; j++, sptr += elemSize, dptr += elemSize, mptr += maskElemSize ) { - if( (mptr[j] != 0) ^ invertMask ) - for( k = 0; k < elemSize; k++ ) - dptr[k] = sptr[k]; + if( mcn == 1) + { + if( (mptr[0] != 0) ^ invertMask ) + for( k = 0; k < elemSize; k++ ) + dptr[k] = sptr[k]; + } + else + { + for( int c = 0; c < mcn; c++ ) + if( (mptr[c] != 0) ^ invertMask ) + for( k = 0; k < elemSize1; k++ ) + dptr[k + c * elemSize1] = sptr[k + c * elemSize1]; + } } } } @@ -414,25 +426,37 @@ void set(Mat& dst, const Scalar& gamma, const Mat& mask) return; } - CV_Assert( dst.size == mask.size && mask.type() == CV_8U ); + int cn = dst.channels(), mcn = mask.channels(); + CV_Assert( dst.size == mask.size && (mcn == 1 || mcn == cn) ); const Mat *arrays[]={&dst, &mask, 0}; Mat planes[2]; NAryMatIterator it(arrays, planes); - size_t j, k, elemSize = dst.elemSize(), total = planes[0].total(); + size_t j, k, elemSize = dst.elemSize(), maskElemSize = mask.elemSize(), total = planes[0].total(); size_t i, nplanes = it.nplanes; + size_t elemSize1 = dst.elemSize1(); for( i = 0; i < nplanes; i++, ++it) { uchar* dptr = planes[0].ptr(); const uchar* mptr = planes[1].ptr(); - for( j = 0; j < total; j++, dptr += elemSize ) + for( j = 0; j < total; j++, dptr += elemSize, mptr += maskElemSize ) { - if( mptr[j] ) - for( k = 0; k < elemSize; k++ ) - dptr[k] = gptr[k]; + if( mcn == 1) + { + if( mptr[0] ) + for( k = 0; k < elemSize; k++ ) + dptr[k] = gptr[k]; + } + else + { + for( int c = 0; c < mcn; c++ ) + if( mptr[c] ) + for( k = 0; k < elemSize1; k++ ) + dptr[k + c * elemSize1] = gptr[k + c * elemSize1]; + } } } }