X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fcxcore%2Fcxstat.cpp;fp=src%2Fcxcore%2Fcxstat.cpp;h=98039019081ff2fdcd3f9eec6c6ac1a60f16dc17;hb=e4c14cdbdf2fe805e79cd96ded236f57e7b89060;hp=0000000000000000000000000000000000000000;hpb=454138ff8a20f6edb9b65a910101403d8b520643;p=opencv diff --git a/src/cxcore/cxstat.cpp b/src/cxcore/cxstat.cpp new file mode 100644 index 0000000..9803901 --- /dev/null +++ b/src/cxcore/cxstat.cpp @@ -0,0 +1,1326 @@ +/*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 "_cxcore.h" + +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_, 0, + sumBlock_, + sumBlock_, + sum_, + sum_, + sum_, 0, + + sumBlock_, Vec, Vec, 1<<24>, 0, + sumBlock_, Vec, Vec, 1<<16>, + sumBlock_, Vec, Vec, 1<<16>, + sum_, Vec >, + sum_, Vec >, + sum_, Vec >, 0, + + sumBlock_, Vec, Vec, 1<<24>, 0, + sumBlock_, Vec, Vec, 1<<16>, + sumBlock_, Vec, Vec, 1<<16>, + sum_, Vec >, + sum_, Vec >, + sum_, Vec >, 0, + + sumBlock_, Vec, Vec, 1<<24>, 0, + sumBlock_, Vec, Vec, 1<<16>, + sumBlock_, Vec, Vec, 1<<16>, + sum_, Vec >, + sum_, Vec >, + sum_, Vec >, 0 + }; + + Size size = m.size(); + SumFunc func; + + CV_Assert( m.channels() <= 4 ); + + func = tab[m.type()]; + CV_Assert( func != 0 ); + + 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 ); + 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./std::max(m.rows*m.cols, 1)); +} + +Scalar mean( const Mat& m, const Mat& mask ) +{ + static MeanMaskFunc tab[]= + { + meanBlock_, 0, + meanBlock_, + meanBlock_, + mean_, + mean_, + mean_, 0, + + meanBlock_, Vec, Vec, 1<<24>, 0, + meanBlock_, Vec, Vec, 1<<16>, + meanBlock_, Vec, Vec, 1<<16>, + mean_, Vec >, + mean_, Vec >, + mean_, Vec >, 0, + + meanBlock_, Vec, Vec, 1<<24>, 0, + meanBlock_, Vec, Vec, 1<<16>, + meanBlock_, Vec, Vec, 1<<16>, + mean_, Vec >, + mean_, Vec >, + mean_, Vec >, 0, + + meanBlock_, Vec, Vec, 1<<24>, 0, + meanBlock_, Vec, Vec, 1<<16>, + meanBlock_, Vec, Vec, 1<<16>, + mean_, Vec >, + mean_, Vec >, + mean_, Vec >, 0 + }; + + if( !mask.data ) + return mean(m); + + CV_Assert( m.channels() <= 4 && m.size() == mask.size() && mask.type() == CV_8U ); + + MeanMaskFunc func = tab[m.type()]; + CV_Assert( func != 0 ); + + 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& _mean, Scalar& _stddev ) +{ + 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); + } + } + + _mean = _stddev = Scalar(); + double scale = 1./std::max(size.width*size.height, 1); + for( int i = 0; i < DataType::channels; i++ ) + { + double t = ((ST1*)&s)[i]*scale; + _mean.val[i] = t; + _stddev.val[i] = std::sqrt(std::max(((ST1*)&sq)[i]*scale - t*t, 0.)); + } +} + +template static void +meanStdDevMask_( const Mat& srcmat, const Mat& maskmat, + Scalar& _mean, Scalar& _stddev ) +{ + 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++; + } + } + _mean = _stddev = Scalar(); + double scale = 1./std::max(pix, 1); + for( int i = 0; i < DataType::channels; i++ ) + { + double t = ((ST1*)&s)[i]*scale; + _mean.val[i] = t; + _stddev.val[i] = std::sqrt(std::max(((ST1*)&sq)[i]*scale - t*t, 0.)); + } +} + +typedef void (*MeanStdDevFunc)(const Mat& src, Scalar& mean, Scalar& stddev); + +typedef void (*MeanStdDevMaskFunc)(const Mat& src, const Mat& mask, + Scalar& mean, Scalar& stddev); + +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 ); + + if( !mask.data ) + { + MeanStdDevFunc func = tab[m.type()]; + CV_Assert( func != 0 ); + func( m, mean, stddev ); + } + else + { + MeanStdDevMaskFunc func = mtab[m.type()]; + CV_Assert( mask.size() == m.size() && mask.type() == CV_8U && func != 0 ); + func( m, mask, mean, stddev ); + } +} + + +/****************************************************************************************\ +* minMaxLoc * +\****************************************************************************************/ + +template static void +minMaxIndx_( const Mat& srcmat, double* minVal, double* maxVal, int* minLoc, int* maxLoc ) +{ + assert( DataType::type == srcmat.type() ); + const T* src = (const T*)srcmat.data; + size_t step = srcmat.step/sizeof(src[0]); + T min_val = src[0], max_val = min_val; + int min_loc = 0, max_loc = 0; + int x, loc = 0; + Size size = getContinuousSize( srcmat ); + + for( ; size.height--; src += step, loc += size.width ) + { + for( x = 0; x < size.width; x++ ) + { + T val = src[x]; + if( val < min_val ) + { + min_val = val; + min_loc = loc + x; + } + else if( val > max_val ) + { + max_val = val; + max_loc = loc + x; + } + } + } + + *minLoc = min_loc; + *maxLoc = max_loc; + *minVal = min_val; + *maxVal = max_val; +} + + +template static void +minMaxIndxMask_( const Mat& srcmat, const Mat& maskmat, + double* minVal, double* maxVal, int* minLoc, int* maxLoc ) +{ + 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; + T min_val = 0, max_val = 0; + int min_loc = -1, max_loc = -1; + int x = 0, y, loc = 0; + Size size = getContinuousSize( srcmat, maskmat ); + + for( y = 0; y < size.height; y++, src += step, mask += maskstep, loc += size.width ) + { + for( x = 0; x < size.width; x++ ) + if( mask[x] != 0 ) + { + min_loc = max_loc = loc + x; + min_val = max_val = src[x]; + break; + } + if( x < size.width ) + break; + } + + for( ; y < size.height; x = 0, y++, src += step, mask += maskstep, loc += size.width ) + { + for( ; x < size.width; x++ ) + { + T val = src[x]; + int m = mask[x]; + + if( val < min_val && m ) + { + min_val = val; + min_loc = loc + x; + } + else if( val > max_val && m ) + { + max_val = val; + max_loc = loc + x; + } + } + } + + *minLoc = min_loc; + *maxLoc = max_loc; + *minVal = min_val; + *maxVal = max_val; +} + +typedef void (*MinMaxIndxFunc)(const Mat&, double*, double*, int*, int*); + +typedef void (*MinMaxIndxMaskFunc)(const Mat&, const Mat&, + double*, double*, int*, int*); + +void minMaxLoc( const Mat& img, double* minVal, double* maxVal, + Point* minLoc, Point* maxLoc, const Mat& mask ) +{ + 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=0, maxval=0; + int minloc=0, maxloc=0; + + CV_Assert( img.channels() == 1 ); + + if( !mask.data ) + { + MinMaxIndxFunc func = tab[depth]; + CV_Assert( func != 0 ); + func( img, &minval, &maxval, &minloc, &maxloc ); + } + else + { + CV_Assert( img.size() == mask.size() && mask.type() == CV_8U ); + MinMaxIndxMaskFunc func = tabm[depth]; + CV_Assert( func != 0 ); + func( img, mask, &minval, &maxval, &minloc, &maxloc ); + } + + if( minVal ) + *minVal = minval; + if( maxVal ) + *maxVal = maxval; + if( minLoc ) + { + if( minloc >= 0 ) + { + minLoc->y = minloc/img.cols; + minLoc->x = minloc - minLoc->y*img.cols; + } + else + minLoc->x = minLoc->y = -1; + } + if( maxLoc ) + { + if( maxloc >= 0 ) + { + maxLoc->y = maxloc/img.cols; + maxLoc->x = maxloc - maxLoc->y*img.cols; + } + else + maxLoc->x = maxLoc->y = -1; + } +} + +/****************************************************************************************\ +* 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; + + 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 - 4; x += 4 ) + { + if( mask[x] ) + s = update(s, (WT)f(src[x])); + if( mask[x+1] ) + s = update(s, (WT)f(src[x+1])); + if( mask[x+2] ) + s = update(s, (WT)f(src[x+2])); + if( mask[x+3] ) + s = update(s, (WT)f(src[x+3])); + } + for( ; x < limit; x++ ) + { + if( mask[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 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; + + 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; + int x = 0; + for( ; x <= size.width - 4; x += 4 ) + { + if( mask[x] ) + s = update(s, (ST)f(src[x])); + if( mask[x+1] ) + s = update(s, (ST)f(src[x+1])); + if( mask[x+2] ) + s = update(s, (ST)f(src[x+2])); + if( mask[x+3] ) + s = update(s, (ST)f(src[x+3])); + } + for( ; x < size.width; x++ ) + { + if( mask[x] ) + s = update(s, (ST)f(src[x])); + } + } + 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; + + 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; + for( ; x <= limit - 4; x += 4 ) + { + if( mask[x] ) + s = update(s, (WT)f(src1[x] - src2[x])); + if( mask[x+1] ) + s = update(s, (WT)f(src1[x+1] - src2[x+1])); + if( mask[x+2] ) + s = update(s, (WT)f(src1[x+2] - src2[x+2])); + if( mask[x+3] ) + s = update(s, (WT)f(src1[x+3] - src2[x+3])); + } + for( ; x < limit; x++ ) + if( mask[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 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; + + 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; + int x = 0; + for( ; x <= size.width - 4; x += 4 ) + { + if( mask[x] ) + s = update(s, (ST)f(src1[x] - src2[x])); + if( mask[x+1] ) + s = update(s, (ST)f(src1[x+1] - src2[x+1])); + if( mask[x+2] ) + s = update(s, (ST)f(src1[x+2] - src2[x+2])); + if( mask[x+3] ) + s = update(s, (ST)f(src1[x+3] - src2[x+3])); + } + for( ; x < size.width; x++ ) + if( mask[x] ) + s = update(s, (ST)f(src1[x] - src2[x])); + + } + 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 >, 0, + norm_, OpMax >, + norm_, OpMax >, + norm_, OpMax >, + norm_, OpMax >, + norm_, OpMax > + }, + + { + normBlock_, OpAdd, OpAdd, 1<<24>, 0, + normBlock_, OpAdd, OpAdd, 1<<16>, + normBlock_, OpAdd, OpAdd, 1<<16>, + norm_, OpAdd >, + norm_, OpAdd >, + norm_, OpAdd > + }, + + { + normBlock_, OpAdd, OpAdd, 1<<16>, 0, + 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 = 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 >, 0, + normMask_, OpMax >, + normMask_, OpMax >, + normMask_, OpMax >, + normMask_, OpMax >, + normMask_, OpMax > + }, + + { + normMaskBlock_, OpAdd, OpAdd, 1<<24>, 0, + normMaskBlock_, OpAdd, OpAdd, 1<<16>, + normMaskBlock_, OpAdd, OpAdd, 1<<16>, + normMask_, OpAdd >, + normMask_, OpAdd >, + normMask_, OpAdd > + }, + + { + normMaskBlock_, OpAdd, OpAdd, 1<<16>, 0, + 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) && + a.size() == mask.size() && mask.type() == CV_8U ); + NormMaskFunc func = tab[normType >> 1][a.depth()]; + CV_Assert(func != 0); + double 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 >, 0, + normDiff_, OpMax >, + normDiff_, OpMax >, + normDiff_, OpMax >, + normDiff_, OpMax >, + normDiff_, OpMax > + }, + + { + normDiffBlock_, OpAdd, OpAdd, 1<<24>, 0, + normDiffBlock_, OpAdd, OpAdd, 1<<16>, + normDiffBlock_, OpAdd, OpAdd, 1<<16>, + normDiff_, OpAdd >, + normDiff_, OpAdd >, + normDiff_, OpAdd > + }, + + { + normDiffBlock_, OpAdd, OpAdd, 1<<16>, 0, + normDiff_, OpAdd >, + normDiff_, OpAdd >, + normDiff_, OpAdd >, + normDiff_, OpAdd >, + normDiff_, OpAdd > + } + }; + + CV_Assert( a.type() == b.type() && a.size() == b.size() ); + + 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 = 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 >, 0, + normDiffMask_, OpMax >, + normDiffMask_, OpMax >, + normDiffMask_, OpMax >, + normDiffMask_, OpMax >, + normDiffMask_, OpMax > + }, + + { + normDiffMaskBlock_, OpAdd, OpAdd, 1<<24>, 0, + normDiffMaskBlock_, OpAdd, OpAdd, 1<<16>, + normDiffMaskBlock_, OpAdd, OpAdd, 1<<16>, + normDiffMask_, OpAdd >, + normDiffMask_, OpAdd >, + normDiffMask_, OpAdd > + }, + + { + normDiffMaskBlock_, OpAdd, OpAdd, 1<<16>, 0, + normDiffMask_, OpAdd >, + normDiffMask_, OpAdd >, + normDiffMask_, OpAdd >, + normDiffMask_, OpAdd >, + normDiffMask_, OpAdd > + } + }; + + if( !mask.data ) + return norm(a, b, normType); + + CV_Assert( a.type() == b.type() && a.size() == b.size() && + a.size() == mask.size() && 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 = 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); +}