mirror of
https://github.com/opencv/opencv.git
synced 2026-07-27 14:23:04 +04:00
373 lines
12 KiB
C++
373 lines
12 KiB
C++
// 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 "opencl_kernels_core.hpp"
|
|
#include "stat.hpp"
|
|
|
|
#include "mean.simd.hpp"
|
|
#include "mean.simd_declarations.hpp" // defines CV_CPU_DISPATCH_MODES_ALL=AVX2,...,BASELINE based on CMakeLists.txt content
|
|
|
|
|
|
namespace cv {
|
|
|
|
Scalar mean(InputArray _src, InputArray _mask)
|
|
{
|
|
CV_INSTRUMENT_REGION();
|
|
|
|
Mat src = _src.getMat(), mask = _mask.getMat();
|
|
CV_Assert( mask.empty() || mask.type() == CV_8U );
|
|
|
|
int k, cn = src.channels(), depth = src.depth();
|
|
Scalar s = Scalar::all(0.0);
|
|
|
|
CV_Assert( cn <= 4 );
|
|
|
|
if (src.isContinuous() && mask.isContinuous())
|
|
{
|
|
CALL_HAL_RET2(meanStdDev, cv_hal_meanStdDev, s, src.data, 0, (int)src.total(), 1, src.type(),
|
|
&s[0], nullptr /*stddev*/, mask.data, 0);
|
|
}
|
|
else
|
|
{
|
|
if (src.dims <= 2)
|
|
{
|
|
CALL_HAL_RET2(meanStdDev, cv_hal_meanStdDev, s, src.data, src.step, src.cols, src.rows, src.type(),
|
|
&s[0], nullptr, mask.data, mask.step);
|
|
}
|
|
}
|
|
|
|
SumFunc func = getSumFunc(depth);
|
|
|
|
CV_Assert( func != 0 );
|
|
|
|
const Mat* arrays[] = {&src, &mask, 0};
|
|
uchar* ptrs[2] = {};
|
|
NAryMatIterator it(arrays, ptrs);
|
|
int total = (int)it.size, blockSize = total, intSumBlockSize = 0;
|
|
int j, count = 0;
|
|
AutoBuffer<int> _buf;
|
|
int* buf = (int*)&s[0];
|
|
bool blockSum = depth <= CV_16S;
|
|
size_t esz = 0, nz0 = 0;
|
|
|
|
if( blockSum )
|
|
{
|
|
intSumBlockSize = depth <= CV_8S ? (1 << 23) : (1 << 15);
|
|
blockSize = std::min(blockSize, intSumBlockSize);
|
|
_buf.allocate(cn);
|
|
buf = _buf.data();
|
|
|
|
for( k = 0; k < cn; k++ )
|
|
buf[k] = 0;
|
|
esz = src.elemSize();
|
|
}
|
|
|
|
for( size_t i = 0; i < it.nplanes; i++, ++it )
|
|
{
|
|
for( j = 0; j < total; j += blockSize )
|
|
{
|
|
int bsz = std::min(total - j, blockSize);
|
|
int nz = func( ptrs[0], ptrs[1], (uchar*)buf, bsz, cn );
|
|
count += nz;
|
|
nz0 += nz;
|
|
if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) )
|
|
{
|
|
for( k = 0; k < cn; k++ )
|
|
{
|
|
s[k] += buf[k];
|
|
buf[k] = 0;
|
|
}
|
|
count = 0;
|
|
}
|
|
ptrs[0] += bsz*esz;
|
|
if( ptrs[1] )
|
|
ptrs[1] += bsz;
|
|
}
|
|
}
|
|
return s*(nz0 ? 1./nz0 : 0);
|
|
}
|
|
|
|
static SumSqrFunc getSumSqrFunc(int depth)
|
|
{
|
|
CV_INSTRUMENT_REGION();
|
|
CV_CPU_DISPATCH(getSumSqrFunc, (depth),
|
|
CV_CPU_DISPATCH_MODES_ALL);
|
|
}
|
|
|
|
#ifdef HAVE_OPENCL
|
|
static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray _mask )
|
|
{
|
|
CV_INSTRUMENT_REGION_OPENCL();
|
|
|
|
bool haveMask = _mask.kind() != _InputArray::NONE;
|
|
int nz = haveMask ? -1 : (int)_src.total();
|
|
Scalar mean(0), stddev(0);
|
|
const int cn = _src.channels();
|
|
if (cn > 4)
|
|
return false;
|
|
|
|
{
|
|
int type = _src.type(), depth = CV_MAT_DEPTH(type);
|
|
bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0,
|
|
isContinuous = _src.isContinuous(),
|
|
isMaskContinuous = _mask.isContinuous();
|
|
const ocl::Device &defDev = ocl::Device::getDefault();
|
|
int groups = defDev.maxComputeUnits();
|
|
if (defDev.isIntel())
|
|
{
|
|
static const int subSliceEUCount = 10;
|
|
groups = (groups / subSliceEUCount) * 2;
|
|
}
|
|
size_t wgs = defDev.maxWorkGroupSize();
|
|
|
|
int ddepth = std::max(CV_32S, depth), sqddepth = std::max(CV_32F, depth),
|
|
dtype = CV_MAKE_TYPE(ddepth, cn),
|
|
sqdtype = CV_MAKETYPE(sqddepth, cn);
|
|
CV_Assert(!haveMask || _mask.type() == CV_8UC1);
|
|
|
|
int wgs2_aligned = 1;
|
|
while (wgs2_aligned < (int)wgs)
|
|
wgs2_aligned <<= 1;
|
|
wgs2_aligned >>= 1;
|
|
|
|
if ( (!doubleSupport && depth == CV_64F) )
|
|
return false;
|
|
|
|
char cvt[2][50];
|
|
String opts = format("-D srcT=%s -D srcT1=%s -D dstT=%s -D dstT1=%s -D sqddepth=%d"
|
|
" -D sqdstT=%s -D sqdstT1=%s -D convertToSDT=%s -D cn=%d%s%s"
|
|
" -D convertToDT=%s -D WGS=%d -D WGS2_ALIGNED=%d%s%s",
|
|
ocl::typeToStr(type), ocl::typeToStr(depth),
|
|
ocl::typeToStr(dtype), ocl::typeToStr(ddepth), sqddepth,
|
|
ocl::typeToStr(sqdtype), ocl::typeToStr(sqddepth),
|
|
ocl::convertTypeStr(depth, sqddepth, cn, cvt[0], sizeof(cvt[0])),
|
|
cn, isContinuous ? " -D HAVE_SRC_CONT" : "",
|
|
isMaskContinuous ? " -D HAVE_MASK_CONT" : "",
|
|
ocl::convertTypeStr(depth, ddepth, cn, cvt[1], sizeof(cvt[1])),
|
|
(int)wgs, wgs2_aligned, haveMask ? " -D HAVE_MASK" : "",
|
|
doubleSupport ? " -D DOUBLE_SUPPORT" : "");
|
|
|
|
ocl::Kernel k("meanStdDev", ocl::core::meanstddev_oclsrc, opts);
|
|
if (k.empty())
|
|
return false;
|
|
|
|
int dbsize = groups * ((haveMask ? CV_ELEM_SIZE1(CV_32S) : 0) +
|
|
CV_ELEM_SIZE(sqdtype) + CV_ELEM_SIZE(dtype));
|
|
UMat src = _src.getUMat(), db(1, dbsize, CV_8UC1), mask = _mask.getUMat();
|
|
|
|
ocl::KernelArg srcarg = ocl::KernelArg::ReadOnlyNoSize(src),
|
|
dbarg = ocl::KernelArg::PtrWriteOnly(db),
|
|
maskarg = ocl::KernelArg::ReadOnlyNoSize(mask);
|
|
|
|
if (haveMask)
|
|
k.args(srcarg, src.cols, (int)src.total(), groups, dbarg, maskarg);
|
|
else
|
|
k.args(srcarg, src.cols, (int)src.total(), groups, dbarg);
|
|
|
|
size_t globalsize = groups * wgs;
|
|
|
|
if(!k.run(1, &globalsize, &wgs, false))
|
|
return false;
|
|
|
|
typedef Scalar (* part_sum)(Mat m);
|
|
part_sum funcs[3] = { ocl_part_sum<int>, ocl_part_sum<float>, ocl_part_sum<double> };
|
|
Mat dbm = db.getMat(ACCESS_READ);
|
|
|
|
mean = funcs[ddepth - CV_32S](Mat(1, groups, dtype, dbm.ptr()));
|
|
stddev = funcs[sqddepth - CV_32S](Mat(1, groups, sqdtype, dbm.ptr() + groups * CV_ELEM_SIZE(dtype)));
|
|
|
|
if (haveMask)
|
|
nz = saturate_cast<int>(funcs[0](Mat(1, groups, CV_32SC1, dbm.ptr() +
|
|
groups * (CV_ELEM_SIZE(dtype) +
|
|
CV_ELEM_SIZE(sqdtype))))[0]);
|
|
}
|
|
|
|
double total = nz != 0 ? 1.0 / nz : 0;
|
|
int k, j;
|
|
for (int i = 0; i < cn; ++i)
|
|
{
|
|
mean[i] *= total;
|
|
stddev[i] = std::sqrt(std::max(stddev[i] * total - mean[i] * mean[i] , 0.));
|
|
}
|
|
|
|
for( j = 0; j < 2; j++ )
|
|
{
|
|
const double * const sptr = j == 0 ? &mean[0] : &stddev[0];
|
|
_OutputArray _dst = j == 0 ? _mean : _sdv;
|
|
if( !_dst.needed() )
|
|
continue;
|
|
|
|
if( !_dst.fixedSize() )
|
|
_dst.create(cn, 1, CV_64F, -1, true);
|
|
Mat dst = _dst.getMat();
|
|
int dcn = (int)dst.total();
|
|
CV_Assert( dst.type() == CV_64F && dst.isContinuous() &&
|
|
(dst.cols == 1 || dst.rows == 1) && dcn >= cn );
|
|
double* dptr = dst.ptr<double>();
|
|
for( k = 0; k < cn; k++ )
|
|
dptr[k] = sptr[k];
|
|
for( ; k < dcn; k++ )
|
|
dptr[k] = 0;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
void meanStdDev(InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray _mask)
|
|
{
|
|
CV_INSTRUMENT_REGION();
|
|
|
|
CV_Assert(!_src.empty());
|
|
CV_Assert( _mask.empty() || _mask.type() == CV_8UC1 );
|
|
|
|
CV_OCL_RUN(OCL_PERFORMANCE_CHECK(_src.isUMat()) && _src.dims() <= 2,
|
|
ocl_meanStdDev(_src, _mean, _sdv, _mask))
|
|
|
|
Mat src = _src.getMat(), mask = _mask.getMat();
|
|
|
|
CV_Assert(mask.empty() || src.size == mask.size);
|
|
|
|
int k, cn = src.channels(), depth = src.depth();
|
|
Mat mean_mat, stddev_mat;
|
|
|
|
if(_mean.needed())
|
|
{
|
|
if( !_mean.fixedSize() )
|
|
_mean.create(cn, 1, CV_64F, -1, true);
|
|
|
|
mean_mat = _mean.getMat();
|
|
int dcn = (int)mean_mat.total();
|
|
CV_Assert( mean_mat.type() == CV_64F && mean_mat.isContinuous() &&
|
|
(mean_mat.cols == 1 || mean_mat.rows == 1) && dcn >= cn );
|
|
|
|
double* dptr = mean_mat.ptr<double>();
|
|
for(k = cn ; k < dcn; k++ )
|
|
dptr[k] = 0;
|
|
}
|
|
|
|
if (_sdv.needed())
|
|
{
|
|
if( !_sdv.fixedSize() )
|
|
_sdv.create(cn, 1, CV_64F, -1, true);
|
|
|
|
stddev_mat = _sdv.getMat();
|
|
int dcn = (int)stddev_mat.total();
|
|
CV_Assert( stddev_mat.type() == CV_64F && stddev_mat.isContinuous() &&
|
|
(stddev_mat.cols == 1 || stddev_mat.rows == 1) && dcn >= cn );
|
|
|
|
double* dptr = stddev_mat.ptr<double>();
|
|
for(k = cn ; k < dcn; k++ )
|
|
dptr[k] = 0;
|
|
|
|
}
|
|
|
|
if (src.isContinuous() && mask.isContinuous())
|
|
{
|
|
CALL_HAL(meanStdDev, cv_hal_meanStdDev, src.data, 0, (int)src.total(), 1, src.type(),
|
|
_mean.needed() ? mean_mat.ptr<double>() : nullptr,
|
|
_sdv.needed() ? stddev_mat.ptr<double>() : nullptr,
|
|
mask.data, 0);
|
|
}
|
|
else
|
|
{
|
|
if (src.dims <= 2)
|
|
{
|
|
CALL_HAL(meanStdDev, cv_hal_meanStdDev, src.data, src.step, src.cols, src.rows, src.type(),
|
|
_mean.needed() ? mean_mat.ptr<double>() : nullptr,
|
|
_sdv.needed() ? stddev_mat.ptr<double>() : nullptr,
|
|
mask.data, mask.step);
|
|
}
|
|
}
|
|
|
|
SumSqrFunc func = getSumSqrFunc(depth);
|
|
|
|
CV_Assert( func != 0 );
|
|
|
|
const Mat* arrays[] = {&src, &mask, 0};
|
|
uchar* ptrs[2] = {};
|
|
NAryMatIterator it(arrays, ptrs);
|
|
int total = (int)it.size, blockSize = total, intSumBlockSize = 0;
|
|
int j;
|
|
int64_t count = 0, nz0 = 0;
|
|
AutoBuffer<double> _buf(cn*4);
|
|
double *s = (double*)_buf.data(), *sq = s + cn;
|
|
int *sbuf = (int*)s, *sqbuf = (int*)sq;
|
|
bool blockSum = depth <= CV_16S, blockSqSum = depth <= CV_8S;
|
|
size_t esz = 0;
|
|
|
|
for( k = 0; k < cn; k++ )
|
|
s[k] = sq[k] = 0;
|
|
|
|
if( blockSum )
|
|
{
|
|
intSumBlockSize = 1 << 15;
|
|
blockSize = std::min(blockSize, intSumBlockSize);
|
|
sbuf = (int*)(sq + cn);
|
|
if( blockSqSum )
|
|
sqbuf = sbuf + cn;
|
|
for( k = 0; k < cn; k++ )
|
|
sbuf[k] = sqbuf[k] = 0;
|
|
esz = src.elemSize();
|
|
}
|
|
|
|
for( size_t i = 0; i < it.nplanes; i++, ++it )
|
|
{
|
|
for( j = 0; j < total; j += blockSize )
|
|
{
|
|
int bsz = std::min(total - j, blockSize);
|
|
int nz = func( ptrs[0], ptrs[1], (uchar*)sbuf, (uchar*)sqbuf, bsz, cn );
|
|
count += nz;
|
|
nz0 += nz;
|
|
if( blockSum && (count + blockSize >= intSumBlockSize || (i+1 >= it.nplanes && j+bsz >= total)) )
|
|
{
|
|
for( k = 0; k < cn; k++ )
|
|
{
|
|
s[k] += sbuf[k];
|
|
sbuf[k] = 0;
|
|
}
|
|
if( blockSqSum )
|
|
{
|
|
for( k = 0; k < cn; k++ )
|
|
{
|
|
sq[k] += sqbuf[k];
|
|
sqbuf[k] = 0;
|
|
}
|
|
}
|
|
count = 0;
|
|
}
|
|
ptrs[0] += bsz*esz;
|
|
if( ptrs[1] )
|
|
ptrs[1] += bsz;
|
|
}
|
|
}
|
|
|
|
double scale = nz0 ? 1./nz0 : 0.;
|
|
for( k = 0; k < cn; k++ )
|
|
{
|
|
s[k] *= scale;
|
|
sq[k] = std::sqrt(std::max(sq[k]*scale - s[k]*s[k], 0.));
|
|
}
|
|
|
|
if (_mean.needed())
|
|
{
|
|
const double* sptr = s;
|
|
double* dptr = mean_mat.ptr<double>();
|
|
for( k = 0; k < cn; k++ )
|
|
dptr[k] = sptr[k];
|
|
}
|
|
|
|
if (_sdv.needed())
|
|
{
|
|
const double* sptr = sq;
|
|
double* dptr = stddev_mat.ptr<double>();
|
|
for( k = 0; k < cn; k++ )
|
|
dptr[k] = sptr[k];
|
|
}
|
|
}
|
|
|
|
} // namespace
|