// This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html #include "precomp.hpp" #include "stat.hpp" namespace cv { typedef int (*SumSqrFunc)(const uchar*, const uchar* mask, uchar*, uchar*, int, int); CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN SumSqrFunc getSumSqrFunc(int depth); #ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY template struct SumSqr_SIMD { inline int operator () (const T *, const uchar *, ST *, SQT *, int, int) const { return 0; } }; #if CV_SIMD template <> struct SumSqr_SIMD { int operator () (const uchar * src0, const uchar * mask, int * sum, int * sqsum, int len, int cn) const { if (mask || (cn != 1 && cn != 2 && cn != 4)) return 0; len *= cn; int x = 0; v_int32 v_sum = vx_setzero_s32(); v_int32 v_sqsum = vx_setzero_s32(); const int len0 = len & -v_uint8::nlanes; while(x < len0) { const int len_tmp = min(x + 256*v_uint16::nlanes, len0); v_uint16 v_sum16 = vx_setzero_u16(); for ( ; x < len_tmp; x += v_uint8::nlanes) { v_uint16 v_src0 = vx_load_expand(src0 + x); v_uint16 v_src1 = vx_load_expand(src0 + x + v_uint16::nlanes); v_sum16 += v_src0 + v_src1; v_int16 v_tmp0, v_tmp1; v_zip(v_reinterpret_as_s16(v_src0), v_reinterpret_as_s16(v_src1), v_tmp0, v_tmp1); v_sqsum += v_dotprod(v_tmp0, v_tmp0) + v_dotprod(v_tmp1, v_tmp1); } v_uint32 v_half0, v_half1; v_expand(v_sum16, v_half0, v_half1); v_sum += v_reinterpret_as_s32(v_half0 + v_half1); } if (x <= len - v_uint16::nlanes) { v_uint16 v_src = vx_load_expand(src0 + x); v_uint16 v_half = v_combine_high(v_src, v_src); v_uint32 v_tmp0, v_tmp1; v_expand(v_src + v_half, v_tmp0, v_tmp1); v_sum += v_reinterpret_as_s32(v_tmp0); v_int16 v_tmp2, v_tmp3; v_zip(v_reinterpret_as_s16(v_src), v_reinterpret_as_s16(v_half), v_tmp2, v_tmp3); v_sqsum += v_dotprod(v_tmp2, v_tmp2); x += v_uint16::nlanes; } if (cn == 1) { *sum += v_reduce_sum(v_sum); *sqsum += v_reduce_sum(v_sqsum); } else { int CV_DECL_ALIGNED(CV_SIMD_WIDTH) ar[2 * v_int32::nlanes]; v_store(ar, v_sum); v_store(ar + v_int32::nlanes, v_sqsum); for (int i = 0; i < v_int32::nlanes; ++i) { sum[i % cn] += ar[i]; sqsum[i % cn] += ar[v_int32::nlanes + i]; } } v_cleanup(); return x / cn; } }; template <> struct SumSqr_SIMD { int operator () (const schar * src0, const uchar * mask, int * sum, int * sqsum, int len, int cn) const { if (mask || (cn != 1 && cn != 2 && cn != 4)) return 0; len *= cn; int x = 0; v_int32 v_sum = vx_setzero_s32(); v_int32 v_sqsum = vx_setzero_s32(); const int len0 = len & -v_int8::nlanes; while (x < len0) { const int len_tmp = min(x + 256 * v_int16::nlanes, len0); v_int16 v_sum16 = vx_setzero_s16(); for (; x < len_tmp; x += v_int8::nlanes) { v_int16 v_src0 = vx_load_expand(src0 + x); v_int16 v_src1 = vx_load_expand(src0 + x + v_int16::nlanes); v_sum16 += v_src0 + v_src1; v_int16 v_tmp0, v_tmp1; v_zip(v_src0, v_src1, v_tmp0, v_tmp1); v_sqsum += v_dotprod(v_tmp0, v_tmp0) + v_dotprod(v_tmp1, v_tmp1); } v_int32 v_half0, v_half1; v_expand(v_sum16, v_half0, v_half1); v_sum += v_half0 + v_half1; } if (x <= len - v_int16::nlanes) { v_int16 v_src = vx_load_expand(src0 + x); v_int16 v_half = v_combine_high(v_src, v_src); v_int32 v_tmp0, v_tmp1; v_expand(v_src + v_half, v_tmp0, v_tmp1); v_sum += v_tmp0; v_int16 v_tmp2, v_tmp3; v_zip(v_src, v_half, v_tmp2, v_tmp3); v_sqsum += v_dotprod(v_tmp2, v_tmp2); x += v_int16::nlanes; } if (cn == 1) { *sum += v_reduce_sum(v_sum); *sqsum += v_reduce_sum(v_sqsum); } else { int CV_DECL_ALIGNED(CV_SIMD_WIDTH) ar[2 * v_int32::nlanes]; v_store(ar, v_sum); v_store(ar + v_int32::nlanes, v_sqsum); for (int i = 0; i < v_int32::nlanes; ++i) { sum[i % cn] += ar[i]; sqsum[i % cn] += ar[v_int32::nlanes + i]; } } v_cleanup(); return x / cn; } }; #endif template static int sumsqr_(const T* src0, const uchar* mask, ST* sum, SQT* sqsum, int len, int cn ) { const T* src = src0; if( !mask ) { SumSqr_SIMD vop; int x = vop(src0, mask, sum, sqsum, len, cn), k = cn % 4; src = src0 + x * cn; if( k == 1 ) { ST s0 = sum[0]; SQT sq0 = sqsum[0]; for(int i = x; i < len; i++, src += cn ) { T v = src[0]; s0 += v; sq0 += (SQT)v*v; } sum[0] = s0; sqsum[0] = sq0; } else if( k == 2 ) { ST s0 = sum[0], s1 = sum[1]; SQT sq0 = sqsum[0], sq1 = sqsum[1]; for(int i = x; i < len; i++, src += cn ) { T v0 = src[0], v1 = src[1]; s0 += v0; sq0 += (SQT)v0*v0; s1 += v1; sq1 += (SQT)v1*v1; } sum[0] = s0; sum[1] = s1; sqsum[0] = sq0; sqsum[1] = sq1; } else if( k == 3 ) { ST s0 = sum[0], s1 = sum[1], s2 = sum[2]; SQT sq0 = sqsum[0], sq1 = sqsum[1], sq2 = sqsum[2]; for(int i = x; i < len; i++, src += cn ) { 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; } sum[0] = s0; sum[1] = s1; sum[2] = s2; sqsum[0] = sq0; sqsum[1] = sq1; sqsum[2] = sq2; } for( ; k < cn; k += 4 ) { src = src0 + x * cn + k; ST s0 = sum[k], s1 = sum[k+1], s2 = sum[k+2], s3 = sum[k+3]; SQT sq0 = sqsum[k], sq1 = sqsum[k+1], sq2 = sqsum[k+2], sq3 = sqsum[k+3]; for(int i = x; i < len; i++, src += cn ) { T v0, v1; v0 = src[0], v1 = src[1]; s0 += v0; sq0 += (SQT)v0*v0; s1 += v1; sq1 += (SQT)v1*v1; v0 = src[2], v1 = src[3]; s2 += v0; sq2 += (SQT)v0*v0; s3 += v1; sq3 += (SQT)v1*v1; } sum[k] = s0; sum[k+1] = s1; sum[k+2] = s2; sum[k+3] = s3; sqsum[k] = sq0; sqsum[k+1] = sq1; sqsum[k+2] = sq2; sqsum[k+3] = sq3; } return len; } int i, nzm = 0; if( cn == 1 ) { ST s0 = sum[0]; SQT sq0 = sqsum[0]; for( i = 0; i < len; i++ ) if( mask[i] ) { T v = src[i]; s0 += v; sq0 += (SQT)v*v; nzm++; } sum[0] = s0; sqsum[0] = sq0; } else if( cn == 3 ) { 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] ) { 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++; } 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++ ) { T v = src[k]; ST s = sum[k] + v; SQT sq = sqsum[k] + (SQT)v*v; sum[k] = s; sqsum[k] = sq; } nzm++; } } return nzm; } static int sqsum8u( const uchar* src, const uchar* mask, int* sum, int* sqsum, int len, int cn ) { CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); } static int sqsum8s( const schar* src, const uchar* mask, int* sum, int* sqsum, int len, int cn ) { CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); } static int sqsum16u( const ushort* src, const uchar* mask, int* sum, double* sqsum, int len, int cn ) { CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); } static int sqsum16s( const short* src, const uchar* mask, int* sum, double* sqsum, int len, int cn ) { CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); } static int sqsum32s( const int* src, const uchar* mask, double* sum, double* sqsum, int len, int cn ) { CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); } static int sqsum32f( const float* src, const uchar* mask, double* sum, double* sqsum, int len, int cn ) { CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); } static int sqsum64f( const double* src, const uchar* mask, double* sum, double* sqsum, int len, int cn ) { CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); } SumSqrFunc getSumSqrFunc(int depth) { CV_INSTRUMENT_REGION(); static SumSqrFunc sumSqrTab[] = { (SumSqrFunc)GET_OPTIMIZED(sqsum8u), (SumSqrFunc)sqsum8s, (SumSqrFunc)sqsum16u, (SumSqrFunc)sqsum16s, (SumSqrFunc)sqsum32s, (SumSqrFunc)GET_OPTIMIZED(sqsum32f), (SumSqrFunc)sqsum64f, 0 }; return sumSqrTab[depth]; } #endif CV_CPU_OPTIMIZATION_NAMESPACE_END } // namespace