Skip to content

Commit 46a668c

Browse files
Add multi-channel mask support to mean, meanStdDev and setTo
This adds the possibility to use multi-channel masks for the functions cv::mean, cv::meanStdDev and the method Mat::setTo. The tests have now a probability to use multi-channel masks for operations that support them. This also includes Mat::copyTo, which supported multi-channel masks before, but there was no test confirming this.
1 parent 791a11f commit 46a668c

File tree

6 files changed

+371
-160
lines changed

6 files changed

+371
-160
lines changed

modules/core/include/opencv2/core.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ CV_EXPORTS_W void findNonZero( InputArray src, OutputArray idx );
608608
609609
The function cv::mean calculates the mean value M of array elements,
610610
independently for each channel, and return it:
611-
\f[\begin{array}{l} N = \sum _{I: \; \texttt{mask} (I) \ne 0} 1 \\ M_c = \left ( \sum _{I: \; \texttt{mask} (I) \ne 0}{ \texttt{mtx} (I)_c} \right )/N \end{array}\f]
611+
\f[\begin{array}{l} N_c = \sum _{I: \; {\texttt{mask} (I)_c} \ne 0} 1 \\ M_c = \left ( \sum _{I: \; {\texttt{mask} (I)_c} \ne 0}{ \texttt{src} (I)_c} \right )/N_c \end{array}\f]
612612
When all the mask elements are 0's, the function returns Scalar::all(0)
613613
@param src input array that should have from 1 to 4 channels so that the result can be stored in
614614
Scalar_ .
@@ -622,7 +622,7 @@ CV_EXPORTS_W Scalar mean(InputArray src, InputArray mask = noArray());
622622
The function cv::meanStdDev calculates the mean and the standard deviation M
623623
of array elements independently for each channel and returns it via the
624624
output parameters:
625-
\f[\begin{array}{l} N = \sum _{I, \texttt{mask} (I) \ne 0} 1 \\ \texttt{mean} _c = \frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \texttt{src} (I)_c}{N} \\ \texttt{stddev} _c = \sqrt{\frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \left ( \texttt{src} (I)_c - \texttt{mean} _c \right )^2}{N}} \end{array}\f]
625+
\f[\begin{array}{l} N_c = \sum _{I, {\texttt{mask} (I)_c} \ne 0} 1 \\ \texttt{mean} _c = \frac{\sum_{ I: \; {\texttt{mask} (I)_c} \ne 0} \texttt{src} (I)_c}{N_c} \\ \texttt{stddev} _c = \sqrt{\frac{\sum_{ I: \; {\texttt{mask} (I)_c} \ne 0} \left ( \texttt{src} (I)_c - \texttt{mean} _c \right )^2}{N_c}} \end{array}\f]
626626
When all the mask elements are 0's, the function returns
627627
mean=stddev=Scalar::all(0).
628628
@note The calculated standard deviation is only the diagonal of the

modules/core/include/opencv2/core/mat.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,8 +1192,8 @@ class CV_EXPORTS Mat
11921192
/** @overload
11931193
@param m Destination matrix. If it does not have a proper size or type before the operation, it is
11941194
reallocated.
1195-
@param mask Operation mask. Its non-zero elements indicate which matrix elements need to be copied.
1196-
The mask has to be of type CV_8U and can have 1 or multiple channels.
1195+
@param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix
1196+
elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels.
11971197
*/
11981198
void copyTo( OutputArray m, InputArray mask ) const;
11991199

@@ -1229,7 +1229,8 @@ class CV_EXPORTS Mat
12291229
12301230
This is an advanced variant of the Mat::operator=(const Scalar& s) operator.
12311231
@param value Assigned scalar converted to the actual array type.
1232-
@param mask Operation mask of the same size as \*this.
1232+
@param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix
1233+
elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels
12331234
*/
12341235
Mat& setTo(InputArray value, InputArray mask=noArray());
12351236

modules/core/src/copy.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ static bool ipp_copyTo(const Mat &src, Mat &dst, const Mat &mask)
334334
#ifdef HAVE_IPP_IW
335335
CV_INSTRUMENT_REGION_IPP()
336336

337-
if(mask.channels() > 1 && mask.depth() != CV_8U)
337+
if(mask.channels() > 1 || mask.depth() != CV_8U)
338338
return false;
339339

340340
if (src.dims <= 2)
@@ -510,20 +510,23 @@ Mat& Mat::setTo(InputArray _value, InputArray _mask)
510510
Mat value = _value.getMat(), mask = _mask.getMat();
511511

512512
CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::MAT ));
513-
CV_Assert( mask.empty() || (mask.type() == CV_8U && size == mask.size) );
513+
int cn = channels(), mcn = mask.channels();
514+
CV_Assert( mask.empty() || (mask.depth() == CV_8U && (mcn == 1 || mcn == cn) && size == mask.size) );
514515

515516
CV_IPP_RUN_FAST(ipp_Mat_setTo_Mat(*this, value, mask), *this)
516517

517-
size_t esz = elemSize();
518+
size_t esz = mcn > 1 ? elemSize1() : elemSize();
518519
BinaryFunc copymask = getCopyMaskFunc(esz);
519520

520521
const Mat* arrays[] = { this, !mask.empty() ? &mask : 0, 0 };
521522
uchar* ptrs[2]={0,0};
522523
NAryMatIterator it(arrays, ptrs);
523-
int totalsz = (int)it.size, blockSize0 = std::min(totalsz, (int)((BLOCK_SIZE + esz-1)/esz));
524+
int totalsz = (int)it.size*mcn;
525+
int blockSize0 = std::min(totalsz, (int)((BLOCK_SIZE + esz-1)/esz));
526+
blockSize0 -= blockSize0 % mcn; // must be divisible without remainder for unrolling and advancing
524527
AutoBuffer<uchar> _scbuf(blockSize0*esz + 32);
525528
uchar* scbuf = alignPtr((uchar*)_scbuf, (int)sizeof(double));
526-
convertAndUnrollScalar( value, type(), scbuf, blockSize0 );
529+
convertAndUnrollScalar( value, type(), scbuf, blockSize0/mcn );
527530

528531
for( size_t i = 0; i < it.nplanes; i++, ++it )
529532
{

0 commit comments

Comments
 (0)