Merge pull request #2105 from ilya-lavrenov:norm
This commit is contained in:
commit
5a9900481a
@ -60,7 +60,7 @@ inline void _InputArray::init(int _flags, const void* _obj, Size _sz)
|
||||
|
||||
inline void* _InputArray::getObj() const { return obj; }
|
||||
|
||||
inline _InputArray::_InputArray() { init(0, 0); }
|
||||
inline _InputArray::_InputArray() { init(NONE, 0); }
|
||||
inline _InputArray::_InputArray(int _flags, void* _obj) { init(_flags, _obj); }
|
||||
inline _InputArray::_InputArray(const Mat& m) { init(MAT+ACCESS_READ, &m); }
|
||||
inline _InputArray::_InputArray(const std::vector<Mat>& vec) { init(STD_VECTOR_MAT+ACCESS_READ, &vec); }
|
||||
|
@ -651,13 +651,13 @@ OCL_PERF_TEST_P(SetIdentityFixture, SetIdentity,
|
||||
|
||||
typedef Size_MatType MeanStdDevFixture;
|
||||
|
||||
OCL_PERF_TEST_P(MeanStdDevFixture, DISABLED_MeanStdDev,
|
||||
OCL_PERF_TEST_P(MeanStdDevFixture, MeanStdDev,
|
||||
::testing::Combine(OCL_PERF_ENUM(OCL_SIZE_1, OCL_SIZE_2, OCL_SIZE_3), OCL_TEST_TYPES))
|
||||
{
|
||||
const Size_MatType_t params = GetParam();
|
||||
const Size srcSize = get<0>(params);
|
||||
const int type = get<1>(params);
|
||||
const double eps = 1e-5;
|
||||
const double eps = 2e-5;
|
||||
|
||||
checkDeviceMaxMemoryAllocSize(srcSize, type);
|
||||
|
||||
@ -687,7 +687,7 @@ CV_ENUM(NormType, NORM_INF, NORM_L1, NORM_L2)
|
||||
typedef std::tr1::tuple<Size, MatType, NormType> NormParams;
|
||||
typedef TestBaseWithParam<NormParams> NormFixture;
|
||||
|
||||
OCL_PERF_TEST_P(NormFixture, DISABLED_Norm,
|
||||
OCL_PERF_TEST_P(NormFixture, Norm,
|
||||
::testing::Combine(OCL_PERF_ENUM(OCL_SIZE_1, OCL_SIZE_2, OCL_SIZE_3), OCL_TEST_TYPES, NormType::all()))
|
||||
{
|
||||
const NormParams params = GetParam();
|
||||
@ -703,7 +703,7 @@ OCL_PERF_TEST_P(NormFixture, DISABLED_Norm,
|
||||
|
||||
OCL_TEST_CYCLE() res = cv::norm(src1, src2, normType);
|
||||
|
||||
SANITY_CHECK(res, 1e-6, ERROR_RELATIVE);
|
||||
SANITY_CHECK(res, 1e-5, ERROR_RELATIVE);
|
||||
}
|
||||
|
||||
///////////// Repeat ////////////////////////
|
||||
|
@ -51,7 +51,12 @@
|
||||
#endif
|
||||
|
||||
#define noconvert
|
||||
|
||||
#ifdef HAVE_MASK
|
||||
#define EXTRA_PARAMS , __global const uchar * mask, int mask_step, int mask_offset
|
||||
#else
|
||||
#define EXTRA_PARAMS
|
||||
#endif
|
||||
|
||||
#if defined OP_SUM || defined OP_SUM_ABS || defined OP_SUM_SQR
|
||||
#if OP_SUM
|
||||
@ -65,11 +70,19 @@
|
||||
__local dstT localmem[WGS2_ALIGNED]
|
||||
#define DEFINE_ACCUMULATOR \
|
||||
dstT accumulator = (dstT)(0)
|
||||
#ifdef HAVE_MASK
|
||||
#define REDUCE_GLOBAL \
|
||||
dstT temp = convertToDT(src[0]); \
|
||||
int mask_index = mad24(id / cols, mask_step, mask_offset + (id % cols)); \
|
||||
if (mask[mask_index]) \
|
||||
FUNC(accumulator, temp)
|
||||
#else
|
||||
#define REDUCE_GLOBAL \
|
||||
dstT temp = convertToDT(src[0]); \
|
||||
FUNC(accumulator, temp)
|
||||
#endif
|
||||
#define SET_LOCAL_1 \
|
||||
localmem[lid] = accumulator
|
||||
localmem[lid] = accumulator
|
||||
#define REDUCE_LOCAL_1 \
|
||||
localmem[lid - WGS2_ALIGNED] += accumulator
|
||||
#define REDUCE_LOCAL_2 \
|
||||
@ -88,7 +101,7 @@
|
||||
#define REDUCE_GLOBAL \
|
||||
accumulator += src[0] == zero ? zero : one
|
||||
#define SET_LOCAL_1 \
|
||||
localmem[lid] = accumulator
|
||||
localmem[lid] = accumulator
|
||||
#define REDUCE_LOCAL_1 \
|
||||
localmem[lid - WGS2_ALIGNED] += accumulator
|
||||
#define REDUCE_LOCAL_2 \
|
||||
|
@ -466,7 +466,7 @@ template <typename T> Scalar ocl_part_sum(Mat m)
|
||||
|
||||
enum { OCL_OP_SUM = 0, OCL_OP_SUM_ABS = 1, OCL_OP_SUM_SQR = 2 };
|
||||
|
||||
static bool ocl_sum( InputArray _src, Scalar & res, int sum_op )
|
||||
static bool ocl_sum( InputArray _src, Scalar & res, int sum_op, InputArray _mask = noArray() )
|
||||
{
|
||||
CV_Assert(sum_op == OCL_OP_SUM || sum_op == OCL_OP_SUM_ABS || sum_op == OCL_OP_SUM_SQR);
|
||||
|
||||
@ -479,7 +479,10 @@ static bool ocl_sum( InputArray _src, Scalar & res, int sum_op )
|
||||
int dbsize = ocl::Device::getDefault().maxComputeUnits();
|
||||
size_t wgs = ocl::Device::getDefault().maxWorkGroupSize();
|
||||
|
||||
int ddepth = std::max(CV_32S, depth), dtype = CV_MAKE_TYPE(ddepth, cn);
|
||||
int ddepth = std::max(sum_op == OCL_OP_SUM_SQR ? CV_32F : CV_32S, depth),
|
||||
dtype = CV_MAKE_TYPE(ddepth, cn);
|
||||
bool haveMask = _mask.kind() != _InputArray::NONE;
|
||||
CV_Assert(!haveMask || _mask.type() == CV_8UC1);
|
||||
|
||||
int wgs2_aligned = 1;
|
||||
while (wgs2_aligned < (int)wgs)
|
||||
@ -489,19 +492,27 @@ static bool ocl_sum( InputArray _src, Scalar & res, int sum_op )
|
||||
static const char * const opMap[3] = { "OP_SUM", "OP_SUM_ABS", "OP_SUM_SQR" };
|
||||
char cvt[40];
|
||||
ocl::Kernel k("reduce", ocl::core::reduce_oclsrc,
|
||||
format("-D srcT=%s -D dstT=%s -D convertToDT=%s -D %s -D WGS=%d -D WGS2_ALIGNED=%d%s",
|
||||
format("-D srcT=%s -D dstT=%s -D convertToDT=%s -D %s -D WGS=%d -D WGS2_ALIGNED=%d%s%s",
|
||||
ocl::typeToStr(type), ocl::typeToStr(dtype), ocl::convertTypeStr(depth, ddepth, cn, cvt),
|
||||
opMap[sum_op], (int)wgs, wgs2_aligned,
|
||||
doubleSupport ? " -D DOUBLE_SUPPORT" : ""));
|
||||
doubleSupport ? " -D DOUBLE_SUPPORT" : "",
|
||||
haveMask ? " -D HAVE_MASK" : ""));
|
||||
if (k.empty())
|
||||
return false;
|
||||
|
||||
UMat src = _src.getUMat(), db(1, dbsize, dtype);
|
||||
k.args(ocl::KernelArg::ReadOnlyNoSize(src), src.cols, (int)src.total(),
|
||||
dbsize, ocl::KernelArg::PtrWriteOnly(db));
|
||||
UMat src = _src.getUMat(), db(1, dbsize, dtype), 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(), dbsize, dbarg, maskarg);
|
||||
else
|
||||
k.args(srcarg, src.cols, (int)src.total(), dbsize, dbarg);
|
||||
|
||||
size_t globalsize = dbsize * wgs;
|
||||
if (k.run(1, &globalsize, &wgs, true))
|
||||
if (k.run(1, &globalsize, &wgs, false))
|
||||
{
|
||||
typedef Scalar (*part_sum)(Mat m);
|
||||
part_sum funcs[3] = { ocl_part_sum<int>, ocl_part_sum<float>, ocl_part_sum<double> },
|
||||
@ -806,15 +817,18 @@ cv::Scalar cv::mean( InputArray _src, InputArray _mask )
|
||||
|
||||
namespace cv {
|
||||
|
||||
static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv )
|
||||
static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray _mask )
|
||||
{
|
||||
bool haveMask = _mask.kind() != _InputArray::NONE;
|
||||
|
||||
Scalar mean, stddev;
|
||||
if (!ocl_sum(_src, mean, OCL_OP_SUM))
|
||||
if (!ocl_sum(_src, mean, OCL_OP_SUM, _mask))
|
||||
return false;
|
||||
if (!ocl_sum(_src, stddev, OCL_OP_SUM_SQR))
|
||||
if (!ocl_sum(_src, stddev, OCL_OP_SUM_SQR, _mask))
|
||||
return false;
|
||||
|
||||
double total = 1.0 / _src.total();
|
||||
int nz = haveMask ? countNonZero(_mask) : (int)_src.total();
|
||||
double total = nz != 0 ? 1.0 / nz : 0;
|
||||
int k, j, cn = _src.channels();
|
||||
for (int i = 0; i < cn; ++i)
|
||||
{
|
||||
@ -849,7 +863,7 @@ static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv
|
||||
|
||||
void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray _mask )
|
||||
{
|
||||
if (ocl::useOpenCL() && _src.isUMat() && _mask.empty() && ocl_meanStdDev(_src, _mean, _sdv))
|
||||
if (ocl::useOpenCL() && _src.isUMat() && ocl_meanStdDev(_src, _mean, _sdv, _mask))
|
||||
return;
|
||||
|
||||
Mat src = _src.getMat(), mask = _mask.getMat();
|
||||
@ -1882,13 +1896,14 @@ static NormDiffFunc getNormDiffFunc(int normType, int depth)
|
||||
|
||||
namespace cv {
|
||||
|
||||
static bool ocl_norm( InputArray _src, int normType, double & result )
|
||||
static bool ocl_norm( InputArray _src, int normType, InputArray _mask, double & result )
|
||||
{
|
||||
int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
|
||||
bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0;
|
||||
bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0,
|
||||
haveMask = _mask.kind() != _InputArray::NONE;
|
||||
|
||||
if ( !(normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2) ||
|
||||
(!doubleSupport && depth == CV_64F))
|
||||
(!doubleSupport && depth == CV_64F) || (normType == NORM_INF && haveMask && cn != 1))
|
||||
return false;
|
||||
|
||||
UMat src = _src.getUMat();
|
||||
@ -1920,16 +1935,25 @@ static bool ocl_norm( InputArray _src, int normType, double & result )
|
||||
else
|
||||
abssrc = src;
|
||||
|
||||
cv::minMaxIdx(abssrc.reshape(1), NULL, &result);
|
||||
cv::minMaxIdx(haveMask ? abssrc : abssrc.reshape(1), NULL, &result, NULL, NULL, _mask);
|
||||
}
|
||||
else if (normType == NORM_L1 || normType == NORM_L2)
|
||||
{
|
||||
Scalar s;
|
||||
Scalar sc;
|
||||
bool unstype = depth == CV_8U || depth == CV_16U;
|
||||
|
||||
ocl_sum(src.reshape(1), s, normType == NORM_L2 ?
|
||||
OCL_OP_SUM_SQR : (unstype ? OCL_OP_SUM : OCL_OP_SUM_ABS) );
|
||||
result = normType == NORM_L1 ? s[0] : std::sqrt(s[0]);
|
||||
if ( !ocl_sum(haveMask ? src : src.reshape(1), sc, normType == NORM_L2 ?
|
||||
OCL_OP_SUM_SQR : (unstype ? OCL_OP_SUM : OCL_OP_SUM_ABS), _mask) )
|
||||
return false;
|
||||
|
||||
if (!haveMask)
|
||||
cn = 1;
|
||||
|
||||
double s = 0.0;
|
||||
for (int i = 0; i < cn; ++i)
|
||||
s += sc[i];
|
||||
|
||||
result = normType == NORM_L1 ? s : std::sqrt(s);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1945,7 +1969,7 @@ double cv::norm( InputArray _src, int normType, InputArray _mask )
|
||||
((normType == NORM_HAMMING || normType == NORM_HAMMING2) && _src.type() == CV_8U) );
|
||||
|
||||
double _result = 0;
|
||||
if (ocl::useOpenCL() && _mask.empty() && _src.isUMat() && _src.dims() <= 2 && ocl_norm(_src, normType, _result))
|
||||
if (ocl::useOpenCL() && _src.isUMat() && _src.dims() <= 2 && ocl_norm(_src, normType, _mask, _result))
|
||||
return _result;
|
||||
|
||||
Mat src = _src.getMat(), mask = _mask.getMat();
|
||||
|
@ -924,6 +924,44 @@ OCL_TEST_P(MeanStdDev, Mat)
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(MeanStdDev, Mat_Mask)
|
||||
{
|
||||
for (int j = 0; j < test_loop_times; j++)
|
||||
{
|
||||
generateTestData();
|
||||
|
||||
Scalar cpu_mean, cpu_stddev;
|
||||
Scalar gpu_mean, gpu_stddev;
|
||||
|
||||
OCL_OFF(cv::meanStdDev(src1_roi, cpu_mean, cpu_stddev, mask_roi));
|
||||
OCL_ON(cv::meanStdDev(usrc1_roi, gpu_mean, gpu_stddev, umask_roi));
|
||||
|
||||
for (int i = 0; i < cn; ++i)
|
||||
{
|
||||
EXPECT_NEAR(cpu_mean[i], gpu_mean[i], 0.1);
|
||||
EXPECT_NEAR(cpu_stddev[i], gpu_stddev[i], 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST(MeanStdDev_, ZeroMask)
|
||||
{
|
||||
Size size(5, 5);
|
||||
UMat um(size, CV_32SC1), umask(size, CV_8UC1, Scalar::all(0));
|
||||
Mat m(size, CV_32SC1), mask(size, CV_8UC1, Scalar::all(0));
|
||||
|
||||
Scalar cpu_mean, cpu_stddev;
|
||||
Scalar gpu_mean, gpu_stddev;
|
||||
|
||||
OCL_OFF(cv::meanStdDev(m, cpu_mean, cpu_stddev, mask));
|
||||
OCL_ON(cv::meanStdDev(um, gpu_mean, gpu_stddev, umask));
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_NEAR(cpu_mean[i], gpu_mean[i], 0.1);
|
||||
EXPECT_NEAR(cpu_stddev[i], gpu_stddev[i], 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////// Log /////////////////////////////////////////
|
||||
|
||||
@ -1124,6 +1162,19 @@ OCL_TEST_P(Norm, NORM_INF_1arg)
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_INF_1arg_mask)
|
||||
{
|
||||
for (int j = 0; j < test_loop_times; j++)
|
||||
{
|
||||
generateTestData();
|
||||
|
||||
OCL_OFF(const double cpuRes = cv::norm(src1_roi, NORM_INF, mask_roi));
|
||||
OCL_ON(const double gpuRes = cv::norm(usrc1_roi, NORM_INF, umask_roi));
|
||||
|
||||
EXPECT_NEAR(cpuRes, gpuRes, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_L1_1arg)
|
||||
{
|
||||
for (int j = 0; j < test_loop_times; j++)
|
||||
@ -1137,6 +1188,19 @@ OCL_TEST_P(Norm, NORM_L1_1arg)
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_L1_1arg_mask)
|
||||
{
|
||||
for (int j = 0; j < test_loop_times; j++)
|
||||
{
|
||||
generateTestData();
|
||||
|
||||
OCL_OFF(const double cpuRes = cv::norm(src1_roi, NORM_L1, mask_roi));
|
||||
OCL_ON(const double gpuRes = cv::norm(usrc1_roi, NORM_L1, umask_roi));
|
||||
|
||||
EXPECT_PRED3(relativeError, cpuRes, gpuRes, 1e-6);
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_L2_1arg)
|
||||
{
|
||||
for (int j = 0; j < test_loop_times; j++)
|
||||
@ -1150,6 +1214,19 @@ OCL_TEST_P(Norm, NORM_L2_1arg)
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_L2_1arg_mask)
|
||||
{
|
||||
for (int j = 0; j < test_loop_times; j++)
|
||||
{
|
||||
generateTestData();
|
||||
|
||||
OCL_OFF(const double cpuRes = cv::norm(src1_roi, NORM_L2, mask_roi));
|
||||
OCL_ON(const double gpuRes = cv::norm(usrc1_roi, NORM_L2, umask_roi));
|
||||
|
||||
EXPECT_PRED3(relativeError, cpuRes, gpuRes, 1e-6);
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_INF_2args)
|
||||
{
|
||||
for (int relative = 0; relative < 2; ++relative)
|
||||
@ -1168,6 +1245,24 @@ OCL_TEST_P(Norm, NORM_INF_2args)
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_INF_2args_mask)
|
||||
{
|
||||
for (int relative = 0; relative < 2; ++relative)
|
||||
for (int j = 0; j < test_loop_times; j++)
|
||||
{
|
||||
generateTestData();
|
||||
|
||||
int type = NORM_INF;
|
||||
if (relative == 1)
|
||||
type |= NORM_RELATIVE;
|
||||
|
||||
OCL_OFF(const double cpuRes = cv::norm(src1_roi, src2_roi, type, mask_roi));
|
||||
OCL_ON(const double gpuRes = cv::norm(usrc1_roi, usrc2_roi, type, umask_roi));
|
||||
|
||||
EXPECT_NEAR(cpuRes, gpuRes, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_L1_2args)
|
||||
{
|
||||
for (int relative = 0; relative < 2; ++relative)
|
||||
@ -1186,6 +1281,24 @@ OCL_TEST_P(Norm, NORM_L1_2args)
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_L1_2args_mask)
|
||||
{
|
||||
for (int relative = 0; relative < 2; ++relative)
|
||||
for (int j = 0; j < test_loop_times; j++)
|
||||
{
|
||||
generateTestData();
|
||||
|
||||
int type = NORM_L1;
|
||||
if (relative == 1)
|
||||
type |= NORM_RELATIVE;
|
||||
|
||||
OCL_OFF(const double cpuRes = cv::norm(src1_roi, src2_roi, type, mask_roi));
|
||||
OCL_ON(const double gpuRes = cv::norm(usrc1_roi, usrc2_roi, type, umask_roi));
|
||||
|
||||
EXPECT_PRED3(relativeError, cpuRes, gpuRes, 1e-6);
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_L2_2args)
|
||||
{
|
||||
for (int relative = 0; relative < 2; ++relative)
|
||||
@ -1204,6 +1317,24 @@ OCL_TEST_P(Norm, NORM_L2_2args)
|
||||
}
|
||||
}
|
||||
|
||||
OCL_TEST_P(Norm, NORM_L2_2args_mask)
|
||||
{
|
||||
for (int relative = 0; relative < 2; ++relative)
|
||||
for (int j = 0; j < test_loop_times; j++)
|
||||
{
|
||||
generateTestData();
|
||||
|
||||
int type = NORM_L2;
|
||||
if (relative == 1)
|
||||
type |= NORM_RELATIVE;
|
||||
|
||||
OCL_OFF(const double cpuRes = cv::norm(src1_roi, src2_roi, type, mask_roi));
|
||||
OCL_ON(const double gpuRes = cv::norm(usrc1_roi, usrc2_roi, type, umask_roi));
|
||||
|
||||
EXPECT_PRED3(relativeError, cpuRes, gpuRes, 1e-6);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////// Sqrt ////////////////////////////////////////////////
|
||||
|
||||
typedef ArithmTestBase Sqrt;
|
||||
@ -1355,7 +1486,7 @@ OCL_TEST_P(ScaleAdd, Mat)
|
||||
OCL_OFF(cv::scaleAdd(src1_roi, val[0], src2_roi, dst1_roi));
|
||||
OCL_ON(cv::scaleAdd(usrc1_roi, val[0], usrc2_roi, udst1_roi));
|
||||
|
||||
Near(depth <= CV_32S ? 1 : 1e-6);
|
||||
Near(depth <= CV_32S ? 1 : 1e-3);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,6 +318,8 @@ IMPLEMENT_PARAM_CLASS(Channels, int)
|
||||
#endif // IMPLEMENT_PARAM_CLASS
|
||||
|
||||
#define OCL_TEST_P TEST_P
|
||||
#define OCL_TEST_F(name, ...) typedef name OCL_##name; TEST_F(OCL_##name, __VA_ARGS__)
|
||||
#define OCL_TEST(name, ...) TEST(OCL_##name, __VA_ARGS__)
|
||||
|
||||
#define OCL_OFF(fn) cv::ocl::setUseOpenCL(false); fn
|
||||
#define OCL_ON(fn) cv::ocl::setUseOpenCL(true); fn
|
||||
|
Loading…
x
Reference in New Issue
Block a user