/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "precomp.hpp" namespace cv { template static inline Scalar rawToScalar(const T& v) { Scalar s; typedef typename DataType::channel_type T1; int i, n = DataType::channels; for( i = 0; i < n; i++ ) s.val[i] = ((T1*)&v)[i]; return s; } /****************************************************************************************\ * sum * \****************************************************************************************/ template static Scalar sumBlock_( const Mat& srcmat ) { assert( DataType::type == srcmat.type() ); Size size = getContinuousSize( srcmat ); ST s0 = 0; WT s = 0; int y, remaining = BLOCK_SIZE; for( y = 0; y < size.height; y++ ) { const T* src = (const T*)(srcmat.data + srcmat.step*y); int x = 0; while( x < size.width ) { int limit = std::min( remaining, size.width - x ); remaining -= limit; limit += x; for( ; x <= limit - 4; x += 4 ) { s += src[x]; s += src[x+1]; s += src[x+2]; s += src[x+3]; } for( ; x < limit; x++ ) s += src[x]; if( remaining == 0 || (x == size.width && y == size.height-1) ) { s0 += s; s = 0; remaining = BLOCK_SIZE; } } } return rawToScalar(s0); } template static Scalar sum_( const Mat& srcmat ) { assert( DataType::type == srcmat.type() ); Size size = getContinuousSize( srcmat ); ST s = 0; for( int y = 0; y < size.height; y++ ) { const T* src = (const T*)(srcmat.data + srcmat.step*y); int x = 0; for( ; x <= size.width - 4; x += 4 ) { s += src[x]; s += src[x+1]; s += src[x+2]; s += src[x+3]; } for( ; x < size.width; x++ ) s += src[x]; } return rawToScalar(s); } typedef Scalar (*SumFunc)(const Mat& src); Scalar sum( const Mat& m ) { static SumFunc tab[]= { sumBlock_, sumBlock_, sumBlock_, sumBlock_, sum_, sum_, sum_, 0, sumBlock_, Vec, Vec, 1<<23>, sumBlock_, Vec, Vec, 1<<24>, sumBlock_, Vec, Vec, 1<<15>, sumBlock_, Vec, Vec, 1<<16>, sum_, Vec >, sum_, Vec >, sum_, Vec >, 0, sumBlock_, Vec, Vec, 1<<23>, sumBlock_, Vec, Vec, 1<<24>, sumBlock_, Vec, Vec, 1<<15>, sumBlock_, Vec, Vec, 1<<16>, sum_, Vec >, sum_, Vec >, sum_, Vec >, 0, sumBlock_, Vec, Vec, 1<<23>, sumBlock_, Vec, Vec, 1<<24>, sumBlock_, Vec, Vec, 1<<15>, sumBlock_, Vec, Vec, 1<<16>, sum_, Vec >, sum_, Vec >, sum_, Vec >, 0 }; CV_Assert( m.channels() <= 4 ); SumFunc func = tab[m.type()]; CV_Assert( func != 0 ); if( m.dims > 2 ) { const Mat* arrays[] = {&m, 0}; Mat planes[1]; NAryMatIterator it(arrays, planes); Scalar s; for( int i = 0; i < it.nplanes; i++, ++it ) s += func(it.planes[0]); return s; } return func(m); } /****************************************************************************************\ * countNonZero * \****************************************************************************************/ template static int countNonZero_( const Mat& srcmat ) { //assert( DataType::type == srcmat.type() ); const T* src = (const T*)srcmat.data; size_t step = srcmat.step/sizeof(src[0]); Size size = getContinuousSize( srcmat ); int nz = 0; for( ; size.height--; src += step ) { int x = 0; for( ; x <= size.width - 4; x += 4 ) nz += (src[x] != 0) + (src[x+1] != 0) + (src[x+2] != 0) + (src[x+3] != 0); for( ; x < size.width; x++ ) nz += src[x] != 0; } return nz; } typedef int (*CountNonZeroFunc)(const Mat& src); int countNonZero( const Mat& m ) { static CountNonZeroFunc tab[] = { countNonZero_, countNonZero_, countNonZero_, countNonZero_, countNonZero_, countNonZero_, countNonZero_, 0 }; CountNonZeroFunc func = tab[m.depth()]; CV_Assert( m.channels() == 1 && func != 0 ); if( m.dims > 2 ) { const Mat* arrays[] = {&m, 0}; Mat planes[1]; NAryMatIterator it(arrays, planes); int nz = 0; for( int i = 0; i < it.nplanes; i++, ++it ) nz += func(it.planes[0]); return nz; } return func(m); } /****************************************************************************************\ * mean * \****************************************************************************************/ template static Scalar meanBlock_( const Mat& srcmat, const Mat& maskmat ) { assert( DataType::type == srcmat.type() && CV_8U == maskmat.type() && srcmat.size() == maskmat.size() ); Size size = getContinuousSize( srcmat, maskmat ); ST s0 = 0; WT s = 0; int y, remaining = BLOCK_SIZE, pix = 0; for( y = 0; y < size.height; y++ ) { const T* src = (const T*)(srcmat.data + srcmat.step*y); const uchar* mask = maskmat.data + maskmat.step*y; int x = 0; while( x < size.width ) { int limit = std::min( remaining, size.width - x ); remaining -= limit; limit += x; for( ; x < limit; x++ ) if( mask[x] ) s += src[x], pix++; if( remaining == 0 || (x == size.width && y == size.height-1) ) { s0 += s; s = 0; remaining = BLOCK_SIZE; } } } return rawToScalar(s0)*(1./std::max(pix, 1)); } template static Scalar mean_( const Mat& srcmat, const Mat& maskmat ) { assert( DataType::type == srcmat.type() && CV_8U == maskmat.type() && srcmat.size() == maskmat.size() ); Size size = getContinuousSize( srcmat, maskmat ); ST s = 0; int y, pix = 0; for( y = 0; y < size.height; y++ ) { const T* src = (const T*)(srcmat.data + srcmat.step*y); const uchar* mask = maskmat.data + maskmat.step*y; for( int x = 0; x < size.width; x++ ) if( mask[x] ) s += src[x], pix++; } return rawToScalar(s)*(1./std::max(pix, 1)); } typedef Scalar (*MeanMaskFunc)(const Mat& src, const Mat& mask); Scalar mean(const Mat& m) { return sum(m)*(1./m.total()); } Scalar mean( const Mat& m, const Mat& mask ) { static MeanMaskFunc tab[]= { meanBlock_, 0, meanBlock_, meanBlock_, mean_, mean_, mean_, 0, meanBlock_, Vec, Vec, 1<<23>, 0, meanBlock_, Vec, Vec, 1<<15>, meanBlock_, Vec, Vec, 1<<16>, mean_, Vec >, mean_, Vec >, mean_, Vec >, 0, meanBlock_, Vec, Vec, 1<<23>, 0, meanBlock_, Vec, Vec, 1<<15>, meanBlock_, Vec, Vec, 1<<16>, mean_, Vec >, mean_, Vec >, mean_, Vec >, 0, meanBlock_, Vec, Vec, 1<<23>, 0, meanBlock_, Vec, Vec, 1<<15>, meanBlock_, Vec, Vec, 1<<16>, mean_, Vec >, mean_, Vec >, mean_, Vec >, 0 }; if( !mask.data ) return mean(m); CV_Assert( m.channels() <= 4 && mask.type() == CV_8U ); MeanMaskFunc func = tab[m.type()]; CV_Assert( func != 0 ); if( m.dims > 2 ) { const Mat* arrays[] = {&m, &mask, 0}; Mat planes[2]; NAryMatIterator it(arrays, planes); double total = 0; Scalar s; for( int i = 0; i < it.nplanes; i++, ++it ) { int n = countNonZero(it.planes[1]); s += mean(it.planes[0], it.planes[1])*(double)n; total += n; } return (s * 1./std::max(total, 1.)); } CV_Assert( m.size() == mask.size() ); return func( m, mask ); } /****************************************************************************************\ * meanStdDev * \****************************************************************************************/ template struct SqrC1 { typedef T type1; typedef SqT rtype; rtype operator()(type1 x) const { return (SqT)x*x; } }; template struct SqrC2 { typedef Vec type1; typedef Vec rtype; rtype operator()(const type1& x) const { return rtype((SqT)x[0]*x[0], (SqT)x[1]*x[1]); } }; template struct SqrC3 { typedef Vec type1; typedef Vec rtype; rtype operator()(const type1& x) const { return rtype((SqT)x[0]*x[0], (SqT)x[1]*x[1], (SqT)x[2]*x[2]); } }; template struct SqrC4 { typedef Vec type1; typedef Vec rtype; rtype operator()(const type1& x) const { return rtype((SqT)x[0]*x[0], (SqT)x[1]*x[1], (SqT)x[2]*x[2], (SqT)x[3]*x[3]); } }; template<> inline double SqrC1::operator()(uchar x) const { return CV_SQR_8U(x); } template<> inline Vec SqrC2::operator()(const Vec& x) const { return Vec(CV_SQR_8U(x[0]), CV_SQR_8U(x[1])); } template<> inline Vec SqrC3::operator() (const Vec& x) const { return Vec(CV_SQR_8U(x[0]), CV_SQR_8U(x[1]), CV_SQR_8U(x[2])); } template<> inline Vec SqrC4::operator() (const Vec& x) const { return Vec(CV_SQR_8U(x[0]), CV_SQR_8U(x[1]), CV_SQR_8U(x[2]), CV_SQR_8U(x[3])); } template static void meanStdDev_( const Mat& srcmat, Scalar& _sum, Scalar& _sqsum ) { SqrOp sqr; typedef typename SqrOp::type1 T; typedef typename SqrOp::rtype ST; typedef typename DataType::channel_type ST1; assert( DataType::type == srcmat.type() ); Size size = getContinuousSize( srcmat ); ST s = 0, sq = 0; for( int y = 0; y < size.height; y++ ) { const T* src = (const T*)(srcmat.data + srcmat.step*y); for( int x = 0; x < size.width; x++ ) { T v = src[x]; s += v; sq += sqr(v); } } _sum = rawToScalar(s); _sqsum = rawToScalar(sq); } template static void meanStdDevMask_( const Mat& srcmat, const Mat& maskmat, Scalar& _sum, Scalar& _sqsum, int& _nz ) { SqrOp sqr; typedef typename SqrOp::type1 T; typedef typename SqrOp::rtype ST; typedef typename DataType::channel_type ST1; assert( DataType::type == srcmat.type() && CV_8U == maskmat.type() && srcmat.size() == maskmat.size() ); Size size = getContinuousSize( srcmat, maskmat ); ST s = 0, sq = 0; int pix = 0; for( int y = 0; y < size.height; y++ ) { const T* src = (const T*)(srcmat.data + srcmat.step*y); const uchar* mask = maskmat.data + maskmat.step*y; for( int x = 0; x < size.width; x++ ) if( mask[x] ) { T v = src[x]; s += v; sq += sqr(v); pix++; } } _sum = rawToScalar(s); _sqsum = rawToScalar(sq); _nz = pix; } typedef void (*MeanStdDevFunc)(const Mat& src, Scalar& s, Scalar& sq); typedef void (*MeanStdDevMaskFunc)(const Mat& src, const Mat& mask, Scalar& s, Scalar& sq, int& nz); void meanStdDev( const Mat& m, Scalar& mean, Scalar& stddev, const Mat& mask ) { static MeanStdDevFunc tab[]= { meanStdDev_ >, 0, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, 0, meanStdDev_ >, 0, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, 0, meanStdDev_ >, 0, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, 0, meanStdDev_ >, 0, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, meanStdDev_ >, 0 }; static MeanStdDevMaskFunc mtab[]= { meanStdDevMask_ >, 0, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, 0, meanStdDevMask_ >, 0, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, 0, meanStdDevMask_ >, 0, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, 0, meanStdDevMask_ >, 0, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, meanStdDevMask_ >, 0 }; CV_Assert( m.channels() <= 4 && (mask.empty() || mask.type() == CV_8U) ); Scalar sum, sqsum; int total = 0; MeanStdDevFunc func = tab[m.type()]; MeanStdDevMaskFunc mfunc = mtab[m.type()]; CV_Assert( func != 0 && mfunc != 0 ); if( m.dims > 2 ) { const Mat* arrays[] = {&m, &mask, 0}; Mat planes[2]; NAryMatIterator it(arrays, planes); int nz = (int)planes[0].total(); for( int i = 0; i < it.nplanes; i++, ++it ) { Scalar s, sq; if( mask.empty() ) func(it.planes[0], s, sq); else mfunc(it.planes[0], it.planes[1], s, sq, nz); total += nz; sum += s; sqsum += sq; } } else { if( mask.data ) { CV_Assert( mask.size() == m.size() ); mfunc( m, mask, sum, sqsum, total ); } else { func( m, sum, sqsum ); total = (int)m.total(); } } double scale = 1./std::max(total, 1); for( int k = 0; k < 4; k++ ) { mean[k] = sum[k]*scale; stddev[k] = std::sqrt(std::max(sqsum[k]*scale - mean[k]*mean[k], 0.)); } } /****************************************************************************************\ * minMaxLoc * \****************************************************************************************/ template static void minMaxIndx_( const Mat& srcmat, double* _minVal, double* _maxVal, size_t startIdx, size_t* _minIdx, size_t* _maxIdx ) { assert( DataType::type == srcmat.type() ); const T* src = (const T*)srcmat.data; size_t step = srcmat.step/sizeof(src[0]); WT minVal = saturate_cast(*_minVal), maxVal = saturate_cast(*_maxVal); size_t minIdx = *_minIdx, maxIdx = *_maxIdx; Size size = getContinuousSize( srcmat ); for( ; size.height--; src += step, startIdx += size.width ) { for( int x = 0; x < size.width; x++ ) { T val = src[x]; if( val < minVal ) { minVal = val; minIdx = startIdx + x; } if( val > maxVal ) { maxVal = val; maxIdx = startIdx + x; } } } *_minIdx = minIdx; *_maxIdx = maxIdx; *_minVal = minVal; *_maxVal = maxVal; } template static void minMaxIndxMask_( const Mat& srcmat, const Mat& maskmat, double* _minVal, double* _maxVal, size_t startIdx, size_t* _minIdx, size_t* _maxIdx ) { assert( DataType::type == srcmat.type() && CV_8U == maskmat.type() && srcmat.size() == maskmat.size() ); const T* src = (const T*)srcmat.data; const uchar* mask = maskmat.data; size_t step = srcmat.step/sizeof(src[0]); size_t maskstep = maskmat.step; WT minVal = saturate_cast(*_minVal), maxVal = saturate_cast(*_maxVal); size_t minIdx = *_minIdx, maxIdx = *_maxIdx; Size size = getContinuousSize( srcmat, maskmat ); for( ; size.height--; src += step, mask += maskstep, startIdx += size.width ) { for( int x = 0; x < size.width; x++ ) { T val = src[x]; int m = mask[x]; if( val < minVal && m ) { minVal = val; minIdx = startIdx + x; } if( val > maxVal && m ) { maxVal = val; maxIdx = startIdx + x; } } } *_minIdx = minIdx; *_maxIdx = maxIdx; *_minVal = minVal; *_maxVal = maxVal; } typedef void (*MinMaxIndxFunc)(const Mat&, double*, double*, size_t, size_t*, size_t*); typedef void (*MinMaxIndxMaskFunc)(const Mat&, const Mat&, double*, double*, size_t, size_t*, size_t*); void minMaxLoc( const Mat& img, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc, const Mat& mask ) { CV_Assert(img.dims <= 2); static MinMaxIndxFunc tab[] = { minMaxIndx_, 0, minMaxIndx_, minMaxIndx_, minMaxIndx_, minMaxIndx_, minMaxIndx_, 0 }; static MinMaxIndxMaskFunc tabm[] = { minMaxIndxMask_, 0, minMaxIndxMask_, minMaxIndxMask_, minMaxIndxMask_, minMaxIndxMask_, minMaxIndxMask_, 0 }; int depth = img.depth(); double minval = depth < CV_32F ? INT_MAX : depth == CV_32F ? FLT_MAX : DBL_MAX; double maxval = depth < CV_32F ? INT_MIN : depth == CV_32F ? -FLT_MAX : -DBL_MAX; size_t minidx = 0, maxidx = 0, startidx = 1; CV_Assert( img.channels() == 1 ); if( !mask.data ) { MinMaxIndxFunc func = tab[depth]; CV_Assert( func != 0 ); func( img, &minval, &maxval, startidx, &minidx, &maxidx ); } else { CV_Assert( img.size() == mask.size() && mask.type() == CV_8U ); MinMaxIndxMaskFunc func = tabm[depth]; CV_Assert( func != 0 ); func( img, mask, &minval, &maxval, startidx, &minidx, &maxidx ); } if( minidx == 0 ) minVal = maxVal = 0; if( minVal ) *minVal = minval; if( maxVal ) *maxVal = maxval; if( minLoc ) { if( minidx > 0 ) { minidx--; minLoc->y = minidx/img.cols; minLoc->x = minidx - minLoc->y*img.cols; } else minLoc->x = minLoc->y = -1; } if( maxLoc ) { if( maxidx > 0 ) { maxidx--; maxLoc->y = maxidx/img.cols; maxLoc->x = maxidx - maxLoc->y*img.cols; } else maxLoc->x = maxLoc->y = -1; } } static void ofs2idx(const Mat& a, size_t ofs, int* idx) { int i, d = a.dims; if( ofs > 0 ) { ofs--; for( i = d-1; i >= 0; i-- ) { int sz = a.size[i]; idx[i] = (int)(ofs % sz); ofs /= sz; } } else { for( i = d-1; i >= 0; i-- ) idx[i] = -1; } } void minMaxIdx(const Mat& a, double* minVal, double* maxVal, int* minIdx, int* maxIdx, const Mat& mask) { if( a.dims <= 2 ) { Point minLoc, maxLoc; minMaxLoc(a, minVal, maxVal, &minLoc, &maxLoc, mask); if( minIdx ) minIdx[0] = minLoc.y, minIdx[1] = minLoc.x; if( maxIdx ) maxIdx[0] = maxLoc.y, maxIdx[1] = maxLoc.x; return; } static MinMaxIndxFunc tab[] = { minMaxIndx_, 0, minMaxIndx_, minMaxIndx_, minMaxIndx_, minMaxIndx_, minMaxIndx_, 0 }; static MinMaxIndxMaskFunc tabm[] = { minMaxIndxMask_, 0, minMaxIndxMask_, minMaxIndxMask_, minMaxIndxMask_, minMaxIndxMask_, minMaxIndxMask_, 0 }; const Mat* arrays[] = {&a, &mask, 0}; Mat planes[2]; NAryMatIterator it(arrays, planes); int depth = a.depth(); double minval = depth < CV_32F ? INT_MAX : depth == CV_32F ? FLT_MAX : DBL_MAX; double maxval = depth < CV_32F ? INT_MIN : depth == CV_32F ? -FLT_MAX : -DBL_MAX; size_t minidx = 0, maxidx = 0; size_t startidx = 1, planeSize = planes[0].total(); MinMaxIndxFunc func = 0; MinMaxIndxMaskFunc mfunc = 0; if( mask.empty() ) func = tab[depth]; else mfunc = tabm[depth]; CV_Assert( func != 0 || mfunc != 0 ); for( int i = 0; i < it.nplanes; i++, ++it, startidx += planeSize ) { if( func ) func( planes[0], &minval, &maxval, startidx, &minidx, &maxidx ); else mfunc( planes[0], planes[1], &minval, &maxval, startidx, &minidx, &maxidx ); } if( minidx == 0 ) minVal = maxVal = 0; if( minVal ) *minVal = minval; if( maxVal ) *maxVal = maxval; if( minIdx ) ofs2idx(a, minidx, minIdx); if( maxIdx ) ofs2idx(a, maxidx, maxIdx); } /****************************************************************************************\ * norm * \****************************************************************************************/ template struct OpAbs { typedef T type1; typedef WT rtype; rtype operator()(type1 x) const { return (WT)std::abs(x); } }; template<> inline uchar OpAbs::operator()(uchar x) const { return x; } template<> inline ushort OpAbs::operator()(ushort x) const { return x; } template static double normBlock_( const Mat& srcmat ) { ElemFunc f; UpdateFunc update; GlobUpdateFunc globUpdate; typedef typename ElemFunc::type1 T; typedef typename UpdateFunc::rtype WT; typedef typename GlobUpdateFunc::rtype ST; assert( DataType::depth == srcmat.depth() ); Size size = getContinuousSize( srcmat, srcmat.channels() ); ST s0 = 0; // luckily, 0 is the correct starting value for both + and max update operations WT s = 0; int y, remaining = BLOCK_SIZE; for( y = 0; y < size.height; y++ ) { const T* src = (const T*)(srcmat.data + srcmat.step*y); int x = 0; while( x < size.width ) { int limit = std::min( remaining, size.width - x ); remaining -= limit; limit += x; for( ; x <= limit - 4; x += 4 ) { s = update(s, (WT)f(src[x])); s = update(s, (WT)f(src[x+1])); s = update(s, (WT)f(src[x+2])); s = update(s, (WT)f(src[x+3])); } for( ; x < limit; x++ ) s = update(s, (WT)f(src[x])); if( remaining == 0 || (x == size.width && y == size.height-1) ) { s0 = globUpdate(s0, (ST)s); s = 0; remaining = BLOCK_SIZE; } } } return s0; } template static double norm_( const Mat& srcmat ) { ElemFunc f; UpdateFunc update; typedef typename ElemFunc::type1 T; typedef typename UpdateFunc::rtype ST; assert( DataType::depth == srcmat.depth() ); Size size = getContinuousSize( srcmat, srcmat.channels() ); ST s = 0; for( int y = 0; y < size.height; y++ ) { const T* src = (const T*)(srcmat.data + srcmat.step*y); int x = 0; for( ; x <= size.width - 4; x += 4 ) { s = update(s, (ST)f(src[x])); s = update(s, (ST)f(src[x+1])); s = update(s, (ST)f(src[x+2])); s = update(s, (ST)f(src[x+3])); } for( ; x < size.width; x++ ) s = update(s, (ST)f(src[x])); } return s; } template static double normMaskBlock_( const Mat& srcmat, const Mat& maskmat ) { ElemFunc f; UpdateFunc update; GlobUpdateFunc globUpdate; typedef typename ElemFunc::type1 T; typedef typename UpdateFunc::rtype WT; typedef typename GlobUpdateFunc::rtype ST; assert( DataType::depth == srcmat.depth() ); Size size = getContinuousSize( srcmat, maskmat ); ST s0 = 0; WT s = 0; int y, remaining = BLOCK_SIZE; int cn = srcmat.channels(); for( y = 0; y < size.height; y++ ) { const T* src = (const T*)(srcmat.data + srcmat.step*y); const uchar* mask = maskmat.data + maskmat.step*y; int x = 0; while( x < size.width ) { int limit = std::min( remaining, size.width - x ); remaining -= limit; limit += x; int x0 = x; for( int c = 0; c < cn; c++ ) { for( x = x0; x <= limit - 4; x += 4 ) { if( mask[x] ) s = update(s, (WT)f(src[x*cn + c])); if( mask[x+1] ) s = update(s, (WT)f(src[(x+1)*cn + c])); if( mask[x+2] ) s = update(s, (WT)f(src[(x+2)*cn + c])); if( mask[x+3] ) s = update(s, (WT)f(src[(x+3)*cn + c])); } for( ; x < limit; x++ ) { if( mask[x] ) s = update(s, (WT)f(src[x*cn + c])); } } if( remaining == 0 || (x == size.width && y == size.height-1) ) { s0 = globUpdate(s0, (ST)s); s = 0; remaining = BLOCK_SIZE; } } } return s0; } template static double normMask_( const Mat& srcmat, const Mat& maskmat ) { ElemFunc f; UpdateFunc update; typedef typename ElemFunc::type1 T; typedef typename UpdateFunc::rtype ST; assert( DataType::depth == srcmat.depth() ); Size size = getContinuousSize( srcmat, maskmat ); ST s = 0; int cn = srcmat.channels(); for( int y = 0; y < size.height; y++ ) { const T* src = (const T*)(srcmat.data + srcmat.step*y); const uchar* mask = maskmat.data + maskmat.step*y; for( int c = 0; c < cn; c++ ) { int x = 0; for( ; x <= size.width - 4; x += 4 ) { if( mask[x] ) s = update(s, (ST)f(src[x*cn + c])); if( mask[x+1] ) s = update(s, (ST)f(src[(x+1)*cn + c])); if( mask[x+2] ) s = update(s, (ST)f(src[(x+2)*cn + c])); if( mask[x+3] ) s = update(s, (ST)f(src[(x+3)*cn + c])); } for( ; x < size.width; x++ ) { if( mask[x] ) s = update(s, (ST)f(src[x*cn + c])); } } } return s; } template static double normDiffBlock_( const Mat& srcmat1, const Mat& srcmat2 ) { ElemFunc f; UpdateFunc update; GlobUpdateFunc globUpdate; typedef typename UpdateFunc::rtype WT; typedef typename GlobUpdateFunc::rtype ST; assert( DataType::depth == srcmat1.depth() ); Size size = getContinuousSize( srcmat1, srcmat2, srcmat1.channels() ); ST s0 = 0; WT s = 0; int y, remaining = BLOCK_SIZE; for( y = 0; y < size.height; y++ ) { const T* src1 = (const T*)(srcmat1.data + srcmat1.step*y); const T* src2 = (const T*)(srcmat2.data + srcmat2.step*y); int x = 0; while( x < size.width ) { int limit = std::min( remaining, size.width - x ); remaining -= limit; limit += x; for( ; x <= limit - 4; x += 4 ) { s = update(s, (WT)f(src1[x] - src2[x])); s = update(s, (WT)f(src1[x+1] - src2[x+1])); s = update(s, (WT)f(src1[x+2] - src2[x+2])); s = update(s, (WT)f(src1[x+3] - src2[x+3])); } for( ; x < limit; x++ ) s = update(s, (WT)f(src1[x] - src2[x])); if( remaining == 0 || (x == size.width && y == size.height-1) ) { s0 = globUpdate(s0, (ST)s); s = 0; remaining = BLOCK_SIZE; } } } return s0; } template static double normDiff_( const Mat& srcmat1, const Mat& srcmat2 ) { ElemFunc f; UpdateFunc update; typedef typename UpdateFunc::rtype ST; assert( DataType::depth == srcmat1.depth() ); Size size = getContinuousSize( srcmat1, srcmat2, srcmat1.channels() ); ST s = 0; for( int y = 0; y < size.height; y++ ) { const T* src1 = (const T*)(srcmat1.data + srcmat1.step*y); const T* src2 = (const T*)(srcmat2.data + srcmat2.step*y); int x = 0; for( ; x <= size.width - 4; x += 4 ) { s = update(s, (ST)f(src1[x] - src2[x])); s = update(s, (ST)f(src1[x+1] - src2[x+1])); s = update(s, (ST)f(src1[x+2] - src2[x+2])); s = update(s, (ST)f(src1[x+3] - src2[x+3])); } for( ; x < size.width; x++ ) s = update(s, (ST)f(src1[x] - src2[x])); } return s; } template static double normDiffMaskBlock_( const Mat& srcmat1, const Mat& srcmat2, const Mat& maskmat ) { ElemFunc f; UpdateFunc update; GlobUpdateFunc globUpdate; typedef typename UpdateFunc::rtype WT; typedef typename GlobUpdateFunc::rtype ST; assert( DataType::depth == srcmat1.depth() ); Size size = getContinuousSize( srcmat1, srcmat2, maskmat ); ST s0 = 0; WT s = 0; int y, remaining = BLOCK_SIZE; int cn = srcmat1.channels(); for( y = 0; y < size.height; y++ ) { const T* src1 = (const T*)(srcmat1.data + srcmat1.step*y); const T* src2 = (const T*)(srcmat2.data + srcmat2.step*y); const uchar* mask = maskmat.data + maskmat.step*y; int x = 0; while( x < size.width ) { int limit = std::min( remaining, size.width - x ); remaining -= limit; limit += x; int x0 = x; for( int c = 0; c < cn; c++ ) { for( x = x0; x <= limit - 4; x += 4 ) { if( mask[x] ) s = update(s, (WT)f(src1[x*cn + c] - src2[x*cn + c])); if( mask[x+1] ) s = update(s, (WT)f(src1[(x+1)*cn + c] - src2[(x+1)*cn + c])); if( mask[x+2] ) s = update(s, (WT)f(src1[(x+2)*cn + c] - src2[(x+2)*cn + c])); if( mask[x+3] ) s = update(s, (WT)f(src1[(x+3)*cn + c] - src2[(x+3)*cn + c])); } for( ; x < limit; x++ ) if( mask[x] ) s = update(s, (WT)f(src1[x*cn + c] - src2[x*cn + c])); } if( remaining == 0 || (x == size.width && y == size.height-1) ) { s0 = globUpdate(s0, (ST)s); s = 0; remaining = BLOCK_SIZE; } } } return s0; } template static double normDiffMask_( const Mat& srcmat1, const Mat& srcmat2, const Mat& maskmat ) { ElemFunc f; UpdateFunc update; typedef typename UpdateFunc::rtype ST; assert( DataType::depth == srcmat1.depth() ); Size size = getContinuousSize( srcmat1, srcmat2, maskmat ); ST s = 0; int cn = srcmat1.channels(); for( int y = 0; y < size.height; y++ ) { const T* src1 = (const T*)(srcmat1.data + srcmat1.step*y); const T* src2 = (const T*)(srcmat2.data + srcmat2.step*y); const uchar* mask = maskmat.data + maskmat.step*y; for( int c = 0; c < cn; c++ ) { int x = 0; for( ; x <= size.width - 4; x += 4 ) { if( mask[x] ) s = update(s, (ST)f(src1[x*cn + c] - src2[x*cn + c])); if( mask[x+1] ) s = update(s, (ST)f(src1[(x+1)*cn + c] - src2[(x+1)*cn + c])); if( mask[x+2] ) s = update(s, (ST)f(src1[(x+2)*cn + c] - src2[(x+2)*cn + c])); if( mask[x+3] ) s = update(s, (ST)f(src1[(x+3)*cn + c] - src2[(x+3)*cn + c])); } for( ; x < size.width; x++ ) if( mask[x] ) s = update(s, (ST)f(src1[x*cn + c] - src2[x*cn + c])); } } return s; } typedef double (*NormFunc)(const Mat& src); typedef double (*NormDiffFunc)(const Mat& src1, const Mat& src2); typedef double (*NormMaskFunc)(const Mat& src1, const Mat& mask); typedef double (*NormDiffMaskFunc)(const Mat& src1, const Mat& src2, const Mat& mask); double norm( const Mat& a, int normType ) { static NormFunc tab[3][8] = { { norm_, OpMax >, norm_, OpMax >, norm_, OpMax >, norm_, OpMax >, norm_, OpMax >, norm_, OpMax >, norm_, OpMax > }, { normBlock_, OpAdd, OpAdd, 1<<24>, normBlock_, OpAdd, OpAdd, 1<<24>, normBlock_, OpAdd, OpAdd, 1<<16>, normBlock_, OpAdd, OpAdd, 1<<16>, norm_, OpAdd >, norm_, OpAdd >, norm_, OpAdd > }, { normBlock_, OpAdd, OpAdd, 1<<16>, normBlock_, OpAdd, OpAdd, 1<<16>, norm_, OpAdd >, norm_, OpAdd >, norm_, OpAdd >, norm_, OpAdd >, norm_, OpAdd > } }; normType &= 7; CV_Assert(normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2); NormFunc func = tab[normType >> 1][a.depth()]; CV_Assert(func != 0); double r = 0; if( a.dims > 2 ) { const Mat* arrays[] = {&a, 0}; Mat planes[1]; NAryMatIterator it(arrays, planes); for( int i = 0; i < it.nplanes; i++, ++it ) { double n = func(it.planes[0]); if( normType == NORM_INF ) r = std::max(r, n); else r += n; } } else r = func(a); return normType == NORM_L2 ? std::sqrt(r) : r; } double norm( const Mat& a, int normType, const Mat& mask ) { static NormMaskFunc tab[3][8] = { { normMask_, OpMax >, normMask_, OpMax >, normMask_, OpMax >, normMask_, OpMax >, normMask_, OpMax >, normMask_, OpMax >, normMask_, OpMax > }, { normMaskBlock_, OpAdd, OpAdd, 1<<24>, normMaskBlock_, OpAdd, OpAdd, 1<<24>, normMaskBlock_, OpAdd, OpAdd, 1<<16>, normMaskBlock_, OpAdd, OpAdd, 1<<16>, normMask_, OpAdd >, normMask_, OpAdd >, normMask_, OpAdd > }, { normMaskBlock_, OpAdd, OpAdd, 1<<16>, normMaskBlock_, OpAdd, OpAdd, 1<<16>, normMask_, OpAdd >, normMask_, OpAdd >, normMask_, OpAdd >, normMask_, OpAdd >, normMask_, OpAdd > } }; if( !mask.data ) return norm(a, normType); normType &= 7; CV_Assert((normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2) && mask.type() == CV_8U); NormMaskFunc func = tab[normType >> 1][a.depth()]; CV_Assert(func != 0); double r = 0; if( a.dims > 2 ) { const Mat* arrays[] = {&a, &mask, 0}; Mat planes[2]; NAryMatIterator it(arrays, planes); for( int i = 0; i < it.nplanes; i++, ++it ) { double n = func(it.planes[0], it.planes[1]); if( normType == NORM_INF ) r = std::max(r, n); else r += n; } } else { CV_Assert( a.size() == mask.size() ); r = func(a, mask); } return normType == NORM_L2 ? std::sqrt(r) : r; } double norm( const Mat& a, const Mat& b, int normType ) { static NormDiffFunc tab[3][8] = { { normDiff_, OpMax >, normDiff_, OpMax >, normDiff_, OpMax >, normDiff_, OpMax >, normDiff_, OpMax >, normDiff_, OpMax >, normDiff_, OpMax > }, { normDiffBlock_, OpAdd, OpAdd, 1<<24>, normDiffBlock_, OpAdd, OpAdd, 1<<24>, normDiffBlock_, OpAdd, OpAdd, 1<<16>, normDiffBlock_, OpAdd, OpAdd, 1<<16>, normDiff_, OpAdd >, normDiff_, OpAdd >, normDiff_, OpAdd > }, { normDiffBlock_, OpAdd, OpAdd, 1<<16>, normDiffBlock_, OpAdd, OpAdd, 1<<16>, normDiff_, OpAdd >, normDiff_, OpAdd >, normDiff_, OpAdd >, normDiff_, OpAdd >, normDiff_, OpAdd > } }; CV_Assert( a.type() == b.type() ); bool isRelative = (normType & NORM_RELATIVE) != 0; normType &= 7; CV_Assert(normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2); NormDiffFunc func = tab[normType >> 1][a.depth()]; CV_Assert(func != 0); double r = 0.; if( a.dims > 2 ) { const Mat* arrays[] = {&a, &b, 0}; Mat planes[2]; NAryMatIterator it(arrays, planes); for( int i = 0; i < it.nplanes; i++, ++it ) { double n = func(it.planes[0], it.planes[1]); if( normType == NORM_INF ) r = std::max(r, n); else r += n; } } else { CV_Assert( a.size() == b.size() ); r = func( a, b ); } if( normType == NORM_L2 ) r = std::sqrt(r); if( isRelative ) r /= norm(b, normType); return r; } double norm( const Mat& a, const Mat& b, int normType, const Mat& mask ) { static NormDiffMaskFunc tab[3][8] = { { normDiffMask_, OpMax >, normDiffMask_, OpMax >, normDiffMask_, OpMax >, normDiffMask_, OpMax >, normDiffMask_, OpMax >, normDiffMask_, OpMax >, normDiffMask_, OpMax > }, { normDiffMaskBlock_, OpAdd, OpAdd, 1<<24>, normDiffMaskBlock_, OpAdd, OpAdd, 1<<24>, normDiffMaskBlock_, OpAdd, OpAdd, 1<<16>, normDiffMaskBlock_, OpAdd, OpAdd, 1<<16>, normDiffMask_, OpAdd >, normDiffMask_, OpAdd >, normDiffMask_, OpAdd > }, { normDiffMaskBlock_, OpAdd, OpAdd, 1<<16>, normDiffMaskBlock_, OpAdd, OpAdd, 1<<16>, normDiffMask_, OpAdd >, normDiffMask_, OpAdd >, normDiffMask_, OpAdd >, normDiffMask_, OpAdd >, normDiffMask_, OpAdd > } }; if( !mask.data ) return norm(a, b, normType); CV_Assert( a.type() == b.type() && mask.type() == CV_8U); bool isRelative = (normType & NORM_RELATIVE) != 0; normType &= 7; CV_Assert(normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2); NormDiffMaskFunc func = tab[normType >> 1][a.depth()]; CV_Assert(func != 0); double r = 0.; if( a.dims > 2 ) { const Mat* arrays[] = {&a, &b, &mask, 0}; Mat planes[3]; NAryMatIterator it(arrays, planes); for( int i = 0; i < it.nplanes; i++, ++it ) { double n = func(it.planes[0], it.planes[1], it.planes[2]); if( normType == NORM_INF ) r = std::max(r, n); else r += n; } } else { CV_Assert( a.size() == b.size() && a.size() == mask.size() ); r = func( a, b, mask ); } if( normType == NORM_L2 ) r = std::sqrt(r); if( isRelative ) r /= std::max(norm(b, normType, mask), DBL_EPSILON); return r; } } CV_IMPL CvScalar cvSum( const CvArr* srcarr ) { cv::Scalar sum = cv::sum(cv::cvarrToMat(srcarr, false, true, 1)); if( CV_IS_IMAGE(srcarr) ) { int coi = cvGetImageCOI((IplImage*)srcarr); if( coi ) { CV_Assert( 0 < coi && coi <= 4 ); sum = cv::Scalar(sum[coi-1]); } } return sum; } CV_IMPL int cvCountNonZero( const CvArr* imgarr ) { cv::Mat img = cv::cvarrToMat(imgarr, false, true, 1); if( img.channels() > 1 ) cv::extractImageCOI(imgarr, img); return countNonZero(img); } CV_IMPL CvScalar cvAvg( const void* imgarr, const void* maskarr ) { cv::Mat img = cv::cvarrToMat(imgarr, false, true, 1); cv::Scalar mean = !maskarr ? cv::mean(img) : cv::mean(img, cv::cvarrToMat(maskarr)); if( CV_IS_IMAGE(imgarr) ) { int coi = cvGetImageCOI((IplImage*)imgarr); if( coi ) { CV_Assert( 0 < coi && coi <= 4 ); mean = cv::Scalar(mean[coi-1]); } } return mean; } CV_IMPL void cvAvgSdv( const CvArr* imgarr, CvScalar* _mean, CvScalar* _sdv, const void* maskarr ) { cv::Scalar mean, sdv; cv::Mat mask; if( maskarr ) mask = cv::cvarrToMat(maskarr); cv::meanStdDev(cv::cvarrToMat(imgarr, false, true, 1), mean, sdv, mask ); if( CV_IS_IMAGE(imgarr) ) { int coi = cvGetImageCOI((IplImage*)imgarr); if( coi ) { CV_Assert( 0 < coi && coi <= 4 ); mean = cv::Scalar(mean[coi-1]); sdv = cv::Scalar(sdv[coi-1]); } } if( _mean ) *(cv::Scalar*)_mean = mean; if( _sdv ) *(cv::Scalar*)_sdv = sdv; } CV_IMPL void cvMinMaxLoc( const void* imgarr, double* _minVal, double* _maxVal, CvPoint* _minLoc, CvPoint* _maxLoc, const void* maskarr ) { cv::Mat mask, img = cv::cvarrToMat(imgarr, false, true, 1); if( maskarr ) mask = cv::cvarrToMat(maskarr); if( img.channels() > 1 ) cv::extractImageCOI(imgarr, img); cv::minMaxLoc( img, _minVal, _maxVal, (cv::Point*)_minLoc, (cv::Point*)_maxLoc, mask ); } CV_IMPL double cvNorm( const void* imgA, const void* imgB, int normType, const void* maskarr ) { cv::Mat a, mask; if( !imgA ) { imgA = imgB; imgB = 0; } a = cv::cvarrToMat(imgA, false, true, 1); if( maskarr ) mask = cv::cvarrToMat(maskarr); if( a.channels() > 1 && CV_IS_IMAGE(imgA) && cvGetImageCOI((const IplImage*)imgA) > 0 ) cv::extractImageCOI(imgA, a); if( !imgB ) return !maskarr ? cv::norm(a, normType) : cv::norm(a, normType, mask); cv::Mat b = cv::cvarrToMat(imgB, false, true, 1); if( b.channels() > 1 && CV_IS_IMAGE(imgB) && cvGetImageCOI((const IplImage*)imgB) > 0 ) cv::extractImageCOI(imgB, b); return !maskarr ? cv::norm(a, b, normType) : cv::norm(a, b, normType, mask); }