1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge pull request #13879 from chacha21:REDUCE_SUM2

add REDUCE_SUM2 #13879 

proposal to add REDUCE_SUM2 to cv::reduce, an operation that sums up the square of elements
This commit is contained in:
Pierre Chatelier
2023-04-28 19:42:52 +02:00
committed by GitHub
parent 23b819efb8
commit 6dd8a9b6ad
9 changed files with 254 additions and 92 deletions
+171 -66
View File
@@ -341,29 +341,32 @@ cv::Mat cv::Mat::cross(InputArray _m) const
namespace cv
{
template<typename T, typename ST, class Op> static void
reduceR_( const Mat& srcmat, Mat& dstmat )
template<typename T, typename ST, typename WT, class Op, class OpInit>
class ReduceR_Invoker : public ParallelLoopBody
{
typedef typename Op::rtype WT;
Size size = srcmat.size();
size.width *= srcmat.channels();
AutoBuffer<WT> buffer(size.width);
public:
ReduceR_Invoker(const Mat& aSrcmat, Mat& aDstmat, Op& aOp, OpInit& aOpInit)
:srcmat(aSrcmat),dstmat(aDstmat),op(aOp),opInit(aOpInit),buffer(srcmat.size().width*srcmat.channels())
{
}
void operator()(const Range& range) const CV_OVERRIDE
{
const T* src = srcmat.ptr<T>();
const size_t srcstep = srcmat.step/sizeof(src[0]);
WT* buf = buffer.data();
ST* dst = dstmat.ptr<ST>();
const T* src = srcmat.ptr<T>();
size_t srcstep = srcmat.step/sizeof(src[0]);
int i;
Op op;
int i = 0;
for( i = 0; i < size.width; i++ )
buf[i] = src[i];
for( i = range.start ; i < range.end; i++ )
buf[i] = opInit(src[i]);
for( ; --size.height; )
int height = srcmat.size().height;
for( ; --height; )
{
src += srcstep;
i = 0;
i = range.start;
#if CV_ENABLE_UNROLLED
for(; i <= size.width - 4; i += 4 )
for(; i <= range.end - 4; i += 4 )
{
WT s0, s1;
s0 = op(buf[i], (WT)src[i]);
@@ -375,63 +378,94 @@ reduceR_( const Mat& srcmat, Mat& dstmat )
buf[i+2] = s0; buf[i+3] = s1;
}
#endif
for( ; i < size.width; i++ )
for( ; i < range.end; i++ )
buf[i] = op(buf[i], (WT)src[i]);
}
for( i = 0; i < size.width; i++ )
for( i = range.start ; i < range.end; i++ )
dst[i] = (ST)buf[i];
}
}
private:
const Mat& srcmat;
Mat& dstmat;
Op& op;
OpInit& opInit;
mutable AutoBuffer<WT> buffer;
};
template<typename T, typename ST, class Op> static void
reduceC_( const Mat& srcmat, Mat& dstmat )
template<typename T, typename ST, class Op, class OpInit = OpNop<ST> > static void
reduceR_( const Mat& srcmat, Mat& dstmat)
{
typedef typename Op::rtype WT;
Size size = srcmat.size();
int cn = srcmat.channels();
size.width *= cn;
Op op;
OpInit opInit;
for( int y = 0; y < size.height; y++ )
ReduceR_Invoker<T, ST, WT, Op, OpInit> body(srcmat, dstmat, op, opInit);
//group columns by 64 bytes for data locality
parallel_for_(Range(0, srcmat.size().width*srcmat.channels()), body, srcmat.size().width*CV_ELEM_SIZE(srcmat.depth())/64);
}
template<typename T, typename ST, typename WT, class Op, class OpInit>
class ReduceC_Invoker : public ParallelLoopBody
{
public:
ReduceC_Invoker(const Mat& aSrcmat, Mat& aDstmat, Op& aOp, OpInit& aOpInit)
:srcmat(aSrcmat),dstmat(aDstmat),op(aOp),opInit(aOpInit)
{
}
void operator()(const Range& range) const CV_OVERRIDE
{
const int cn = srcmat.channels();
const int width = srcmat.size().width*cn;
AutoBuffer<WT> cumul(cn);
for( int y = range.start; y < range.end; y++ )
{
const T* src = srcmat.ptr<T>(y);
ST* dst = dstmat.ptr<ST>(y);
if( size.width == cn )
for( int k = 0; k < cn; k++ )
dst[k] = src[k];
if( width == cn )
{
for( int k = 0; k < cn; k++ )
dst[k] = (ST)opInit(src[k]);
}
else
{
for( int k = 0; k < cn; k++ )
for(int k = 0; k < cn ; ++k )
cumul[k] = opInit(src[k]);
for(int k = cn ; k < width ; k += cn )
{
WT a0 = src[k], a1 = src[k+cn];
int i;
for( i = 2*cn; i <= size.width - 4*cn; i += 4*cn )
{
a0 = op(a0, (WT)src[i+k]);
a1 = op(a1, (WT)src[i+k+cn]);
a0 = op(a0, (WT)src[i+k+cn*2]);
a1 = op(a1, (WT)src[i+k+cn*3]);
}
for( ; i < size.width; i += cn )
{
a0 = op(a0, (WT)src[i+k]);
}
a0 = op(a0, a1);
dst[k] = (ST)a0;
for (int c = 0 ; c < cn ; ++c)
cumul[c] = op(cumul[c], src[k+c]);
}
for(int k = 0 ; k < cn ; ++k )
dst[k] = (ST)cumul[k];
}
}
}
private:
const Mat& srcmat;
Mat& dstmat;
Op& op;
OpInit& opInit;
};
template<typename T, typename ST, class Op, class OpInit = OpNop<ST> > static void
reduceC_( const Mat& srcmat, Mat& dstmat)
{
typedef typename Op::rtype WT;
Op op;
OpInit opInit;
ReduceC_Invoker<T, ST, WT, Op, OpInit> body(srcmat, dstmat, op, opInit);
parallel_for_(Range(0, srcmat.size().height), body);
}
typedef void (*ReduceFunc)( const Mat& src, Mat& dst );
}
#define reduceSumR8u32s reduceR_<uchar, int, OpAdd<int> >
#define reduceSumR8u32f reduceR_<uchar, float, OpAdd<int> >
#define reduceSumR8u64f reduceR_<uchar, double,OpAdd<int> >
#define reduceSumR8u32s reduceR_<uchar, int, OpAdd<int>, OpNop<int> >
#define reduceSumR8u32f reduceR_<uchar, float, OpAdd<int>, OpNop<int> >
#define reduceSumR8u64f reduceR_<uchar, double,OpAdd<int>, OpNop<int> >
#define reduceSumR16u32f reduceR_<ushort,float, OpAdd<float> >
#define reduceSumR16u64f reduceR_<ushort,double,OpAdd<double> >
#define reduceSumR16s32f reduceR_<short, float, OpAdd<float> >
@@ -440,6 +474,17 @@ typedef void (*ReduceFunc)( const Mat& src, Mat& dst );
#define reduceSumR32f64f reduceR_<float, double,OpAdd<double> >
#define reduceSumR64f64f reduceR_<double,double,OpAdd<double> >
#define reduceSum2R8u32s reduceR_<uchar, int, OpAddSqr<int>, OpSqr<int> >
#define reduceSum2R8u32f reduceR_<uchar, float, OpAddSqr<int>, OpSqr<int> >
#define reduceSum2R8u64f reduceR_<uchar, double,OpAddSqr<int>, OpSqr<int> >
#define reduceSum2R16u32f reduceR_<ushort,float, OpAddSqr<float>, OpSqr<float> >
#define reduceSum2R16u64f reduceR_<ushort,double,OpAddSqr<double>,OpSqr<double> >
#define reduceSum2R16s32f reduceR_<short, float, OpAddSqr<float>, OpSqr<float> >
#define reduceSum2R16s64f reduceR_<short, double,OpAddSqr<double>,OpSqr<double> >
#define reduceSum2R32f32f reduceR_<float, float, OpAddSqr<float>, OpSqr<float> >
#define reduceSum2R32f64f reduceR_<float, double,OpAddSqr<double>,OpSqr<double> >
#define reduceSum2R64f64f reduceR_<double,double,OpAddSqr<double>,OpSqr<double> >
#define reduceMaxR8u reduceR_<uchar, uchar, OpMax<uchar> >
#define reduceMaxR16u reduceR_<ushort,ushort,OpMax<ushort> >
#define reduceMaxR16s reduceR_<short, short, OpMax<short> >
@@ -527,23 +572,35 @@ static inline void reduceSumC_8u16u16s32f_64f(const cv::Mat& srcmat, cv::Mat& ds
#endif
#define reduceSumC8u32s reduceC_<uchar, int, OpAdd<int> >
#define reduceSumC8u32f reduceC_<uchar, float, OpAdd<int> >
#define reduceSumC8u32s reduceC_<uchar, int, OpAdd<int>, OpNop<int> >
#define reduceSumC8u32f reduceC_<uchar, float, OpAdd<int>, OpNop<int> >
#define reduceSumC16u32f reduceC_<ushort,float, OpAdd<float> >
#define reduceSumC16s32f reduceC_<short, float, OpAdd<float> >
#define reduceSumC32f32f reduceC_<float, float, OpAdd<float> >
#define reduceSumC64f64f reduceC_<double,double,OpAdd<double> >
#define reduceSum2C8u32s reduceC_<uchar, int, OpAddSqr<int>, OpSqr<int> >
#define reduceSum2C8u32f reduceC_<uchar, float, OpAddSqr<int>, OpSqr<int> >
#define reduceSum2C16u32f reduceC_<ushort,float, OpAddSqr<float>, OpSqr<float> >
#define reduceSum2C16s32f reduceC_<short, float, OpAddSqr<float>, OpSqr<float> >
#define reduceSum2C32f32f reduceC_<float, float, OpAddSqr<float>, OpSqr<float> >
#define reduceSum2C64f64f reduceC_<double,double,OpAddSqr<double>,OpSqr<double> >
#ifdef HAVE_IPP
#define reduceSumC8u64f reduceSumC_8u16u16s32f_64f
#define reduceSumC16u64f reduceSumC_8u16u16s32f_64f
#define reduceSumC16s64f reduceSumC_8u16u16s32f_64f
#define reduceSumC32f64f reduceSumC_8u16u16s32f_64f
#else
#define reduceSumC8u64f reduceC_<uchar, double,OpAdd<int> >
#define reduceSumC8u64f reduceC_<uchar, double,OpAdd<int>, OpNop<int> >
#define reduceSumC16u64f reduceC_<ushort,double,OpAdd<double> >
#define reduceSumC16s64f reduceC_<short, double,OpAdd<double> >
#define reduceSumC32f64f reduceC_<float, double,OpAdd<double> >
#define reduceSum2C8u64f reduceC_<uchar, double,OpAddSqr<int>, OpSqr<int> >
#define reduceSum2C16u64f reduceC_<ushort,double,OpAddSqr<double>,OpSqr<double> >
#define reduceSum2C16s64f reduceC_<short, double,OpAddSqr<double>,OpSqr<double> >
#define reduceSum2C32f64f reduceC_<float, double,OpAddSqr<double>,OpSqr<double> >
#endif
#ifdef HAVE_IPP
@@ -622,8 +679,9 @@ static bool ocl_reduce(InputArray _src, OutputArray _dst,
ddepth = CV_32S;
}
const char * const ops[4] = { "OCL_CV_REDUCE_SUM", "OCL_CV_REDUCE_AVG",
"OCL_CV_REDUCE_MAX", "OCL_CV_REDUCE_MIN" };
const char * const ops[5] = { "OCL_CV_REDUCE_SUM", "OCL_CV_REDUCE_AVG",
"OCL_CV_REDUCE_MAX", "OCL_CV_REDUCE_MIN",
"OCL_CV_REDUCE_SUM2"};
int wdepth = std::max(ddepth, CV_32F);
if (useOptimized)
{
@@ -718,7 +776,8 @@ void cv::reduce(InputArray _src, OutputArray _dst, int dim, int op, int dtype)
CV_Assert( cn == CV_MAT_CN(dtype) );
CV_Assert( op == REDUCE_SUM || op == REDUCE_MAX ||
op == REDUCE_MIN || op == REDUCE_AVG );
op == REDUCE_MIN || op == REDUCE_AVG ||
op == REDUCE_SUM2);
CV_OCL_RUN(_dst.isUMat(),
ocl_reduce(_src, _dst, dim, op, op0, stype, dtype))
@@ -748,7 +807,7 @@ void cv::reduce(InputArray _src, OutputArray _dst, int dim, int op, int dtype)
if( op == REDUCE_SUM )
{
if(sdepth == CV_8U && ddepth == CV_32S)
func = GET_OPTIMIZED(reduceSumR8u32s);
func = reduceSumR8u32s;
else if(sdepth == CV_8U && ddepth == CV_32F)
func = reduceSumR8u32f;
else if(sdepth == CV_8U && ddepth == CV_64F)
@@ -762,7 +821,7 @@ void cv::reduce(InputArray _src, OutputArray _dst, int dim, int op, int dtype)
else if(sdepth == CV_16S && ddepth == CV_64F)
func = reduceSumR16s64f;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceSumR32f32f);
func = reduceSumR32f32f;
else if(sdepth == CV_32F && ddepth == CV_64F)
func = reduceSumR32f64f;
else if(sdepth == CV_64F && ddepth == CV_64F)
@@ -771,36 +830,59 @@ void cv::reduce(InputArray _src, OutputArray _dst, int dim, int op, int dtype)
else if(op == REDUCE_MAX)
{
if(sdepth == CV_8U && ddepth == CV_8U)
func = GET_OPTIMIZED(reduceMaxR8u);
func = reduceMaxR8u;
else if(sdepth == CV_16U && ddepth == CV_16U)
func = reduceMaxR16u;
else if(sdepth == CV_16S && ddepth == CV_16S)
func = reduceMaxR16s;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceMaxR32f);
func = reduceMaxR32f;
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceMaxR64f;
}
else if(op == REDUCE_MIN)
{
if(sdepth == CV_8U && ddepth == CV_8U)
func = GET_OPTIMIZED(reduceMinR8u);
func = reduceMinR8u;
else if(sdepth == CV_16U && ddepth == CV_16U)
func = reduceMinR16u;
else if(sdepth == CV_16S && ddepth == CV_16S)
func = reduceMinR16s;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceMinR32f);
func = reduceMinR32f;
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceMinR64f;
}
else if( op == REDUCE_SUM2 )
{
if(sdepth == CV_8U && ddepth == CV_32S)
func = reduceSum2R8u32s;
else if(sdepth == CV_8U && ddepth == CV_32F)
func = reduceSum2R8u32f;
else if(sdepth == CV_8U && ddepth == CV_64F)
func = reduceSum2R8u64f;
else if(sdepth == CV_16U && ddepth == CV_32F)
func = reduceSum2R16u32f;
else if(sdepth == CV_16U && ddepth == CV_64F)
func = reduceSum2R16u64f;
else if(sdepth == CV_16S && ddepth == CV_32F)
func = reduceSum2R16s32f;
else if(sdepth == CV_16S && ddepth == CV_64F)
func = reduceSum2R16s64f;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = reduceSum2R32f32f;
else if(sdepth == CV_32F && ddepth == CV_64F)
func = reduceSum2R32f64f;
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceSum2R64f64f;
}
}
else
{
if(op == REDUCE_SUM)
{
if(sdepth == CV_8U && ddepth == CV_32S)
func = GET_OPTIMIZED(reduceSumC8u32s);
func = reduceSumC8u32s;
else if(sdepth == CV_8U && ddepth == CV_32F)
func = reduceSumC8u32f;
else if(sdepth == CV_8U && ddepth == CV_64F)
@@ -814,7 +896,7 @@ void cv::reduce(InputArray _src, OutputArray _dst, int dim, int op, int dtype)
else if(sdepth == CV_16S && ddepth == CV_64F)
func = reduceSumC16s64f;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceSumC32f32f);
func = reduceSumC32f32f;
else if(sdepth == CV_32F && ddepth == CV_64F)
func = reduceSumC32f64f;
else if(sdepth == CV_64F && ddepth == CV_64F)
@@ -823,29 +905,52 @@ void cv::reduce(InputArray _src, OutputArray _dst, int dim, int op, int dtype)
else if(op == REDUCE_MAX)
{
if(sdepth == CV_8U && ddepth == CV_8U)
func = GET_OPTIMIZED(reduceMaxC8u);
func = reduceMaxC8u;
else if(sdepth == CV_16U && ddepth == CV_16U)
func = reduceMaxC16u;
else if(sdepth == CV_16S && ddepth == CV_16S)
func = reduceMaxC16s;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceMaxC32f);
func = reduceMaxC32f;
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceMaxC64f;
}
else if(op == REDUCE_MIN)
{
if(sdepth == CV_8U && ddepth == CV_8U)
func = GET_OPTIMIZED(reduceMinC8u);
func = reduceMinC8u;
else if(sdepth == CV_16U && ddepth == CV_16U)
func = reduceMinC16u;
else if(sdepth == CV_16S && ddepth == CV_16S)
func = reduceMinC16s;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = GET_OPTIMIZED(reduceMinC32f);
func = reduceMinC32f;
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceMinC64f;
}
else if(op == REDUCE_SUM2)
{
if(sdepth == CV_8U && ddepth == CV_32S)
func = reduceSum2C8u32s;
else if(sdepth == CV_8U && ddepth == CV_32F)
func = reduceSum2C8u32f;
else if(sdepth == CV_8U && ddepth == CV_64F)
func = reduceSum2C8u64f;
else if(sdepth == CV_16U && ddepth == CV_32F)
func = reduceSum2C16u32f;
else if(sdepth == CV_16U && ddepth == CV_64F)
func = reduceSum2C16u64f;
else if(sdepth == CV_16S && ddepth == CV_32F)
func = reduceSum2C16s32f;
else if(sdepth == CV_16S && ddepth == CV_64F)
func = reduceSum2C16s64f;
else if(sdepth == CV_32F && ddepth == CV_32F)
func = reduceSum2C32f32f;
else if(sdepth == CV_32F && ddepth == CV_64F)
func = reduceSum2C32f64f;
else if(sdepth == CV_64F && ddepth == CV_64F)
func = reduceSum2C64f64f;
}
}
if( !func )
+3
View File
@@ -85,6 +85,9 @@
#elif defined OCL_CV_REDUCE_MIN
#define INIT_VALUE MAX_VAL
#define PROCESS_ELEM(acc, value) acc = min(value, acc)
#elif defined OCL_CV_REDUCE_SUM2
#define INIT_VALUE 0
#define PROCESS_ELEM(acc, value) acc += value*value
#else
#error "No operation is specified"
#endif
+24
View File
@@ -108,6 +108,22 @@ extern const uchar g_Saturate8u[];
#define CV_MIN_8U(a,b) ((a) - CV_FAST_CAST_8U((a) - (b)))
#define CV_MAX_8U(a,b) ((a) + CV_FAST_CAST_8U((b) - (a)))
template<typename T1, typename T2=T1, typename T3=T1> struct OpNop
{
typedef T1 type1;
typedef T2 type2;
typedef T3 rtype;
T3 operator ()(const T1 a) const { return saturate_cast<T3>(a); }
};
template<typename T1, typename T2=T1, typename T3=T1> struct OpSqr
{
typedef T1 type1;
typedef T2 type2;
typedef T3 rtype;
T3 operator ()(const T1 a) const { return saturate_cast<T3>(a)*saturate_cast<T3>(a); }
};
template<typename T1, typename T2=T1, typename T3=T1> struct OpAdd
{
typedef T1 type1;
@@ -116,6 +132,14 @@ template<typename T1, typename T2=T1, typename T3=T1> struct OpAdd
T3 operator ()(const T1 a, const T2 b) const { return saturate_cast<T3>(a + b); }
};
template<typename T1, typename T2=T1, typename T3=T1> struct OpAddSqr
{
typedef T1 type1;
typedef T2 type2;
typedef T3 rtype;
T3 operator ()(const T1 a, const T2 b) const { return saturate_cast<T3>(a + saturate_cast<T3>(b)*saturate_cast<T3>(b)); }
};
template<typename T1, typename T2=T1, typename T3=T1> struct OpSub
{
typedef T1 type1;