diff --git a/modules/core/include/opencv2/core.hpp b/modules/core/include/opencv2/core.hpp index b077d06dcd..b50a502f72 100644 --- a/modules/core/include/opencv2/core.hpp +++ b/modules/core/include/opencv2/core.hpp @@ -608,7 +608,7 @@ CV_EXPORTS_W void findNonZero( InputArray src, OutputArray idx ); The function cv::mean calculates the mean value M of array elements, independently for each channel, and return it: -\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] +\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] 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_ . @@ -622,7 +622,7 @@ CV_EXPORTS_W Scalar mean(InputArray src, InputArray mask = noArray()); The function cv::meanStdDev calculates the mean and the standard deviation M of array elements independently for each channel and returns it via the output parameters: -\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] +\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] When all the mask elements are 0's, the function returns mean=stddev=Scalar::all(0). @note The calculated standard deviation is only the diagonal of the diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index 990deb87de..817cacee0b 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 5762e5b69a..c40f795648 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -334,7 +334,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) @@ -510,20 +510,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/src/stat.cpp b/modules/core/src/stat.cpp index a978c90fd2..4fb82b3c56 100644 --- a/modules/core/src/stat.cpp +++ b/modules/core/src/stat.cpp @@ -323,8 +323,11 @@ struct Sum_SIMD #endif template -static int sum_(const T* src0, const uchar* mask, ST* dst, int len, int cn ) +static void sum_(const T* src0, const uchar* mask, ST* dst, int* nzm, int len, int cn, int mcn ) { + for( int k = 0; k < mcn; k++ ) + nzm[k] = 0; + const T* src = src0; if( !mask ) { @@ -383,10 +386,14 @@ static int sum_(const T* src0, const uchar* mask, ST* dst, int len, int cn ) dst[k+2] = s2; dst[k+3] = s3; } - return len; + + if (nzm) + nzm[0] = len; + return; } - int i, nzm = 0; + CV_Assert(mcn >= 1 && nzm); + int i; if( cn == 1 ) { ST s = dst[0]; @@ -394,74 +401,112 @@ static int sum_(const T* src0, const uchar* mask, ST* dst, int len, int cn ) if( mask[i] ) { s += src[i]; - nzm++; + nzm[0]++; } dst[0] = s; } else if( cn == 3 ) { ST s0 = dst[0], s1 = dst[1], s2 = dst[2]; - for( i = 0; i < len; i++, src += 3 ) - if( mask[i] ) + if( mcn == 1 ) + { + for( i = 0; i < len; i++, src += 3 ) + if( mask[i] ) + { + s0 += src[0]; + s1 += src[1]; + s2 += src[2]; + nzm[0]++; + } + } + else + { + CV_Assert(mcn == cn); + for( i = 0; i < len; i++, src += 3, mask += 3 ) { - s0 += src[0]; - s1 += src[1]; - s2 += src[2]; - nzm++; + if( mask[0] ) + { + s0 += src[0]; + nzm[0]++; + } + if( mask[1] ) + { + s1 += src[1]; + nzm[1]++; + } + if( mask[2] ) + { + s2 += src[2]; + nzm[2]++; + } } + } dst[0] = s0; dst[1] = s1; dst[2] = s2; } else { - for( i = 0; i < len; i++, src += cn ) - if( mask[i] ) - { - int k = 0; - #if CV_ENABLE_UNROLLED - for( ; k <= cn - 4; k += 4 ) + if( mcn == 1 ) + { + for( i = 0; i < len; i++, src += cn ) + if( mask[i] ) { - ST s0, s1; - s0 = dst[k] + src[k]; - s1 = dst[k+1] + src[k+1]; - dst[k] = s0; dst[k+1] = s1; - s0 = dst[k+2] + src[k+2]; - s1 = dst[k+3] + src[k+3]; - dst[k+2] = s0; dst[k+3] = s1; + int k = 0; + #if CV_ENABLE_UNROLLED + for( ; k <= cn - 4; k += 4 ) + { + ST s0, s1; + s0 = dst[k] + src[k]; + s1 = dst[k+1] + src[k+1]; + dst[k] = s0; dst[k+1] = s1; + s0 = dst[k+2] + src[k+2]; + s1 = dst[k+3] + src[k+3]; + dst[k+2] = s0; dst[k+3] = s1; + } + #endif + for( ; k < cn; k++ ) + dst[k] += src[k]; + nzm[0]++; } - #endif - for( ; k < cn; k++ ) - dst[k] += src[k]; - nzm++; - } + } + else + { + CV_Assert(mcn == cn); + for( i = 0; i < len; i++, src += cn, mask += cn ) + for( int k = 0; k < cn; k++ ) + if( mask[k] ) + { + dst[k] += src[k]; + nzm[k]++; + } + } } - return nzm; } -static int sum8u( const uchar* src, const uchar* mask, int* dst, int len, int cn ) -{ return sum_(src, mask, dst, len, cn); } +static void sum8u( const uchar* src, const uchar* mask, int* dst, int* nzm, int len, int cn, int mcn ) +{ sum_(src, mask, dst, nzm, len, cn, mcn); } -static int sum8s( const schar* src, const uchar* mask, int* dst, int len, int cn ) -{ return sum_(src, mask, dst, len, cn); } +static void sum8s( const schar* src, const uchar* mask, int* dst, int* nzm, int len, int cn, int mcn ) +{ sum_(src, mask, dst, nzm, len, cn, mcn); } -static int sum16u( const ushort* src, const uchar* mask, int* dst, int len, int cn ) -{ return sum_(src, mask, dst, len, cn); } +static void sum16u( const ushort* src, const uchar* mask, int* dst, int* nzm, int len, int cn, int mcn ) +{ sum_(src, mask, dst, nzm, len, cn, mcn); } -static int sum16s( const short* src, const uchar* mask, int* dst, int len, int cn ) -{ return sum_(src, mask, dst, len, cn); } +static void sum16s( const short* src, const uchar* mask, int* dst, int* nzm, int len, int cn, int mcn ) +{ sum_(src, mask, dst, nzm, len, cn, mcn); } -static int sum32s( const int* src, const uchar* mask, double* dst, int len, int cn ) -{ return sum_(src, mask, dst, len, cn); } +static void sum32s( const int* src, const uchar* mask, double* dst, int* nzm, int len, int cn, int mcn ) +{ sum_(src, mask, dst, nzm, len, cn, mcn); } -static int sum32f( const float* src, const uchar* mask, double* dst, int len, int cn ) -{ return sum_(src, mask, dst, len, cn); } +static void sum32f( const float* src, const uchar* mask, double* dst, int* nzm, int len, int cn, int mcn ) +{ sum_(src, mask, dst, nzm, len, cn, mcn); } -static int sum64f( const double* src, const uchar* mask, double* dst, int len, int cn ) -{ return sum_(src, mask, dst, len, cn); } +static void sum64f( const double* src, const uchar* mask, double* dst, int* nzm, int len, int cn, int mcn ) +{ sum_(src, mask, dst, nzm, len, cn, mcn); } -typedef int (*SumFunc)(const uchar*, const uchar* mask, uchar*, int, int); +typedef void (*SumFunc)(const uchar*, const uchar* mask, uchar*, int*, int, int, int); static SumFunc getSumFunc(int depth) { @@ -850,10 +895,12 @@ struct SumSqr_SIMD #endif template -static int sumsqr_(const T* src0, const uchar* mask, ST* sum, SQT* sqsum, int len, int cn ) +static void sumsqr_(const T* src0, const uchar* mask, ST* sum, SQT* sqsum, int* nzm, int len, int cn, int mcn ) { - const T* src = src0; + for( int k = 0; k < mcn; k++ ) + nzm[k] = 0; + const T* src = src0; if( !mask ) { SumSqr_SIMD vop; @@ -920,11 +967,14 @@ static int sumsqr_(const T* src0, const uchar* mask, ST* sum, SQT* sqsum, int le sqsum[k] = sq0; sqsum[k+1] = sq1; sqsum[k+2] = sq2; sqsum[k+3] = sq3; } - return len; - } - int i, nzm = 0; + if (nzm) + nzm[0] = len; + return; + } + CV_Assert(mcn >= 1 && nzm); + int i; if( cn == 1 ) { ST s0 = sum[0]; @@ -934,7 +984,7 @@ static int sumsqr_(const T* src0, const uchar* mask, ST* sum, SQT* sqsum, int le { T v = src[i]; s0 += v; sq0 += (SQT)v*v; - nzm++; + nzm[0]++; } sum[0] = s0; sqsum[0] = sq0; @@ -943,66 +993,113 @@ static int sumsqr_(const T* src0, const uchar* mask, ST* sum, SQT* sqsum, int le { ST s0 = sum[0], s1 = sum[1], s2 = sum[2]; SQT sq0 = sqsum[0], sq1 = sqsum[1], sq2 = sqsum[2]; - for( i = 0; i < len; i++, src += 3 ) - if( mask[i] ) + if( mcn == 1 ) + { + for( i = 0; i < len; i++, src += 3 ) + if( mask[i] ) + { + T v0 = src[0], v1 = src[1], v2 = src[2]; + s0 += v0; sq0 += (SQT)v0*v0; + s1 += v1; sq1 += (SQT)v1*v1; + s2 += v2; sq2 += (SQT)v2*v2; + nzm[0]++; + } + } + else + { + CV_Assert(mcn == cn); + for( i = 0; i < len; i++, src += 3, mask += 3 ) { - T v0 = src[0], v1 = src[1], v2 = src[2]; - s0 += v0; sq0 += (SQT)v0*v0; - s1 += v1; sq1 += (SQT)v1*v1; - s2 += v2; sq2 += (SQT)v2*v2; - nzm++; + if( mask[0] ) + { + T v0 = src[0]; + s0 += v0; sq0 += (SQT)v0*v0; + nzm[0]++; + } + if( mask[1] ) + { + T v1 = src[1]; + s1 += v1; sq1 += (SQT)v1*v1; + nzm[1]++; + } + if( mask[2] ) + { + T v2 = src[2]; + s2 += v2; sq2 += (SQT)v2*v2; + nzm[2]++; + } } + } sum[0] = s0; sum[1] = s1; sum[2] = s2; sqsum[0] = sq0; sqsum[1] = sq1; sqsum[2] = sq2; } else { - for( i = 0; i < len; i++, src += cn ) - if( mask[i] ) - { - for( int k = 0; k < cn; k++ ) + if( mcn == 1 ) + { + for( i = 0; i < len; i++, src += cn ) + if( mask[i] ) { - T v = src[k]; - ST s = sum[k] + v; - SQT sq = sqsum[k] + (SQT)v*v; - sum[k] = s; sqsum[k] = sq; + for( int k = 0; k < cn; k++ ) + { + T v = src[k]; + ST s = sum[k] + v; + SQT sq = sqsum[k] + (SQT)v*v; + sum[k] = s; sqsum[k] = sq; + } + nzm[0]++; } - nzm++; - } + } + else + { + CV_Assert(mcn == cn); + for( i = 0; i < len; i++, src += cn, mask += cn ) + for( int k = 0; k < cn; k++ ) + if( mask[k] ) + { + T v = src[k]; + ST s = sum[k] + v; + SQT sq = sqsum[k] + (SQT)v*v; + sum[k] = s; sqsum[k] = sq; + nzm[k]++; + } + } } - return nzm; } -static int sqsum8u( const uchar* src, const uchar* mask, int* sum, int* sqsum, int len, int cn ) -{ return sumsqr_(src, mask, sum, sqsum, len, cn); } +static void sqsum8u( const uchar* src, const uchar* mask, int* sum, int* sqsum, int* nzm, int len, int cn, int mcn ) +{ sumsqr_(src, mask, sum, sqsum, nzm, len, cn, mcn); } -static int sqsum8s( const schar* src, const uchar* mask, int* sum, int* sqsum, int len, int cn ) -{ return sumsqr_(src, mask, sum, sqsum, len, cn); } +static void sqsum8s( const schar* src, const uchar* mask, int* sum, int* sqsum, int* nzm, int len, int cn, int mcn ) +{ sumsqr_(src, mask, sum, sqsum, nzm, len, cn, mcn); } -static int sqsum16u( const ushort* src, const uchar* mask, int* sum, double* sqsum, int len, int cn ) -{ return sumsqr_(src, mask, sum, sqsum, len, cn); } +static void sqsum16u( const ushort* src, const uchar* mask, int* sum, double* sqsum, int* nzm, int len, int cn, int mcn ) +{ sumsqr_(src, mask, sum, sqsum, nzm, len, cn, mcn); } -static int sqsum16s( const short* src, const uchar* mask, int* sum, double* sqsum, int len, int cn ) -{ return sumsqr_(src, mask, sum, sqsum, len, cn); } +static void sqsum16s( const short* src, const uchar* mask, int* sum, double* sqsum, int* nzm, int len, int cn, int mcn ) +{ sumsqr_(src, mask, sum, sqsum, nzm, len, cn, mcn); } -static int sqsum32s( const int* src, const uchar* mask, double* sum, double* sqsum, int len, int cn ) -{ return sumsqr_(src, mask, sum, sqsum, len, cn); } +static void sqsum32s( const int* src, const uchar* mask, double* sum, double* sqsum, int* nzm, int len, int cn, int mcn ) +{ sumsqr_(src, mask, sum, sqsum, nzm, len, cn, mcn); } -static int sqsum32f( const float* src, const uchar* mask, double* sum, double* sqsum, int len, int cn ) -{ return sumsqr_(src, mask, sum, sqsum, len, cn); } +static void sqsum32f( const float* src, const uchar* mask, double* sum, double* sqsum, int* nzm, int len, int cn, int mcn ) +{ sumsqr_(src, mask, sum, sqsum, nzm, len, cn, mcn); } -static int sqsum64f( const double* src, const uchar* mask, double* sum, double* sqsum, int len, int cn ) -{ return sumsqr_(src, mask, sum, sqsum, len, cn); } +static void sqsum64f( const double* src, const uchar* mask, double* sum, double* sqsum, int* nzm, int len, int cn, int mcn ) +{ sumsqr_(src, mask, sum, sqsum, nzm, len, cn, mcn); } -typedef int (*SumSqrFunc)(const uchar*, const uchar* mask, uchar*, uchar*, int, int); +typedef int (*SumSqrFunc)(const uchar*, const uchar* mask, uchar*, uchar*, int*, int, int, int); static SumSqrFunc getSumSqrTab(int depth) { static SumSqrFunc sumSqrTab[] = { - (SumSqrFunc)GET_OPTIMIZED(sqsum8u), (SumSqrFunc)sqsum8s, (SumSqrFunc)sqsum16u, (SumSqrFunc)sqsum16s, - (SumSqrFunc)sqsum32s, (SumSqrFunc)GET_OPTIMIZED(sqsum32f), (SumSqrFunc)sqsum64f, 0 + (SumSqrFunc)GET_OPTIMIZED(sqsum8u), (SumSqrFunc)sqsum8s, + (SumSqrFunc)sqsum16u, (SumSqrFunc)sqsum16s, + (SumSqrFunc)sqsum32s, + (SumSqrFunc)GET_OPTIMIZED(sqsum32f), (SumSqrFunc)sqsum64f, + 0 }; return sumSqrTab[depth]; @@ -1226,7 +1323,7 @@ cv::Scalar cv::sum( InputArray _src ) for( j = 0; j < total; j += blockSize ) { int bsz = std::min(total - j, blockSize); - func( ptrs[0], 0, (uchar*)buf, bsz, cn ); + func( ptrs[0], 0, (uchar*)buf, 0, bsz, cn, 0 ); count += bsz; if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) ) { @@ -1390,6 +1487,8 @@ namespace cv static bool ipp_mean( Mat &src, Mat &mask, Scalar &ret ) { CV_INSTRUMENT_REGION_IPP() + if( mask.channels() > 1 ) + return false; #if IPP_VERSION_X100 >= 700 size_t total_size = src.total(); @@ -1485,11 +1584,10 @@ cv::Scalar cv::mean( InputArray _src, InputArray _mask ) CV_INSTRUMENT_REGION() Mat src = _src.getMat(), mask = _mask.getMat(); - CV_Assert( mask.empty() || mask.type() == CV_8U ); + int k, cn = src.channels(), depth = src.depth(), mcn = mask.channels(); + CV_Assert( mask.empty() || (mask.depth() == CV_8U && (mcn == 1 || mcn == cn)) ); - int k, cn = src.channels(), depth = src.depth(); Scalar s; - CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_mean(src, mask, s), s) SumFunc func = getSumFunc(depth); @@ -1500,11 +1598,22 @@ cv::Scalar cv::mean( InputArray _src, InputArray _mask ) uchar* ptrs[2]; NAryMatIterator it(arrays, ptrs); int total = (int)it.size, blockSize = total, intSumBlockSize = 0; - int j, count = 0; - AutoBuffer _buf; + int j; + AutoBuffer _count(mcn), _nz(mcn); + int* count = _count; + int* nz = _nz; + AutoBuffer _buf; int* buf = (int*)&s[0]; bool blockSum = depth <= CV_16S; - size_t esz = 0, nz0 = 0; + size_t esz = 0, mesz = 0; + AutoBuffer _nz0(mcn); + size_t* nz0 = _nz0; + + for( k = 0; k < mcn; k++ ) + { + count[k] = 0; + nz0[k] = 0; + } if( blockSum ) { @@ -1516,6 +1625,7 @@ cv::Scalar cv::mean( InputArray _src, InputArray _mask ) for( k = 0; k < cn; k++ ) buf[k] = 0; esz = src.elemSize(); + mesz = mask.elemSize(); } for( size_t i = 0; i < it.nplanes; i++, ++it ) @@ -1523,24 +1633,38 @@ cv::Scalar cv::mean( InputArray _src, InputArray _mask ) for( j = 0; j < total; j += blockSize ) { int bsz = std::min(total - j, blockSize); - int nz = func( ptrs[0], ptrs[1], (uchar*)buf, bsz, cn ); - count += nz; - nz0 += nz; - if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) ) + func( ptrs[0], ptrs[1], (uchar*)buf, nz, bsz, cn, mcn ); + + bool doCommit = false; + for( k = 0; k < mcn; k++ ) + { + nz0[k] += nz[k]; + count[k] += nz[k]; + if( count[k] + blockSize >= intSumBlockSize ) + doCommit = true; + } + if( blockSum && (doCommit || (i+1 >= it.nplanes && j+bsz >= total)) ) { for( k = 0; k < cn; k++ ) { s[k] += buf[k]; buf[k] = 0; } - count = 0; + for( k = 0; k < mcn; k++ ) + count[k] = 0; } ptrs[0] += bsz*esz; if( ptrs[1] ) - ptrs[1] += bsz; + ptrs[1] += bsz*mesz; } } - return s*(nz0 ? 1./nz0 : 0); + + if( mcn == cn ) + for( k = 0; k < cn; k++ ) + s[k] *= nz0[k] ? 1./nz0[k] : 0; + else + s *= nz0[0] ? 1./nz0[0] : 0; + return s; } #ifdef HAVE_OPENCL @@ -1557,6 +1681,8 @@ static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv const int cn = _src.channels(); if (cn > 4) return false; + if (_mask.channels() > 1) + return false; { int type = _src.type(), depth = CV_MAT_DEPTH(type); @@ -1743,6 +1869,9 @@ static bool ipp_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& m { CV_INSTRUMENT_REGION_IPP() + if( mask.channels() > 1 ) + return false; + #if IPP_VERSION_X100 >= 700 int cn = src.channels(); @@ -1866,14 +1995,14 @@ void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, Input ocl_meanStdDev(_src, _mean, _sdv, _mask)) Mat src = _src.getMat(), mask = _mask.getMat(); - CV_Assert( mask.empty() || mask.type() == CV_8UC1 ); + int k, cn = src.channels(), depth = src.depth(), mcn = mask.channels(); + CV_Assert( mask.empty() || (mask.depth() == CV_8U && (mcn == 1 || mcn == cn)) ); CV_OVX_RUN(!ovx::skipSmallImages(src.cols, src.rows), openvx_meanStdDev(src, _mean, _sdv, mask)) CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_meanStdDev(src, _mean, _sdv, mask)); - int k, cn = src.channels(), depth = src.depth(); SumSqrFunc func = getSumSqrTab(depth); @@ -1883,12 +2012,23 @@ void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, Input uchar* ptrs[2]; NAryMatIterator it(arrays, ptrs); int total = (int)it.size, blockSize = total, intSumBlockSize = 0; - int j, count = 0, nz0 = 0; + int j; + AutoBuffer _count(mcn), _nz(mcn); + int* count = _count; + int* nz = _nz; AutoBuffer _buf(cn*4); double *s = (double*)_buf, *sq = s + cn; int *sbuf = (int*)s, *sqbuf = (int*)sq; bool blockSum = depth <= CV_16S, blockSqSum = depth <= CV_8S; - size_t esz = 0; + size_t esz = 0, mesz = 0; + AutoBuffer _nz0(mcn); + size_t* nz0 = _nz0; + + for( k = 0; k < mcn; k++ ) + { + count[k] = 0; + nz0[k] = 0; + } for( k = 0; k < cn; k++ ) s[k] = sq[k] = 0; @@ -1903,6 +2043,7 @@ void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, Input for( k = 0; k < cn; k++ ) sbuf[k] = sqbuf[k] = 0; esz = src.elemSize(); + mesz = mask.elemSize(); } for( size_t i = 0; i < it.nplanes; i++, ++it ) @@ -1910,10 +2051,17 @@ void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, Input for( j = 0; j < total; j += blockSize ) { int bsz = std::min(total - j, blockSize); - int nz = func( ptrs[0], ptrs[1], (uchar*)sbuf, (uchar*)sqbuf, bsz, cn ); - count += nz; - nz0 += nz; - if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) ) + func( ptrs[0], ptrs[1], (uchar*)sbuf, (uchar*)sqbuf, nz, bsz, cn, mcn ); + + bool doCommit = false; + for( k = 0; k < mcn; k++ ) + { + nz0[k] += nz[k]; + count[k] += nz[k]; + if( count[k] + blockSize >= intSumBlockSize ) + doCommit = true; + } + if( blockSum && (doCommit || (i+1 >= it.nplanes && j+bsz >= total)) ) { for( k = 0; k < cn; k++ ) { @@ -1928,19 +2076,29 @@ void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, Input sqbuf[k] = 0; } } - count = 0; + for( k = 0; k < mcn; k++ ) + count[k] = 0; } ptrs[0] += bsz*esz; if( ptrs[1] ) - ptrs[1] += bsz; + ptrs[1] += bsz*mesz; } } - double scale = nz0 ? 1./nz0 : 0.; - for( k = 0; k < cn; k++ ) + if( mcn == cn ) + for( k = 0; k < cn; k++ ) { + double scale = nz0[k] ? 1./nz0[k] : 0; + s[k] *= scale; + sq[k] = std::sqrt(std::max(sq[k]*scale - s[k]*s[k], 0.)); + } + else { - s[k] *= scale; - sq[k] = std::sqrt(std::max(sq[k]*scale - s[k]*s[k], 0.)); + double scale = nz0[0] ? 1./nz0[0] : 0.; + for( k = 0; k < cn; k++ ) + { + s[k] *= scale; + sq[k] = std::sqrt(std::max(sq[k]*scale - s[k]*s[k], 0.)); + } } for( j = 0; j < 2; j++ ) diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index 78c0689852..f1bc834be1 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); @@ -1162,7 +1162,7 @@ struct CartToPolarToCartOp : public BaseElemWiseOp struct MeanOp : public BaseElemWiseOp { - MeanOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0)) + MeanOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SUPPORT_MULTICHANNELMASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0)) { context = 3; }; @@ -1244,7 +1244,7 @@ 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)) + MeanStdDevOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SUPPORT_MULTICHANNELMASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0)) { cn = 0; context = 7; @@ -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..a82c6a9403 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]; + } } } } @@ -2574,11 +2598,11 @@ void divide(const Mat& src1, const Mat& src2, Mat& dst, double scale) template static void -mean_(const _Tp* src, const uchar* mask, size_t total, int cn, Scalar& sum, int& nz) +mean_(const _Tp* src, const uchar* mask, size_t total, int cn, int mcn, Scalar& sum, Scalar_& nz) { if( !mask ) { - nz += (int)total; + nz += Scalar_::all((int)total); total *= cn; for( size_t i = 0; i < total; i += cn ) { @@ -2586,23 +2610,41 @@ mean_(const _Tp* src, const uchar* mask, size_t total, int cn, Scalar& sum, int& sum[c] += src[i + c]; } } - else + else if( mcn == 1 ) { for( size_t i = 0; i < total; i++ ) if( mask[i] ) { - nz++; for( int c = 0; c < cn; c++ ) + { + nz[c]++; sum[c] += src[i*cn + c]; + } + } + } + else + { + total *= cn; + for( size_t i = 0; i < total; i += cn ) + { + for( int c = 0; c < cn; c++ ) + { + if( mask[i + c] ) + { + nz[c]++; + sum[c] += src[i + c]; + } } + } } } 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.depth() == CV_8U && mask.size == src.size && + (mask.channels() == 1 || mask.channels() == src.channels()))); Scalar sum; - int nz = 0; + Scalar_ nz = Scalar_::all(0); const Mat *arrays[]={&src, &mask, 0}; Mat planes[2]; @@ -2610,7 +2652,7 @@ Scalar mean(const Mat& src, const Mat& mask) NAryMatIterator it(arrays, planes); size_t total = planes[0].total(); size_t i, nplanes = it.nplanes; - int depth = src.depth(), cn = src.channels(); + int c, depth = src.depth(), cn = src.channels(), mcn = mask.channels(); for( i = 0; i < nplanes; i++, ++it ) { @@ -2620,32 +2662,34 @@ Scalar mean(const Mat& src, const Mat& mask) switch( depth ) { case CV_8U: - mean_((const uchar*)sptr, mptr, total, cn, sum, nz); + mean_((const uchar*)sptr, mptr, total, cn, mcn, sum, nz); break; case CV_8S: - mean_((const schar*)sptr, mptr, total, cn, sum, nz); + mean_((const schar*)sptr, mptr, total, cn, mcn, sum, nz); break; case CV_16U: - mean_((const ushort*)sptr, mptr, total, cn, sum, nz); + mean_((const ushort*)sptr, mptr, total, cn, mcn, sum, nz); break; case CV_16S: - mean_((const short*)sptr, mptr, total, cn, sum, nz); + mean_((const short*)sptr, mptr, total, cn, mcn, sum, nz); break; case CV_32S: - mean_((const int*)sptr, mptr, total, cn, sum, nz); + mean_((const int*)sptr, mptr, total, cn, mcn, sum, nz); break; case CV_32F: - mean_((const float*)sptr, mptr, total, cn, sum, nz); + mean_((const float*)sptr, mptr, total, cn, mcn, sum, nz); break; case CV_64F: - mean_((const double*)sptr, mptr, total, cn, sum, nz); + mean_((const double*)sptr, mptr, total, cn, mcn, sum, nz); break; default: CV_Error(Error::StsUnsupportedFormat, ""); } } - return sum * (1./std::max(nz, 1)); + for( c = 0; c < cn; c++ ) + sum[c] *= (1./std::max(nz[c], 1)); + return sum; }