From 14dccdf23da27abde55be83e57f580e63ec2cac5 Mon Sep 17 00:00:00 2001 From: Konstantin Matskevich Date: Tue, 3 Dec 2013 14:07:00 +0400 Subject: [PATCH] T-API cv::log, cv::exp, cv::magnitude, cv::phase --- modules/core/src/mathfuncs.cpp | 92 +++++++++++++++++++++++---- modules/core/src/opencl/arithm.cl | 4 +- modules/core/test/ocl/test_arithm.cpp | 80 +++++++++++++++++++++++ 3 files changed, 162 insertions(+), 14 deletions(-) diff --git a/modules/core/src/mathfuncs.cpp b/modules/core/src/mathfuncs.cpp index 2df111f0db..b0dd9a17e1 100644 --- a/modules/core/src/mathfuncs.cpp +++ b/modules/core/src/mathfuncs.cpp @@ -41,7 +41,7 @@ //M*/ #include "precomp.hpp" - +#include "opencl_kernels.hpp" namespace cv { @@ -54,6 +54,50 @@ static const float atan2_p3 = -0.3258083974640975f*(float)(180/CV_PI); static const float atan2_p5 = 0.1555786518463281f*(float)(180/CV_PI); static const float atan2_p7 = -0.04432655554792128f*(float)(180/CV_PI); + +enum { OCL_OP_LOG=0, OCL_OP_EXP=1, OCL_OP_MAG=2, OCL_OP_PHASE_DEGREES=3, OCL_OP_PHASE_RADIANS=4 }; + +static const char* oclop2str[] = { "OP_LOG", "OP_EXP", "OP_MAG", "OP_PHASE_DEGREES", "OP_PHASE_RADIANS", 0 }; + +bool ocl_math_op(InputArray _src1, InputArray _src2, OutputArray _dst, int oclop) +{ + int type1 = _src1.type(), depth1 = CV_MAT_DEPTH(type1), cn1 = CV_MAT_CN(type1); + int type2 = _src2.type(), cn2 = CV_MAT_CN(type2); + + char opts[1024]; + + bool double_support = false; + if(ocl::Device::getDefault().doubleFPConfig() > 0) + double_support = true; + if(!double_support && depth1 == CV_64F) + return false; + + sprintf(opts, "-D %s -D %s -D dstT=%s %s", _src2.empty()?"UNARY_OP":"BINARY_OP", + oclop2str[oclop], ocl::typeToStr(CV_MAKETYPE(depth1, 1) ), double_support ? "-D DOUBLE_SUPPORT" : "" ); + + ocl::Kernel k("KF", ocl::core::arithm_oclsrc, opts); + if( k.empty() ) + return false; + + UMat src1 = _src1.getUMat(); + UMat src2 = _src2.getUMat(); + _dst.create(src1.size(), type1); + UMat dst = _dst.getUMat(); + + ocl::KernelArg src1arg = ocl::KernelArg::ReadOnlyNoSize(src1, cn1); + ocl::KernelArg src2arg = ocl::KernelArg::ReadOnlyNoSize(src2, cn2); + ocl::KernelArg dstarg = ocl::KernelArg::WriteOnly(dst, cn1); + + if(_src2.empty()) + k.args(src1arg, dstarg); + else + k.args(src1arg, src2arg, dstarg); + + size_t globalsize[] = { src1.cols*cn1, src1.rows}; + + return k.run(2, globalsize, 0, false); +} + float fastAtan2( float y, float x ) { float ax = std::abs(x), ay = std::abs(y); @@ -354,9 +398,16 @@ static void Sqrt_64f(const double* src, double* dst, int len) void magnitude( InputArray src1, InputArray src2, OutputArray dst ) { + int type = src1.type(), depth = src1.depth(), cn = src1.channels(); + CV_Assert( src1.size() == src2.size() && type == src2.type() && (depth == CV_32F || depth == CV_64F)); + + bool use_opencl = dst.isUMat() && ocl::useOpenCL() + && src1.dims() <= 2 && src2.dims() <= 2; + + if(use_opencl && ocl_math_op(src1, src2, dst, OCL_OP_MAG) ) + return; + Mat X = src1.getMat(), Y = src2.getMat(); - int type = X.type(), depth = X.depth(), cn = X.channels(); - CV_Assert( X.size == Y.size && type == Y.type() && (depth == CV_32F || depth == CV_64F)); dst.create(X.dims, X.size, X.type()); Mat Mag = dst.getMat(); @@ -385,9 +436,16 @@ void magnitude( InputArray src1, InputArray src2, OutputArray dst ) void phase( InputArray src1, InputArray src2, OutputArray dst, bool angleInDegrees ) { + int type = src1.type(), depth = src1.depth(), cn = src1.channels(); + CV_Assert( src1.size() == src2.size() && type == src2.type() && (depth == CV_32F || depth == CV_64F)); + + bool use_opencl = dst.isUMat() && ocl::useOpenCL() + && src1.dims() <= 2 && src2.dims() <= 2; + + if(use_opencl && ocl_math_op(src1, src2, dst, angleInDegrees ? OCL_OP_PHASE_DEGREES : OCL_OP_PHASE_RADIANS) ) + return; + Mat X = src1.getMat(), Y = src2.getMat(); - int type = X.type(), depth = X.depth(), cn = X.channels(); - CV_Assert( X.size == Y.size && type == Y.type() && (depth == CV_32F || depth == CV_64F)); dst.create( X.dims, X.size, type ); Mat Angle = dst.getMat(); @@ -1151,14 +1209,18 @@ static void Exp_64f( const double *_x, double *y, int n ) void exp( InputArray _src, OutputArray _dst ) { - Mat src = _src.getMat(); - int type = src.type(), depth = src.depth(), cn = src.channels(); + int type = _src.type(), depth = _src.depth(), cn = _src.channels(); + CV_Assert( depth == CV_32F || depth == CV_64F ); + bool use_opencl = _dst.isUMat() && ocl::useOpenCL() && _src.dims() <= 2; + + if(use_opencl && ocl_math_op(_src, noArray(), _dst, OCL_OP_EXP) ) + return; + + Mat src = _src.getMat(); _dst.create( src.dims, src.size, type ); Mat dst = _dst.getMat(); - CV_Assert( depth == CV_32F || depth == CV_64F ); - const Mat* arrays[] = {&src, &dst, 0}; uchar* ptrs[2]; NAryMatIterator it(arrays, ptrs); @@ -1796,14 +1858,18 @@ static void Log_64f( const double *x, double *y, int n ) void log( InputArray _src, OutputArray _dst ) { - Mat src = _src.getMat(); - int type = src.type(), depth = src.depth(), cn = src.channels(); + int type = _src.type(), depth = _src.depth(), cn = _src.channels(); + CV_Assert( depth == CV_32F || depth == CV_64F ); + bool use_opencl = _dst.isUMat() && ocl::useOpenCL() && _src.dims() <= 2; + + if(use_opencl && ocl_math_op(_src, noArray(), _dst, OCL_OP_LOG) ) + return; + + Mat src = _src.getMat(); _dst.create( src.dims, src.size, type ); Mat dst = _dst.getMat(); - CV_Assert( depth == CV_32F || depth == CV_64F ); - const Mat* arrays[] = {&src, &dst, 0}; uchar* ptrs[2]; NAryMatIterator it(arrays, ptrs); diff --git a/modules/core/src/opencl/arithm.cl b/modules/core/src/opencl/arithm.cl index 2f1915cd08..a9c23645ac 100644 --- a/modules/core/src/opencl/arithm.cl +++ b/modules/core/src/opencl/arithm.cl @@ -173,7 +173,9 @@ #define PROCESS_ELEM dstelem = sqrt(srcelem1) #elif defined OP_LOG -#define PROCESS_ELEM dstelem = log(abs(srcelem1)) +#define PROCESS_ELEM \ +dstT v = (dstT)(srcelem1);\ +dstelem = v > (dstT)(0) ? log(v) : log(-v) #elif defined OP_CMP #define PROCESS_ELEM dstelem = convert_uchar(srcelem1 CMP_OPERATOR srcelem2 ? 255 : 0) diff --git a/modules/core/test/ocl/test_arithm.cpp b/modules/core/test/ocl/test_arithm.cpp index 1194bd0f60..c574d004f3 100644 --- a/modules/core/test/ocl/test_arithm.cpp +++ b/modules/core/test/ocl/test_arithm.cpp @@ -281,11 +281,91 @@ OCL_TEST_P(Subtract, Scalar_Mask) } } +//////////////////////////////////////// Log ///////////////////////////////////////// + +typedef ArithmTestBase Log; + +OCL_TEST_P(Log, Mat) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(cv::log(src1_roi, dst1_roi)); + OCL_ON(cv::log(usrc1_roi, udst1_roi)); + Near(1); + } +} + +//////////////////////////////////////// Exp ///////////////////////////////////////// + +typedef ArithmTestBase Exp; + +OCL_TEST_P(Exp, Mat) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(cv::exp(src1_roi, dst1_roi)); + OCL_ON(cv::exp(usrc1_roi, udst1_roi)); + Near(2); + } +} + +//////////////////////////////////////// Phase ///////////////////////////////////////// + +typedef ArithmTestBase Phase; + +OCL_TEST_P(Phase, angleInDegree) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(cv::phase(src1_roi, src2_roi, dst1_roi, true)); + OCL_ON(cv::phase(usrc1_roi, usrc2_roi, udst1_roi, true)); + Near(1e-2); + } +} + +OCL_TEST_P(Phase, angleInRadians) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(cv::phase(src1_roi, src2_roi, dst1_roi)); + OCL_ON(cv::phase(usrc1_roi, usrc2_roi, udst1_roi)); + Near(1e-2); + } +} + +//////////////////////////////////////// Magnitude ///////////////////////////////////////// + +typedef ArithmTestBase Magnitude; + +OCL_TEST_P(Magnitude, Mat) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(cv::magnitude(src1_roi, src2_roi, dst1_roi)); + OCL_ON(cv::magnitude(usrc1_roi, usrc2_roi, udst1_roi)); + Near(depth == CV_64F ? 1e-5 : 1e-2); + } +} + //////////////////////////////////////// Instantiation ///////////////////////////////////////// OCL_INSTANTIATE_TEST_CASE_P(Arithm, Lut, Combine(::testing::Values(CV_8U, CV_8S), OCL_ALL_DEPTHS, ::testing::Values(1, 2, 3, 4), Bool(), Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, Add, Combine(OCL_ALL_DEPTHS, ::testing::Values(1, 2, 4), Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, Subtract, Combine(OCL_ALL_DEPTHS, ::testing::Values(1, 2, 4), Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Log, Combine(::testing::Values(CV_32F, CV_64F), ::testing::Values(1, 2, 3, 4), Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Exp, Combine(::testing::Values(CV_32F, CV_64F), ::testing::Values(1, 2, 3, 4), Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Phase, Combine(::testing::Values(CV_32F, CV_64F), ::testing::Values(1, 2, 3, 4), Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Magnitude, Combine(::testing::Values(CV_32F, CV_64F), ::testing::Values(1, 2, 3, 4), Bool())); } } // namespace cvtest::ocl