opencv/modules/core/src/mean.simd.hpp

326 lines
11 KiB
C++
Raw Normal View History

2018-02-06 20:54:14 +08:00
// 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"
2019-02-19 21:58:32 +08:00
namespace cv {
typedef int (*SumSqrFunc)(const uchar*, const uchar* mask, uchar*, uchar*, int, int);
2018-02-06 20:54:14 +08:00
2019-02-19 21:58:32 +08:00
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
2018-02-06 20:54:14 +08:00
2019-02-19 21:58:32 +08:00
SumSqrFunc getSumSqrFunc(int depth);
2018-02-06 20:54:14 +08:00
2019-02-19 21:58:32 +08:00
#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
2018-02-06 20:54:14 +08:00
template <typename T, typename ST, typename SQT>
struct SumSqr_SIMD
{
2019-02-19 21:58:32 +08:00
inline int operator () (const T *, const uchar *, ST *, SQT *, int, int) const
2018-02-06 20:54:14 +08:00
{
return 0;
}
};
Merge pull request #24325 from hanliutong:rewrite Rewrite Universal Intrinsic code: float related part #24325 The goal of this series of PRs is to modify the SIMD code blocks guarded by CV_SIMD macro: rewrite them by using the new Universal Intrinsic API. The series of PRs is listed below: #23885 First patch, an example #23980 Core module #24058 ImgProc module, part 1 #24132 ImgProc module, part 2 #24166 ImgProc module, part 3 #24301 Features2d and calib3d module #24324 Gapi module This patch (hopefully) is the last one in the series. This patch mainly involves 3 parts 1. Add some modifications related to float (CV_SIMD_64F) 2. Use `#if (CV_SIMD || CV_SIMD_SCALABLE)` instead of `#if CV_SIMD || CV_SIMD_SCALABLE`, then we can get the `CV_SIMD` module that is not enabled for `CV_SIMD_SCALABLE` by looking for `if CV_SIMD` 3. Summary of `CV_SIMD` blocks that remains unmodified: Updated comments - Some blocks will cause test fail when enable for RVV, marked as `TODO: enable for CV_SIMD_SCALABLE, ....` - Some blocks can not be rewrited directly. (Not commented in the source code, just listed here) - ./modules/core/src/mathfuncs_core.simd.hpp (Vector type wrapped in class/struct) - ./modules/imgproc/src/color_lab.cpp (Array of vector type) - ./modules/imgproc/src/color_rgb.simd.hpp (Array of vector type) - ./modules/imgproc/src/sumpixels.simd.hpp (fixed length algorithm, strongly ralated with `CV_SIMD_WIDTH`) These algorithms will need to be redesigned to accommodate scalable backends. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [ ] I agree to contribute to the project under Apache 2 License. - [ ] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [ ] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
2023-10-05 22:57:25 +08:00
#if (CV_SIMD || CV_SIMD_SCALABLE)
2018-02-06 20:54:14 +08:00
template <>
struct SumSqr_SIMD<uchar, int, int>
{
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))
2018-02-06 20:54:14 +08:00
return 0;
len *= cn;
2018-02-06 20:54:14 +08:00
int x = 0;
v_int32 v_sum = vx_setzero_s32();
v_int32 v_sqsum = vx_setzero_s32();
2018-02-06 20:54:14 +08:00
const int len0 = len & -VTraits<v_uint8>::vlanes();
while(x < len0)
2018-02-06 20:54:14 +08:00
{
const int len_tmp = min(x + 256*VTraits<v_uint16>::vlanes(), len0);
v_uint16 v_sum16 = vx_setzero_u16();
for ( ; x < len_tmp; x += VTraits<v_uint8>::vlanes())
2018-02-06 20:54:14 +08:00
{
v_uint16 v_src0 = vx_load_expand(src0 + x);
v_uint16 v_src1 = vx_load_expand(src0 + x + VTraits<v_uint16>::vlanes());
v_sum16 = v_add(v_sum16, v_add(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_add(v_sqsum, v_add(v_dotprod(v_tmp0, v_tmp0), v_dotprod(v_tmp1, v_tmp1)));
2018-02-06 20:54:14 +08:00
}
v_uint32 v_half0, v_half1;
v_expand(v_sum16, v_half0, v_half1);
v_sum = v_add(v_sum, v_reinterpret_as_s32(v_add(v_half0, v_half1)));
2018-02-06 20:54:14 +08:00
}
if (x <= len - VTraits<v_uint16>::vlanes())
2018-02-06 20:54:14 +08:00
{
v_uint16 v_src = vx_load_expand(src0 + x);
v_uint16 v_half = v_combine_high(v_src, v_src);
2018-02-06 20:54:14 +08:00
v_uint32 v_tmp0, v_tmp1;
v_expand(v_add(v_src, v_half), v_tmp0, v_tmp1);
v_sum = v_add(v_sum, v_reinterpret_as_s32(v_tmp0));
2018-02-06 20:54:14 +08:00
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_add(v_sqsum, v_dotprod(v_tmp2, v_tmp2));
x += VTraits<v_uint16>::vlanes();
}
2018-02-06 20:54:14 +08:00
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 * VTraits<v_int32>::max_nlanes];
v_store(ar, v_sum);
v_store(ar + VTraits<v_int32>::vlanes(), v_sqsum);
for (int i = 0; i < VTraits<v_int32>::vlanes(); ++i)
{
sum[i % cn] += ar[i];
sqsum[i % cn] += ar[VTraits<v_int32>::vlanes() + i];
}
}
v_cleanup();
2018-02-06 20:54:14 +08:00
return x / cn;
}
};
template <>
struct SumSqr_SIMD<schar, int, int>
{
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))
2018-02-06 20:54:14 +08:00
return 0;
len *= cn;
2018-02-06 20:54:14 +08:00
int x = 0;
v_int32 v_sum = vx_setzero_s32();
v_int32 v_sqsum = vx_setzero_s32();
2018-02-06 20:54:14 +08:00
const int len0 = len & -VTraits<v_int8>::vlanes();
while (x < len0)
2018-02-06 20:54:14 +08:00
{
const int len_tmp = min(x + 256 * VTraits<v_int16>::vlanes(), len0);
v_int16 v_sum16 = vx_setzero_s16();
for (; x < len_tmp; x += VTraits<v_int8>::vlanes())
2018-02-06 20:54:14 +08:00
{
v_int16 v_src0 = vx_load_expand(src0 + x);
v_int16 v_src1 = vx_load_expand(src0 + x + VTraits<v_int16>::vlanes());
v_sum16 = v_add(v_sum16, v_add(v_src0, v_src1));
v_int16 v_tmp0, v_tmp1;
v_zip(v_src0, v_src1, v_tmp0, v_tmp1);
v_sqsum = v_add(v_sqsum, v_add(v_dotprod(v_tmp0, v_tmp0), v_dotprod(v_tmp1, v_tmp1)));
2018-02-06 20:54:14 +08:00
}
v_int32 v_half0, v_half1;
v_expand(v_sum16, v_half0, v_half1);
v_sum = v_add(v_sum, v_add(v_half0, v_half1));
2018-02-06 20:54:14 +08:00
}
if (x <= len - VTraits<v_int16>::vlanes())
2018-02-06 20:54:14 +08:00
{
v_int16 v_src = vx_load_expand(src0 + x);
v_int16 v_half = v_combine_high(v_src, v_src);
2018-02-06 20:54:14 +08:00
v_int32 v_tmp0, v_tmp1;
v_expand(v_add(v_src, v_half), v_tmp0, v_tmp1);
v_sum = v_add(v_sum, v_tmp0);
2018-02-06 20:54:14 +08:00
v_int16 v_tmp2, v_tmp3;
v_zip(v_src, v_half, v_tmp2, v_tmp3);
v_sqsum = v_add(v_sqsum, v_dotprod(v_tmp2, v_tmp2));
x += VTraits<v_int16>::vlanes();
}
2018-02-06 20:54:14 +08:00
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 * VTraits<v_int32>::max_nlanes];
v_store(ar, v_sum);
v_store(ar + VTraits<v_int32>::vlanes(), v_sqsum);
for (int i = 0; i < VTraits<v_int32>::vlanes(); ++i)
{
sum[i % cn] += ar[i];
sqsum[i % cn] += ar[VTraits<v_int32>::vlanes() + i];
}
}
v_cleanup();
2018-02-06 20:54:14 +08:00
return x / cn;
}
};
#endif
template<typename T, typename ST, typename SQT>
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<T, ST, SQT> vop;
int x = vop(src0, mask, sum, sqsum, len, cn), k = cn % 4;
src = src0 + x * cn;
2018-02-06 20:54:14 +08:00
if( k == 1 )
{
ST s0 = sum[0];
SQT sq0 = sqsum[0];
for(int i = x; i < len; i++, src += cn )
2018-02-06 20:54:14 +08:00
{
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 )
2018-02-06 20:54:14 +08:00
{
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 )
2018-02-06 20:54:14 +08:00
{
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;
2018-02-06 20:54:14 +08:00
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 )
2018-02-06 20:54:14 +08:00
{
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 )
2019-02-19 21:58:32 +08:00
{ CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); }
2018-02-06 20:54:14 +08:00
static int sqsum8s( const schar* src, const uchar* mask, int* sum, int* sqsum, int len, int cn )
2019-02-19 21:58:32 +08:00
{ CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); }
2018-02-06 20:54:14 +08:00
static int sqsum16u( const ushort* src, const uchar* mask, int* sum, double* sqsum, int len, int cn )
2019-02-19 21:58:32 +08:00
{ CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); }
2018-02-06 20:54:14 +08:00
static int sqsum16s( const short* src, const uchar* mask, int* sum, double* sqsum, int len, int cn )
2019-02-19 21:58:32 +08:00
{ CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); }
2018-02-06 20:54:14 +08:00
static int sqsum32s( const int* src, const uchar* mask, double* sum, double* sqsum, int len, int cn )
2019-02-19 21:58:32 +08:00
{ CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); }
2018-02-06 20:54:14 +08:00
static int sqsum32f( const float* src, const uchar* mask, double* sum, double* sqsum, int len, int cn )
2019-02-19 21:58:32 +08:00
{ CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); }
2018-02-06 20:54:14 +08:00
static int sqsum64f( const double* src, const uchar* mask, double* sum, double* sqsum, int len, int cn )
2019-02-19 21:58:32 +08:00
{ CV_INSTRUMENT_REGION(); return sumsqr_(src, mask, sum, sqsum, len, cn); }
2018-02-06 20:54:14 +08:00
2019-02-19 21:58:32 +08:00
SumSqrFunc getSumSqrFunc(int depth)
2018-02-06 20:54:14 +08:00
{
2019-02-19 21:58:32 +08:00
CV_INSTRUMENT_REGION();
2018-02-06 20:54:14 +08:00
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
2019-02-19 21:58:32 +08:00
CV_CPU_OPTIMIZATION_NAMESPACE_END
} // namespace