From ddca47040b01ae7fff0f6028fbc1acb3f3f1e0d4 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 16 Aug 2012 16:23:27 +0400 Subject: [PATCH 001/163] updated gpu accuracy tests added posibility to specify device on which tests will be executed --- modules/gpu/test/main.cpp | 91 +++++++++++------ modules/gpu/test/precomp.hpp | 1 + modules/gpu/test/utility.cpp | 183 +++++++++++++++++++++++++++-------- modules/gpu/test/utility.hpp | 21 ++-- 4 files changed, 219 insertions(+), 77 deletions(-) diff --git a/modules/gpu/test/main.cpp b/modules/gpu/test/main.cpp index 6a8c67d79f..6df7db0a1b 100644 --- a/modules/gpu/test/main.cpp +++ b/modules/gpu/test/main.cpp @@ -49,35 +49,39 @@ using namespace cv::gpu; using namespace cvtest; using namespace testing; -void print_info() +void printInfo() { - printf("\n"); #if defined _WIN32 # if defined _WIN64 - puts("OS: Windows 64"); + puts("OS: Windows x64"); # else - puts("OS: Windows 32"); + puts("OS: Windows x32"); # endif #elif defined linux # if defined _LP64 - puts("OS: Linux 64"); + puts("OS: Linux x64"); # else - puts("OS: Linux 32"); + puts("OS: Linux x32"); # endif #elif defined __APPLE__ # if defined _LP64 - puts("OS: Apple 64"); + puts("OS: Apple x64"); # else - puts("OS: Apple 32"); + puts("OS: Apple x32"); # endif #endif - int deviceCount = getCudaEnabledDeviceCount(); int driver; cudaDriverGetVersion(&driver); printf("CUDA Driver version: %d\n", driver); printf("CUDA Runtime version: %d\n", CUDART_VERSION); + + puts("GPU module was compiled for the following GPU archs:"); + printf(" BIN: %s\n", CUDA_ARCH_BIN); + printf(" PTX: %s\n\n", CUDA_ARCH_PTX); + + int deviceCount = getCudaEnabledDeviceCount(); printf("CUDA device count: %d\n\n", deviceCount); for (int i = 0; i < deviceCount; ++i) @@ -87,17 +91,13 @@ void print_info() printf("Device %d:\n", i); printf(" Name: %s\n", info.name().c_str()); printf(" Compute capability version: %d.%d\n", info.majorVersion(), info.minorVersion()); + printf(" Multi Processor Count: %d\n", info.multiProcessorCount()); printf(" Total memory: %d Mb\n", static_cast(static_cast(info.totalMemory() / 1024.0) / 1024.0)); printf(" Free memory: %d Mb\n", static_cast(static_cast(info.freeMemory() / 1024.0) / 1024.0)); - if (info.isCompatible()) - puts(" This device is compatible with current GPU module build\n"); - else - puts(" This device is NOT compatible with current GPU module build\n"); + if (!info.isCompatible()) + puts(" !!! This device is NOT compatible with current GPU module build\n"); + printf("\n"); } - - puts("GPU module was compiled for the following GPU archs:"); - printf(" BIN: %s\n", CUDA_ARCH_BIN); - printf(" PTX: %s\n\n", CUDA_ARCH_PTX); } enum OutputLevel @@ -111,25 +111,56 @@ extern OutputLevel nvidiaTestOutputLevel; int main(int argc, char** argv) { - TS::ptr()->init("gpu"); - InitGoogleTest(&argc, argv); + try + { + CommandLineParser parser(argc, (const char**)argv, + "{ print_info_only | print_info_only | false | Print information about system and exit }" + "{ device | device | -1 | Device on which tests will be executed (-1 means all devices) }" + "{ nvtest_output_level | nvtest_output_level | compact | NVidia test verbosity level }"); - const char* keys ="{ nvtest_output_level | nvtest_output_level | compact | NVidia test verbosity level }"; + printInfo(); - CommandLineParser parser(argc, (const char**)argv, keys); + if (parser.get("print_info_only")) + return 0; - string outputLevel = parser.get("nvtest_output_level", "none"); + int device = parser.get("device"); + if (device < 0) + { + DeviceManager::instance().loadAll(); + std::cout << "Run tests on all supported devices\n" << std::endl; + } + else + { + DeviceManager::instance().load(device); + std::cout << "Run tests on device " << device << '\n' << std::endl; + } - if (outputLevel == "none") - nvidiaTestOutputLevel = OutputLevelNone; - else if (outputLevel == "compact") - nvidiaTestOutputLevel = OutputLevelCompact; - else if (outputLevel == "full") - nvidiaTestOutputLevel = OutputLevelFull; + string outputLevel = parser.get("nvtest_output_level"); - print_info(); + if (outputLevel == "none") + nvidiaTestOutputLevel = OutputLevelNone; + else if (outputLevel == "compact") + nvidiaTestOutputLevel = OutputLevelCompact; + else if (outputLevel == "full") + nvidiaTestOutputLevel = OutputLevelFull; - return RUN_ALL_TESTS(); + TS::ptr()->init("gpu"); + InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); + } + catch (const exception& e) + { + cerr << e.what() << endl; + return -1; + } + catch (...) + { + cerr << "Unknown error" << endl; + return -1; + } + + return 0; } #else // HAVE_CUDA diff --git a/modules/gpu/test/precomp.hpp b/modules/gpu/test/precomp.hpp index afc3be8559..753367cce8 100644 --- a/modules/gpu/test/precomp.hpp +++ b/modules/gpu/test/precomp.hpp @@ -56,6 +56,7 @@ #include #include #include +#include #include "cvconfig.h" #include "opencv2/core/core.hpp" diff --git a/modules/gpu/test/utility.cpp b/modules/gpu/test/utility.cpp index bc73d30038..148c9d202b 100644 --- a/modules/gpu/test/utility.cpp +++ b/modules/gpu/test/utility.cpp @@ -46,6 +46,7 @@ using namespace cv; using namespace cv::gpu; using namespace cvtest; using namespace testing; +using namespace testing::internal; ////////////////////////////////////////////////////////////////////// // random generators @@ -108,12 +109,12 @@ GpuMat loadMat(const Mat& m, bool useRoi) ////////////////////////////////////////////////////////////////////// // Image load -Mat readImage(const string& fileName, int flags) +Mat readImage(const std::string& fileName, int flags) { - return imread(string(cvtest::TS::ptr()->get_data_path()) + fileName, flags); + return imread(TS::ptr()->get_data_path() + fileName, flags); } -Mat readImageType(const string& fname, int type) +Mat readImageType(const std::string& fname, int type) { Mat src = readImage(fname, CV_MAT_CN(type) == 1 ? IMREAD_GRAYSCALE : IMREAD_COLOR); if (CV_MAT_CN(type) == 4) @@ -134,50 +135,150 @@ bool supportFeature(const DeviceInfo& info, FeatureSet feature) return TargetArchs::builtWith(feature) && info.supports(feature); } -const vector& devices() +DeviceManager& DeviceManager::instance() { - static vector devs; - static bool first = true; - - if (first) - { - int deviceCount = getCudaEnabledDeviceCount(); - - devs.reserve(deviceCount); - - for (int i = 0; i < deviceCount; ++i) - { - DeviceInfo info(i); - if (info.isCompatible()) - devs.push_back(info); - } - - first = false; - } - - return devs; + static DeviceManager obj; + return obj; } -vector devices(FeatureSet feature) +void DeviceManager::load(int i) { - const vector& d = devices(); + devices_.clear(); + devices_.reserve(1); - vector devs_filtered; + ostringstream msg; - if (TargetArchs::builtWith(feature)) + if (i < 0 || i >= getCudaEnabledDeviceCount()) { - devs_filtered.reserve(d.size()); - - for (size_t i = 0, size = d.size(); i < size; ++i) - { - const DeviceInfo& info = d[i]; - - if (info.supports(feature)) - devs_filtered.push_back(info); - } + msg << "Incorrect device number - " << i; + throw runtime_error(msg.str()); } - return devs_filtered; + DeviceInfo info(i); + + if (!info.isCompatible()) + { + msg << "Device " << i << " [" << info.name() << "] is NOT compatible with current GPU module build"; + throw runtime_error(msg.str()); + } + + devices_.push_back(info); +} + +void DeviceManager::loadAll() +{ + int deviceCount = getCudaEnabledDeviceCount(); + + devices_.clear(); + devices_.reserve(deviceCount); + + for (int i = 0; i < deviceCount; ++i) + { + DeviceInfo info(i); + if (info.isCompatible()) + { + devices_.push_back(info); + } + } +} + +class DevicesGenerator : public ParamGeneratorInterface +{ +public: + ~DevicesGenerator(); + + ParamIteratorInterface* Begin() const; + ParamIteratorInterface* End() const; + +private: + class Iterator : public ParamIteratorInterface + { + public: + Iterator(const ParamGeneratorInterface* base, vector::const_iterator iterator); + + virtual ~Iterator(); + + virtual const ParamGeneratorInterface* BaseGenerator() const; + + virtual void Advance(); + + virtual ParamIteratorInterface* Clone() const; + + virtual const DeviceInfo* Current() const; + + virtual bool Equals(const ParamIteratorInterface& other) const; + + private: + Iterator(const Iterator& other); + + const ParamGeneratorInterface* const base_; + vector::const_iterator iterator_; + + mutable DeviceInfo value_; + }; +}; + +DevicesGenerator::~DevicesGenerator() +{ +} + +ParamIteratorInterface* DevicesGenerator::Begin() const +{ + return new Iterator(this, DeviceManager::instance().values().begin()); +} + +ParamIteratorInterface* DevicesGenerator::End() const +{ + return new Iterator(this, DeviceManager::instance().values().end()); +} + +DevicesGenerator::Iterator::Iterator(const ParamGeneratorInterface* base, vector::const_iterator iterator) + : base_(base), iterator_(iterator) +{ +} + +DevicesGenerator::Iterator::~Iterator() +{ +} + +const ParamGeneratorInterface* DevicesGenerator::Iterator::BaseGenerator() const +{ + return base_; +} + +void DevicesGenerator::Iterator::Advance() +{ + ++iterator_; +} + +ParamIteratorInterface* DevicesGenerator::Iterator::Clone() const +{ + return new Iterator(*this); +} + +const DeviceInfo* DevicesGenerator::Iterator::Current() const +{ + value_ = *iterator_; + return &value_; +} + +bool DevicesGenerator::Iterator::Equals(const ParamIteratorInterface& other) const +{ + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << endl; + + return iterator_ == CheckedDowncastToActualType(&other)->iterator_; +} + +DevicesGenerator::Iterator::Iterator(const Iterator& other) : + ParamIteratorInterface(), base_(other.base_), iterator_(other.iterator_) +{ +} + +ParamGenerator DevicesGenerator_() +{ + return ParamGenerator(new DevicesGenerator); } ////////////////////////////////////////////////////////////////////// @@ -250,7 +351,7 @@ void minMaxLocGold(const Mat& src, double* minVal_, double* maxVal_, Point* minL namespace { - template string printMatValImpl(const Mat& m, Point p) + template std::string printMatValImpl(const Mat& m, Point p) { const int cn = m.channels(); @@ -269,9 +370,9 @@ namespace return ostr.str(); } - string printMatVal(const Mat& m, Point p) + std::string printMatVal(const Mat& m, Point p) { - typedef string (*func_t)(const Mat& m, Point p); + typedef std::string (*func_t)(const Mat& m, Point p); static const func_t funcs[] = { diff --git a/modules/gpu/test/utility.hpp b/modules/gpu/test/utility.hpp index 3ad02decbb..b36f177f6e 100644 --- a/modules/gpu/test/utility.hpp +++ b/modules/gpu/test/utility.hpp @@ -80,14 +80,23 @@ cv::Mat readImageType(const std::string& fname, int type); //! return true if device supports specified feature and gpu module was built with support the feature. bool supportFeature(const cv::gpu::DeviceInfo& info, cv::gpu::FeatureSet feature); -//! return all devices compatible with current gpu module build. -const std::vector& devices(); +class DeviceManager +{ +public: + static DeviceManager& instance(); -//! return all devices compatible with current gpu module build which support specified feature. -std::vector devices(cv::gpu::FeatureSet feature); + void load(int i); + void loadAll(); -#define ALL_DEVICES testing::ValuesIn(devices()) -#define DEVICES(feature) testing::ValuesIn(devices(feature)) + const std::vector& values() const { return devices_; } + +private: + std::vector devices_; +}; + +testing::internal::ParamGenerator DevicesGenerator_(); + +#define ALL_DEVICES DevicesGenerator_() ////////////////////////////////////////////////////////////////////// // Additional assertion From 2e685dcf0a74c185db1d7fdf5b460ecbba86dcc0 Mon Sep 17 00:00:00 2001 From: niko Date: Fri, 17 Aug 2012 15:47:02 +0800 Subject: [PATCH 002/163] performance & bug fix for resize erode dilate sobel remap --- modules/ocl/CMakeLists.txt | 2 +- modules/ocl/perf/test_filters.cpp | 10 +- modules/ocl/src/filtering.cpp | 186 ++++++++++------ modules/ocl/src/imgproc.cpp | 13 +- modules/ocl/src/initialization.cpp | 4 +- modules/ocl/src/kernels/filter_sep_col.cl | 178 +-------------- .../ocl/src/kernels/filtering_dilateFilter.cl | 192 ----------------- .../ocl/src/kernels/filtering_erodeFilter.cl | 183 ---------------- modules/ocl/src/kernels/filtering_morph.cl | 204 ++++++++++++++++++ modules/ocl/src/kernels/imgproc_remap.cl | 108 +++++----- modules/ocl/src/matrix_operations.cpp | 7 + modules/ocl/src/threadsafe.cpp | 2 +- modules/ocl/test/test_imgproc.cpp | 2 +- 13 files changed, 415 insertions(+), 676 deletions(-) delete mode 100644 modules/ocl/src/kernels/filtering_dilateFilter.cl delete mode 100644 modules/ocl/src/kernels/filtering_erodeFilter.cl create mode 100644 modules/ocl/src/kernels/filtering_morph.cl diff --git a/modules/ocl/CMakeLists.txt b/modules/ocl/CMakeLists.txt index a6496aef25..994353b5a6 100644 --- a/modules/ocl/CMakeLists.txt +++ b/modules/ocl/CMakeLists.txt @@ -4,7 +4,7 @@ if(NOT HAVE_OPENCL) endif() set(the_description "OpenCL-accelerated Computer Vision") -ocv_add_module(ocl opencv_core opencv_imgproc opencv_calib3d opencv_objdetect opencv_video opencv_nonfree) +ocv_add_module(ocl opencv_core opencv_imgproc opencv_calib3d opencv_objdetect opencv_video opencv_nonfree opencv_ts) ocv_module_include_directories() diff --git a/modules/ocl/perf/test_filters.cpp b/modules/ocl/perf/test_filters.cpp index ac9a86573b..1c113fb6fb 100644 --- a/modules/ocl/perf/test_filters.cpp +++ b/modules/ocl/perf/test_filters.cpp @@ -325,7 +325,7 @@ PARAM_TEST_CASE(LaplacianTestBase, MatType, int) ksize = GET_PARAM(1); cv::RNG& rng = TS::ptr()->get_rng(); - cv::Size size = cv::Size(2560, 2560); + cv::Size size = cv::Size(MWIDTH, MHEIGHT); mat = randomMat(rng, size, type, 5, 16, false); dst = randomMat(rng, size, type, 5, 16, false); @@ -468,7 +468,7 @@ PARAM_TEST_CASE(ErodeDilateBase, MatType, bool) // iterations = GET_PARAM(1); cv::RNG& rng = TS::ptr()->get_rng(); - cv::Size size = cv::Size(2560, 2560); + cv::Size size = cv::Size(MWIDTH, MHEIGHT); mat1 = randomMat(rng, size, type, 5, 16, false); dst = randomMat(rng, size, type, 5, 16, false); @@ -679,7 +679,7 @@ PARAM_TEST_CASE(Sobel, MatType, int, int, int, int) dx = 2; dy=0; cv::RNG& rng = TS::ptr()->get_rng(); - cv::Size size = cv::Size(2560, 2560); + cv::Size size = cv::Size(MWIDTH, MHEIGHT); mat1 = randomMat(rng, size, type, 5, 16, false); dst = randomMat(rng, size, type, 5, 16, false); @@ -817,7 +817,7 @@ PARAM_TEST_CASE(Scharr, MatType, int, int, int) dx = 1; dy=0; cv::RNG& rng = TS::ptr()->get_rng(); - cv::Size size = cv::Size(2560, 2560); + cv::Size size = cv::Size(MWIDTH, MHEIGHT); mat1 = randomMat(rng, size, type, 5, 16, false); dst = randomMat(rng, size, type, 5, 16, false); @@ -956,7 +956,7 @@ PARAM_TEST_CASE(GaussianBlur, MatType, cv::Size, int) bordertype = GET_PARAM(2); cv::RNG& rng = TS::ptr()->get_rng(); - cv::Size size = cv::Size(2560, 2560); + cv::Size size = cv::Size(MWIDTH, MHEIGHT); sigma1 = rng.uniform(0.1, 1.0); sigma2 = rng.uniform(0.1, 1.0); diff --git a/modules/ocl/src/filtering.cpp b/modules/ocl/src/filtering.cpp index ea7f312bdd..c71c2a23eb 100644 --- a/modules/ocl/src/filtering.cpp +++ b/modules/ocl/src/filtering.cpp @@ -177,9 +177,7 @@ namespace cv extern const char *filter_sep_row; extern const char *filter_sep_col; extern const char *filtering_laplacian; - extern const char *filtering_erodeFilter; - extern const char *filtering_dilateFilter; - + extern const char *filtering_morph; } } @@ -334,28 +332,54 @@ void GPUErode(const oclMat &src, oclMat &dst, oclMat &mat_kernel, Size &ksize, c int srcStep = src.step1() / src.channels(); int dstStep = dst.step1() / dst.channels(); - int srcOffset = src.offset / src.channels() / src.elemSize1(); - int dstOffset = dst.offset / dst.channels() / dst.elemSize1(); - int minclos = -(srcOffset % srcStep); - int maxclos = src.wholecols + minclos - 1; - int minrows = -(srcOffset / srcStep); - int maxrows = src.wholerows + minrows - 1; - - //int D=src.depth(); + int srcOffset = src.offset / src.elemSize(); + int dstOffset = dst.offset / dst.elemSize(); + int srcOffset_x=srcOffset%srcStep; + int srcOffset_y=srcOffset/srcStep; Context *clCxt = src.clCxt; - - string kernelName = "erode"; - + string kernelName; + size_t localThreads[3] = {16, 16, 1}; + size_t globalThreads[3] = {(src.cols + localThreads[0]) / localThreads[0] * localThreads[0], (src.rows + localThreads[1]) / localThreads[1] * localThreads[1], 1}; + + if(src.type()==CV_8UC1) + { + kernelName = "morph_C1_D0"; + globalThreads[0] = ((src.cols + 3) / 4 + localThreads[0]) / localThreads[0] * localThreads[0]; + CV_Assert( localThreads[0]*localThreads[1]*8 >= (localThreads[0]*4+ksize.width-1)*(localThreads[1]+ksize.height-1) ); + } + else + { + kernelName = "morph"; + CV_Assert( localThreads[0]*localThreads[1]*2 >= (localThreads[0]+ksize.width-1)*(localThreads[1]+ksize.height-1) ); + } + char s[64]; + switch(src.type()) + { + case CV_8UC1: + sprintf(s, "-D VAL=255"); + break; + case CV_8UC3: + case CV_8UC4: + sprintf(s, "-D VAL=255 -D GENTYPE=uchar4"); + break; + case CV_32FC1: + sprintf(s, "-D VAL=FLT_MAX -D GENTYPE=float"); + break; + case CV_32FC3: + case CV_32FC4: + sprintf(s, "-D VAL=FLT_MAX -D GENTYPE=float4"); + break; + default: + CV_Error(-217,"unsupported type"); + } + char compile_option[128]; + sprintf(compile_option, "-D RADIUSX=%d -D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D ERODE %s", anchor.x, anchor.y, localThreads[0], localThreads[1],s); vector< pair > args; args.push_back( make_pair( sizeof(cl_mem), (void *)&src.data)); args.push_back( make_pair( sizeof(cl_mem), (void *)&dst.data)); - args.push_back( make_pair( sizeof(cl_int), (void *)&srcOffset)); - args.push_back( make_pair( sizeof(cl_int), (void *)&dstOffset)); - args.push_back( make_pair( sizeof(cl_int), (void *)&minclos)); - args.push_back( make_pair( sizeof(cl_int), (void *)&maxclos)); - args.push_back( make_pair( sizeof(cl_int), (void *)&minrows)); - args.push_back( make_pair( sizeof(cl_int), (void *)&maxrows)); + args.push_back( make_pair( sizeof(cl_int), (void *)&srcOffset_x)); + args.push_back( make_pair( sizeof(cl_int), (void *)&srcOffset_y)); args.push_back( make_pair( sizeof(cl_int), (void *)&src.cols)); args.push_back( make_pair( sizeof(cl_int), (void *)&src.rows)); args.push_back( make_pair( sizeof(cl_int), (void *)&srcStep)); @@ -363,18 +387,8 @@ void GPUErode(const oclMat &src, oclMat &dst, oclMat &mat_kernel, Size &ksize, c args.push_back( make_pair( sizeof(cl_mem), (void *)&mat_kernel.data)); args.push_back( make_pair( sizeof(cl_int),(void*)&src.wholecols)); args.push_back( make_pair( sizeof(cl_int),(void*)&src.wholerows)); - //args.push_back( make_pair( sizeof(cl_int),(void*)&ksize.width)); - //args.push_back( make_pair( sizeof(cl_int),(void*)&ksize.height)); - - size_t globalThreads[3] = {(src.cols + 15) / 16 * 16, (src.rows + 15) / 16 * 16, 1}; - if(src.channels() == 1) - globalThreads[0] = ((src.cols + 9) / 4 + 15) / 16 * 16; - size_t localThreads[3] = {16, 16, 1}; - - char compile_option[128]; - sprintf(compile_option, "-D anX=%d -D anY=%d -D ksX=%d -D ksY=%d", anchor.x, anchor.y, ksize.width, ksize.height); - - openCLExecuteKernel(clCxt, &filtering_erodeFilter, kernelName, globalThreads, localThreads, args, src.channels(), src.depth(), compile_option); + args.push_back( make_pair( sizeof(cl_int),(void*)&dstOffset)); + openCLExecuteKernel(clCxt, &filtering_morph, kernelName, globalThreads, localThreads, args, -1, -1, compile_option); } @@ -390,26 +404,54 @@ void GPUDilate(const oclMat &src, oclMat &dst, oclMat &mat_kernel, Size &ksize, int srcStep = src.step1() / src.channels(); int dstStep = dst.step1() / dst.channels(); - int srcOffset = src.offset / src.channels() / src.elemSize1(); - int dstOffset = dst.offset / dst.channels() / dst.elemSize1(); - int minclos = -(srcOffset % srcStep); - int maxclos = src.wholecols + minclos - 1; - int minrows = -(srcOffset / srcStep); - int maxrows = src.wholerows + minrows - 1; - + int srcOffset = src.offset / src.elemSize(); + int dstOffset = dst.offset / dst.elemSize(); + int srcOffset_x=srcOffset%srcStep; + int srcOffset_y=srcOffset/srcStep; Context *clCxt = src.clCxt; - - string kernelName = "dilate"; + string kernelName; + size_t localThreads[3] = {16, 16, 1}; + size_t globalThreads[3] = {(src.cols + localThreads[0]) / localThreads[0] * localThreads[0], (src.rows + localThreads[1]) / localThreads[1] * localThreads[1], 1}; + + if(src.type()==CV_8UC1) + { + kernelName = "morph_C1_D0"; + globalThreads[0] = ((src.cols + 3) / 4 + localThreads[0]) / localThreads[0] * localThreads[0]; + CV_Assert( localThreads[0]*localThreads[1]*8 >= (localThreads[0]*4+ksize.width-1)*(localThreads[1]+ksize.height-1) ); + } + else + { + kernelName = "morph"; + CV_Assert( localThreads[0]*localThreads[1]*2 >= (localThreads[0]+ksize.width-1)*(localThreads[1]+ksize.height-1) ); + } + char s[64]; + switch(src.type()) + { + case CV_8UC1: + sprintf(s, "-D VAL=0"); + break; + case CV_8UC3: + case CV_8UC4: + sprintf(s, "-D VAL=0 -D GENTYPE=uchar4"); + break; + case CV_32FC1: + sprintf(s, "-D VAL=-FLT_MAX -D GENTYPE=float"); + break; + case CV_32FC3: + case CV_32FC4: + sprintf(s, "-D VAL=-FLT_MAX -D GENTYPE=float4"); + break; + default: + CV_Error(-217,"unsupported type"); + } + char compile_option[128]; + sprintf(compile_option, "-D RADIUSX=%d -D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D DILATE %s", anchor.x, anchor.y, localThreads[0], localThreads[1],s); vector< pair > args; args.push_back( make_pair( sizeof(cl_mem), (void *)&src.data)); args.push_back( make_pair( sizeof(cl_mem), (void *)&dst.data)); - args.push_back( make_pair( sizeof(cl_int), (void *)&srcOffset)); - args.push_back( make_pair( sizeof(cl_int), (void *)&dstOffset)); - args.push_back( make_pair( sizeof(cl_int), (void *)&minclos)); - args.push_back( make_pair( sizeof(cl_int), (void *)&maxclos)); - args.push_back( make_pair( sizeof(cl_int), (void *)&minrows)); - args.push_back( make_pair( sizeof(cl_int), (void *)&maxrows)); + args.push_back( make_pair( sizeof(cl_int), (void *)&srcOffset_x)); + args.push_back( make_pair( sizeof(cl_int), (void *)&srcOffset_y)); args.push_back( make_pair( sizeof(cl_int), (void *)&src.cols)); args.push_back( make_pair( sizeof(cl_int), (void *)&src.rows)); args.push_back( make_pair( sizeof(cl_int), (void *)&srcStep)); @@ -417,15 +459,8 @@ void GPUDilate(const oclMat &src, oclMat &dst, oclMat &mat_kernel, Size &ksize, args.push_back( make_pair( sizeof(cl_mem), (void *)&mat_kernel.data)); args.push_back( make_pair( sizeof(cl_int),(void*)&src.wholecols)); args.push_back( make_pair( sizeof(cl_int),(void*)&src.wholerows)); - - size_t globalThreads[3] = {(src.cols + 15) / 16 * 16, (src.rows + 15) / 16 * 16, 1}; - if(src.channels() == 1) - globalThreads[0] = ((src.cols + 9) / 4 + 15) / 16 * 16; - size_t localThreads[3] = {16, 16, 1}; - char compile_option[128]; - sprintf(compile_option, "-D anX=%d -D anY=%d -D ksX=%d -D ksY=%d", anchor.x, anchor.y, ksize.width, ksize.height); - - openCLExecuteKernel(clCxt, &filtering_dilateFilter, kernelName, globalThreads, localThreads, args, src.channels(), src.depth(), compile_option); + args.push_back( make_pair( sizeof(cl_int),(void*)&dstOffset)); + openCLExecuteKernel(clCxt, &filtering_morph, kernelName, globalThreads, localThreads, args, -1, -1, compile_option); } Ptr cv::ocl::getMorphologyFilter_GPU(int op, int type, const Mat &kernel, const Size &ksize, Point anchor) @@ -739,7 +774,7 @@ namespace int src_type = src.type(); int cn = src.channels(); - dst.create(src_size, src_type); + //dst.create(src_size, src_type); dst = Scalar(0.0); //dstBuf.create(src_size, src_type); dstBuf.create(src_size.height + ksize.height - 1, src_size.width, CV_MAKETYPE(CV_32F, cn)); @@ -1265,8 +1300,8 @@ void linearColumnFilter_gpu(const oclMat &src, const oclMat &dst, oclMat mat_ker sprintf(btype, "BORDER_REFLECT_101"); break; } - char compile_option[128]; - sprintf(compile_option, "-D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D CN=%d -D %s", anchor, localThreads[0], localThreads[1], channels, btype); + char compile_option[256]; + size_t globalThreads[3]; globalThreads[1] = (dst.rows + localThreads[1] - 1) / localThreads[1] * localThreads[1]; @@ -1277,21 +1312,46 @@ void linearColumnFilter_gpu(const oclMat &src, const oclMat &dst, oclMat mat_ker { case 1: globalThreads[0] = (dst.cols + localThreads[0] - 1) / localThreads[0] * localThreads[0]; + sprintf(compile_option, "-D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D CN=%d -D %s -D GENTYPE_SRC=%s -D GENTYPE_DST=%s -D convert_to_DST=%s", + anchor, localThreads[0], localThreads[1], channels, btype,"float","uchar","convert_uchar_sat"); break; case 2: globalThreads[0] = ((dst.cols + 1) / 2 + localThreads[0] - 1) / localThreads[0] * localThreads[0]; + sprintf(compile_option, "-D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D CN=%d -D %s -D GENTYPE_SRC=%s -D GENTYPE_DST=%s -D convert_to_DST=%s", + anchor, localThreads[0], localThreads[1], channels, btype,"float2","uchar2","convert_uchar2_sat"); break; case 3: - globalThreads[0] = ((dst.cols * 3 + 3) / 4 + localThreads[0] - 1) / localThreads[0] * localThreads[0]; - break; case 4: globalThreads[0] = (dst.cols + localThreads[0] - 1) / localThreads[0] * localThreads[0]; + sprintf(compile_option, "-D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D CN=%d -D %s -D GENTYPE_SRC=%s -D GENTYPE_DST=%s -D convert_to_DST=%s", + anchor, localThreads[0], localThreads[1], channels, btype,"float4","uchar4","convert_uchar4_sat"); break; } } else { globalThreads[0] = (dst.cols + localThreads[0] - 1) / localThreads[0] * localThreads[0]; + switch(dst.type()) + { + case CV_32SC1: + sprintf(compile_option, "-D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D CN=%d -D %s -D GENTYPE_SRC=%s -D GENTYPE_DST=%s -D convert_to_DST=%s", + anchor, localThreads[0], localThreads[1], channels, btype,"float","int","convert_int_sat"); + break; + case CV_32SC3: + case CV_32SC4: + sprintf(compile_option, "-D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D CN=%d -D %s -D GENTYPE_SRC=%s -D GENTYPE_DST=%s -D convert_to_DST=%s", + anchor, localThreads[0], localThreads[1], channels, btype,"float4","int4","convert_int4_sat"); + break; + case CV_32FC1: + sprintf(compile_option, "-D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D CN=%d -D %s -D GENTYPE_SRC=%s -D GENTYPE_DST=%s -D convert_to_DST=%s", + anchor, localThreads[0], localThreads[1], channels, btype,"float","float",""); + break; + case CV_32FC3: + case CV_32FC4: + sprintf(compile_option, "-D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D CN=%d -D %s -D GENTYPE_SRC=%s -D GENTYPE_DST=%s -D convert_to_DST=%s", + anchor, localThreads[0], localThreads[1], channels, btype,"float4","float4",""); + break; + } } //sanity checks @@ -1321,7 +1381,7 @@ void linearColumnFilter_gpu(const oclMat &src, const oclMat &dst, oclMat mat_ker args.push_back(make_pair(sizeof(cl_int), (void *)&dst_offset_in_pixel)); args.push_back(make_pair(sizeof(cl_mem), (void *)&mat_kernel.data)); - openCLExecuteKernel(clCxt, &filter_sep_col, kernelName, globalThreads, localThreads, args, channels, dst.depth(), compile_option); + openCLExecuteKernel(clCxt, &filter_sep_col, kernelName, globalThreads, localThreads, args, -1, -1, compile_option); } Ptr cv::ocl::getLinearColumnFilter_GPU(int bufType, int dstType, const Mat &columnKernel, int anchor, int bordertype, double delta) @@ -1376,7 +1436,7 @@ void cv::ocl::sepFilter2D(const oclMat &src, oclMat &dst, int ddepth, const Mat { if( ddepth < 0 ) ddepth = src.depth(); - CV_Assert(ddepth == src.depth()); + //CV_Assert(ddepth == src.depth()); dst.create(src.size(), CV_MAKETYPE(ddepth, src.channels())); Ptr f = createSeparableLinearFilter_GPU(src.type(), dst.type(), kernelX, kernelY, anchor, delta, bordertype); diff --git a/modules/ocl/src/imgproc.cpp b/modules/ocl/src/imgproc.cpp index 7617c08c5e..98ab98e0c4 100644 --- a/modules/ocl/src/imgproc.cpp +++ b/modules/ocl/src/imgproc.cpp @@ -260,7 +260,7 @@ namespace cv CV_Assert((!map2.data || map2.size()== map1.size())); dst.create(map1.size(), src.type()); - + string kernelName; @@ -394,8 +394,15 @@ namespace cv args.push_back( make_pair(sizeof(cl_int),(void*)&map1.cols)); args.push_back( make_pair(sizeof(cl_int),(void*)&map1.rows)); args.push_back( make_pair(sizeof(cl_int), (void *)&cols)); - args.push_back( make_pair(sizeof(cl_double4),(void*)&borderValue)); - } + if(src.clCxt -> impl -> double_support != 0) + { + args.push_back( make_pair(sizeof(cl_double4),(void*)&borderValue)); + } + else + { + args.push_back( make_pair(sizeof(cl_float4),(void*)&borderValue)); + } + } openCLExecuteKernel(clCxt,&imgproc_remap,kernelName,globalThreads,localThreads,args,src.channels(),src.depth()); } diff --git a/modules/ocl/src/initialization.cpp b/modules/ocl/src/initialization.cpp index 61e7177ae9..fab81fd46d 100644 --- a/modules/ocl/src/initialization.cpp +++ b/modules/ocl/src/initialization.cpp @@ -44,9 +44,9 @@ //M*/ #include "precomp.hpp" -#include "threadsafe.h" +#include "Threadsafe.h" #include -#include "binarycaching.hpp" +#include "binaryCaching.hpp" using namespace cv; using namespace cv::ocl; diff --git a/modules/ocl/src/kernels/filter_sep_col.cl b/modules/ocl/src/kernels/filter_sep_col.cl index f85906a9b2..bfb8cac179 100644 --- a/modules/ocl/src/kernels/filter_sep_col.cl +++ b/modules/ocl/src/kernels/filter_sep_col.cl @@ -90,9 +90,9 @@ Niko ***********************************************************************************/ -__kernel __attribute__((reqd_work_group_size(LSIZE0,LSIZE1,1))) void col_filter_C1_D0 - (__global const float * restrict src, - __global uchar * dst, +__kernel __attribute__((reqd_work_group_size(LSIZE0,LSIZE1,1))) void col_filter + (__global const GENTYPE_SRC * restrict src, + __global GENTYPE_DST * dst, const int dst_cols, const int dst_rows, const int src_whole_cols, @@ -111,10 +111,10 @@ __kernel __attribute__((reqd_work_group_size(LSIZE0,LSIZE1,1))) void col_filter_ int start_addr = mad24(y,src_step_in_pixel,x); int end_addr = mad24(src_whole_rows - 1,src_step_in_pixel,src_whole_cols); int i; - float sum; - float temp[READ_TIMES_COL]; + GENTYPE_SRC sum; + GENTYPE_SRC temp[READ_TIMES_COL]; - __local float LDS_DAT[LSIZE1*READ_TIMES_COL][LSIZE0+1]; + __local GENTYPE_SRC LDS_DAT[LSIZE1*READ_TIMES_COL][LSIZE0+1]; //read pixels from src for(i = 0;i 0)) ? current_addr : 0; - float4 v = src[current_addr]; - uchar now = mat_kernel[k++]; - float4 flag = (kX >= mincols & kX <= maxcols & kY >= minrows & kY <= maxrows & now != 0) ? v : (float4)(-FLT_MAX); - maxVal = max(maxVal , flag); - } - } - - if(mX < cols && mY < rows) - dst[mY * dstStep + mX + dstOffset] = (maxVal); -} - -__kernel void dilate_C1_D5(__global float4 * src, __global float *dst, int srcOffset, int dstOffset, - int mincols, int maxcols, int minrows, int maxrows, int cols, int rows, - int srcStep, int dstStep, __constant uchar * mat_kernel, int src_whole_cols, int src_whole_rows) -{ - int mX = (get_global_id(0)<<2) - (dstOffset&3); - int mY = get_global_id(1); - int kX = mX - anX, kY = mY - anY; - int end_addr = mad24(src_whole_rows-1,srcStep,src_whole_cols); - float4 maxVal = (float4)(-FLT_MAX); - int k=0; - for(int i=0;i 0)) ? start : 0; - int start2 = ((start + 4 < end_addr) && (start > 0)) ? start + 4 : 0; - float8 sVal = (float8)(src[start>>2], src[start2>>2]); - - float sAry[8]= {sVal.s0, sVal.s1, sVal.s2, sVal.s3, sVal.s4, sVal.s5, sVal.s6, sVal.s7}; - int det = start & 3; - float4 v=(float4)(sAry[det], sAry[det+1], sAry[det+2], sAry[det+3]); - uchar now = mat_kernel[k++]; - float4 flag = (kY >= minrows & kY <= maxrows & now != 0) ? v : maxVal; - flag.x = (kX >= mincols & kX <= maxcols) ? flag.x : -FLT_MAX; - flag.y = (kX+1 >= mincols & kX+1 <= maxcols) ? flag.y : -FLT_MAX; - flag.z = (kX+2 >= mincols & kX+2 <= maxcols) ? flag.z : -FLT_MAX; - flag.w = (kX+3 >= mincols & kX+3 <= maxcols) ? flag.w : -FLT_MAX; - - maxVal = max(maxVal , flag); - } - } - if(mY < rows && mX < cols) - { - __global float4* d = (__global float4*)(dst + mY * dstStep + mX + dstOffset); - float4 dVal = *d; - maxVal.x = (mX >=0 & mX < cols) ? maxVal.x : dVal.x; - maxVal.y = (mX+1 >=0 & mX+1 < cols) ? maxVal.y : dVal.y; - maxVal.z = (mX+2 >=0 & mX+2 < cols) ? maxVal.z : dVal.z; - maxVal.w = (mX+3 >=0 & mX+3 < cols) ? maxVal.w : dVal.w; - - *d = (maxVal); - } -} - -__kernel void dilate_C1_D0(__global const uchar4 * restrict src, __global uchar *dst, int srcOffset, int dstOffset, - int mincols, int maxcols, int minrows, int maxrows, int cols, int rows, - int srcStep, int dstStep, __constant uchar * mat_kernel, int src_whole_cols, int src_whole_rows) -{ - int mX = (get_global_id(0)<<2) - (dstOffset&3);; - int mY = get_global_id(1); - int kX = mX - anX, kY = mY - anY; - int end_addr = mad24(src_whole_rows-1,srcStep,src_whole_cols); - uchar4 maxVal = (uchar4)(UCHAR_MIN); - int k=0; - for(int i=0;i 0)) ? start : 0; - int start2 = ((start + 4 < end_addr) && (start > 0)) ? start + 4 : 0; - uchar8 sVal = (uchar8)(src[start>>2], src[start2>>2]); - - uchar sAry[8]= {sVal.s0, sVal.s1, sVal.s2, sVal.s3, sVal.s4, sVal.s5, sVal.s6, sVal.s7}; - int det = start & 3; - uchar4 v=(uchar4)(sAry[det], sAry[det+1], sAry[det+2], sAry[det+3]); - - uchar4 flag = (kY >= minrows & kY <= maxrows & mat_kernel[k++] != 0) ? v : maxVal; - flag.x = (kX >= mincols & kX <= maxcols) ? flag.x : UCHAR_MIN; - flag.y = (kX+1 >= mincols & kX+1 <= maxcols) ? flag.y : UCHAR_MIN; - flag.z = (kX+2 >= mincols & kX+2 <= maxcols) ? flag.z : UCHAR_MIN; - flag.w = (kX+3 >= mincols & kX+3 <= maxcols) ? flag.w : UCHAR_MIN; - - maxVal = max(maxVal , flag); - } - } - if(mY < rows) - { - __global uchar4* d = (__global uchar4*)(dst + mY * dstStep + mX + dstOffset); - uchar4 dVal = *d; - - maxVal.x = (mX >=0 & mX < cols) ? maxVal.x : dVal.x; - maxVal.y = (mX+1 >=0 & mX+1 < cols) ? maxVal.y : dVal.y; - maxVal.z = (mX+2 >=0 & mX+2 < cols) ? maxVal.z : dVal.z; - maxVal.w = (mX+3 >=0 & mX+3 < cols) ? maxVal.w : dVal.w; - - *d = (maxVal); - } -} - -__kernel void dilate_C4_D0(__global const uchar4 * restrict src, __global uchar4 *dst, int srcOffset, int dstOffset, - int mincols, int maxcols, int minrows, int maxrows, int cols, int rows, - int srcStep, int dstStep, __constant uchar * mat_kernel, int src_whole_cols, int src_whole_rows) -{ - int mX = get_global_id(0); - int mY = get_global_id(1); - int kX = mX - anX, kY = mY - anY; - int end_addr = mad24(src_whole_rows-1,srcStep,src_whole_cols); - uchar4 maxVal = (uchar4)(UCHAR_MIN); - int k=0; - for(int i=0;i 0)) ? current_addr : 0; - uchar4 v = src[current_addr]; - uchar now = mat_kernel[k++]; - uchar4 flag = (kX >= mincols & kX <= maxcols & kY >= minrows & kY <= maxrows & now != 0) ? v : maxVal; - maxVal = max(maxVal , flag); - } - } - - if(mX < cols && mY < rows) - dst[mY * dstStep + mX + dstOffset] = (maxVal); -} - diff --git a/modules/ocl/src/kernels/filtering_erodeFilter.cl b/modules/ocl/src/kernels/filtering_erodeFilter.cl deleted file mode 100644 index 1714fb024b..0000000000 --- a/modules/ocl/src/kernels/filtering_erodeFilter.cl +++ /dev/null @@ -1,183 +0,0 @@ -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved. -// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// @Authors -// Niko Li, newlife20080214@gmail.com -// Zero Lin, zero.lin@amd.com -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other oclMaterials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors as is and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -// - -__kernel void erode_C4_D5(__global const float4 * restrict src, __global float4 *dst, int srcOffset, int dstOffset, - int mincols, int maxcols, int minrows, int maxrows, int cols, int rows, - int srcStep, int dstStep, __constant uchar * mat_kernel, int src_whole_cols, int src_whole_rows) -{ - int mX = get_global_id(0); - int mY = get_global_id(1); - int kX = mX - anX, kY = mY - anY; - int end_addr = mad24(src_whole_rows-1,srcStep,src_whole_cols); - float4 minVal = (float4)(3.4e+38); - int k=0; - for(int i=0;i 0)) ? current_addr : 0; - float4 v = src[current_addr]; - uchar now = mat_kernel[k++]; - float4 flag = (kX >= mincols & kX <= maxcols & kY >= minrows & kY <= maxrows & now != 0) ? v : (float4)(3.4e+38); - minVal = min(minVal , flag); - } - } - - if(mX < cols && mY < rows) - dst[mY * dstStep + mX + dstOffset] = (minVal); -} - -__kernel void erode_C1_D5(__global float4 * src, __global float *dst, int srcOffset, int dstOffset, - int mincols, int maxcols, int minrows, int maxrows, int cols, int rows, - int srcStep, int dstStep, __constant uchar * mat_kernel, int src_whole_cols, int src_whole_rows) -{ - int mX = (get_global_id(0)<<2) - (dstOffset&3); - int mY = get_global_id(1); - int kX = mX - anX, kY = mY - anY; - int end_addr = mad24(src_whole_rows-1,srcStep,src_whole_cols); - float4 minVal = (float4)(3.4e+38); - int k=0; - for(int i=0;i 0)) ? start : 0; - int start2 = ((start + 4 < end_addr) && (start > 0)) ? start + 4 : 0; - float8 sVal = (float8)(src[start>>2], src[start2>>2]); - - float sAry[8]= {sVal.s0, sVal.s1, sVal.s2, sVal.s3, sVal.s4, sVal.s5, sVal.s6, sVal.s7}; - int det = start & 3; - float4 v=(float4)(sAry[det], sAry[det+1], sAry[det+2], sAry[det+3]); - uchar now = mat_kernel[k++]; - float4 flag = (kY >= minrows & kY <= maxrows & now != 0) ? v : (float4)(3.4e+38); - flag.x = (kX >= mincols & kX <= maxcols) ? flag.x : 3.4e+38; - flag.y = (kX+1 >= mincols & kX+1 <= maxcols) ? flag.y : 3.4e+38; - flag.z = (kX+2 >= mincols & kX+2 <= maxcols) ? flag.z : 3.4e+38; - flag.w = (kX+3 >= mincols & kX+3 <= maxcols) ? flag.w : 3.4e+38; - - minVal = min(minVal , flag); - } - } - - if(mY < rows && mX < cols) - { - __global float4* d = (__global float4*)(dst + mY * dstStep + mX + dstOffset); - float4 dVal = *d; - minVal.x = (mX >=0 & mX < cols) ? minVal.x : dVal.x; - minVal.y = (mX+1 >=0 & mX+1 < cols) ? minVal.y : dVal.y; - minVal.z = (mX+2 >=0 & mX+2 < cols) ? minVal.z : dVal.z; - minVal.w = (mX+3 >=0 & mX+3 < cols) ? minVal.w : dVal.w; - - *d = (minVal); - } -} - -__kernel void erode_C1_D0(__global const uchar4 * restrict src, __global uchar *dst, int srcOffset, int dstOffset, - int mincols, int maxcols, int minrows, int maxrows, int cols, int rows, - int srcStep, int dstStep, __constant uchar * mat_kernel, int src_whole_cols, int src_whole_rows) -{ - int mX = (get_global_id(0)<<2) - (dstOffset&3); - int mY = get_global_id(1); - int kX = mX - anX, kY = mY - anY; - int end_addr = mad24(src_whole_rows-1,srcStep,src_whole_cols); - uchar4 minVal = (uchar4)(0xff); - int k=0; - for(int i=0;i 0)) ? start : 0; - int start2 = ((start + 4 < end_addr) && (start > 0)) ? start + 4 : 0; - uchar8 sVal = (uchar8)(src[start>>2], src[start2>>2]); - - uchar sAry[8]= {sVal.s0, sVal.s1, sVal.s2, sVal.s3, sVal.s4, sVal.s5, sVal.s6, sVal.s7}; - int det = start & 3; - uchar4 v=(uchar4)(sAry[det], sAry[det+1], sAry[det+2], sAry[det+3]); - - uchar4 flag = (kY >= minrows & kY <= maxrows & mat_kernel[k++] != 0) ? v : (uchar4)(0xff); - flag.x = (kX >= mincols & kX <= maxcols) ? flag.x : 0xff; - flag.y = (kX+1 >= mincols & kX+1 <= maxcols) ? flag.y : 0xff; - flag.z = (kX+2 >= mincols & kX+2 <= maxcols) ? flag.z : 0xff; - flag.w = (kX+3 >= mincols & kX+3 <= maxcols) ? flag.w : 0xff; - - minVal = min(minVal , flag); - } - } - - if(mY < rows) - { - __global uchar4* d = (__global uchar4*)(dst + mY * dstStep + mX + dstOffset); - uchar4 dVal = *d; - - minVal.x = (mX >=0 & mX < cols) ? minVal.x : dVal.x; - minVal.y = (mX+1 >=0 & mX+1 < cols) ? minVal.y : dVal.y; - minVal.z = (mX+2 >=0 & mX+2 < cols) ? minVal.z : dVal.z; - minVal.w = (mX+3 >=0 & mX+3 < cols) ? minVal.w : dVal.w; - - *d = (minVal); - } -} - -__kernel void erode_C4_D0(__global const uchar4 * restrict src, __global uchar4 *dst, int srcOffset, int dstOffset, - int mincols, int maxcols, int minrows, int maxrows, int cols, int rows, - int srcStep, int dstStep, __constant uchar * mat_kernel, int src_whole_cols, int src_whole_rows) -{ - int mX = get_global_id(0); - int mY = get_global_id(1); - int kX = mX - anX, kY = mY - anY; - int end_addr = mad24(src_whole_rows-1,srcStep,src_whole_cols); - uchar4 minVal = (uchar4)(0xff); - int k=0; - for(int i=0;i 0)) ? current_addr : 0; - uchar4 v = src[current_addr]; - uchar now = mat_kernel[k++]; - uchar4 flag = (kX >= mincols & kX <= maxcols & kY >= minrows & kY <= maxrows & now != 0) ? v : (uchar4)(0xff); - minVal = min(minVal , flag); - } - } - - if(mX < cols && mY < rows) - dst[mY * dstStep + mX + dstOffset] = (minVal); -} - diff --git a/modules/ocl/src/kernels/filtering_morph.cl b/modules/ocl/src/kernels/filtering_morph.cl new file mode 100644 index 0000000000..b008cb55d6 --- /dev/null +++ b/modules/ocl/src/kernels/filtering_morph.cl @@ -0,0 +1,204 @@ +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Niko Li, newlife20080214@gmail.com +// Zero Lin, zero.lin@amd.com +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other oclMaterials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors as is and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// + + +#ifdef ERODE +#define MORPH_OP(A,B) min((A),(B)) +#endif +#ifdef DILATE +#define MORPH_OP(A,B) max((A),(B)) +#endif +//BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii +#define ELEM(i,l_edge,r_edge,elem1,elem2) (i)<(l_edge) | (i) >= (r_edge) ? (elem1) : (elem2) +#ifndef GENTYPE +__kernel void morph_C1_D0(__global const uchar * restrict src, + __global uchar *dst, + int src_offset_x, int src_offset_y, + int cols, int rows, + int src_step_in_pixel, int dst_step_in_pixel, + __constant uchar * mat_kernel, + int src_whole_cols, int src_whole_rows, + int dst_offset_in_pixel) +{ + int l_x = get_local_id(0); + int l_y = get_local_id(1); + int x = get_group_id(0)*4*LSIZE0; + int y = get_group_id(1)*LSIZE1; + int start_x = x+src_offset_x-RADIUSX & 0xfffffffc; + int end_x = x + src_offset_x+LSIZE0*4+RADIUSX & 0xfffffffc; + int width = (end_x -start_x+4)>>2; + int offset = src_offset_x-RADIUSX & 3; + int start_y = y+src_offset_y-RADIUSY; + int point1 = mad24(l_y,LSIZE0,l_x); + int point2 = point1 + LSIZE0*LSIZE1; + int tl_x = (point1 % width)<<2; + int tl_y = point1 / width; + int tl_x2 = (point2 % width)<<2; + int tl_y2 = point2 / width; + int cur_x = start_x + tl_x; + int cur_y = start_y + tl_y; + int cur_x2 = start_x + tl_x2; + int cur_y2 = start_y + tl_y2; + int start_addr = mad24(cur_y,src_step_in_pixel,cur_x); + int start_addr2 = mad24(cur_y2,src_step_in_pixel,cur_x2); + uchar4 temp0,temp1; + __local uchar4 LDS_DAT[2*LSIZE1*LSIZE0]; + + int end_addr = mad24(src_whole_rows - 1,src_step_in_pixel,src_whole_cols); + //read pixels from src + start_addr = ((start_addr < end_addr) && (start_addr > 0)) ? start_addr : 0; + start_addr2 = ((start_addr2 < end_addr) && (start_addr2 > 0)) ? start_addr2 : 0; + temp0 = *(__global uchar4*)&src[start_addr]; + temp1 = *(__global uchar4*)&src[start_addr2]; + //judge if read out of boundary + temp0.x= ELEM(cur_x,0,src_whole_cols,VAL,temp0.x); + temp0.y= ELEM(cur_x+1,0,src_whole_cols,VAL,temp0.y); + temp0.z= ELEM(cur_x+2,0,src_whole_cols,VAL,temp0.z); + temp0.w= ELEM(cur_x+3,0,src_whole_cols,VAL,temp0.w); + temp0= ELEM(cur_y,0,src_whole_rows,(uchar4)VAL,temp0); + + temp1.x= ELEM(cur_x2,0,src_whole_cols,VAL,temp1.x); + temp1.y= ELEM(cur_x2+1,0,src_whole_cols,VAL,temp1.y); + temp1.z= ELEM(cur_x2+2,0,src_whole_cols,VAL,temp1.z); + temp1.w= ELEM(cur_x2+3,0,src_whole_cols,VAL,temp1.w); + temp1= ELEM(cur_y2,0,src_whole_rows,(uchar4)VAL,temp1); + + LDS_DAT[point1] = temp0; + LDS_DAT[point2] = temp1; + barrier(CLK_LOCAL_MEM_FENCE); + uchar4 res = (uchar4)VAL; + for(int i=0;i<2*RADIUSY+1;i++) + for(int j=0;j<2*RADIUSX+1;j++) + { + res =mat_kernel[i*(2*RADIUSX+1)+j]? MORPH_OP(res,vload4(0,(__local uchar*)&LDS_DAT[mad24((l_y+i),width,l_x)]+offset+j)):res; + } + int gidx = get_global_id(0)<<2; + int gidy = get_global_id(1); + int out_addr = mad24(gidy,dst_step_in_pixel,gidx+dst_offset_in_pixel); + if(gidx+3 0)) ? start_addr : 0; + start_addr2 = ((start_addr2 < end_addr) && (start_addr2 > 0)) ? start_addr2 : 0; + temp0 = src[start_addr]; + temp1 = src[start_addr2]; + //judge if read out of boundary + temp0= ELEM(cur_x,0,src_whole_cols,(GENTYPE)VAL,temp0); + temp0= ELEM(cur_y,0,src_whole_rows,(GENTYPE)VAL,temp0); + + temp1= ELEM(cur_x2,0,src_whole_cols,(GENTYPE)VAL,temp1); + temp1= ELEM(cur_y2,0,src_whole_rows,(GENTYPE)VAL,temp1); + + LDS_DAT[point1] = temp0; + LDS_DAT[point2] = temp1; + barrier(CLK_LOCAL_MEM_FENCE); + GENTYPE res = (GENTYPE)VAL; + for(int i=0;i<2*RADIUSY+1;i++) + for(int j=0;j<2*RADIUSX+1;j++) + { + res =mat_kernel[i*(2*RADIUSX+1)+j]? MORPH_OP(res,LDS_DAT[mad24(l_y+i,width,l_x+j)]):res; + } + int gidx = get_global_id(0); + int gidy = get_global_id(1); + int out_addr = mad24(gidy,dst_step_in_pixel,gidx+dst_offset_in_pixel); + if(gidx= 0 && Gx < dst_cols && y >= 0 && y < dst_rows); - dst_data = (convert_uchar4(con) != (uchar4)0) ? dst_data : dVal; + dst_data = (convert_uchar4(con) != convert_uchar4((int4)(0))) ? dst_data : dVal; *d = dst_data; @@ -139,8 +139,8 @@ __kernel void remapNNFConstant_C1_D0(__global unsigned char* dst, __global unsig uchar4 dVal = *d; int4 con = (Gx >= 0 && Gx < dst_cols && y >= 0 && y < dst_rows); - dst_data = (convert_uchar4(con) != (uchar4)0) ? dst_data : dVal; - + + dst_data = (convert_uchar4(con) != convert_uchar4((int4)(0))) ? dst_data : dVal; *d = dst_data; } @@ -167,7 +167,7 @@ __kernel void remapNNSConstant_C4_D0(__global unsigned char* dst, __global unsig short8 map1_data; map1_data = *((__global short8 *)((__global char*)map1 + map1Start)); - int4 srcIdx = convert_int4(map1_data.odd) * src_step + convert_int4(map1_data.even <<(short4)2) + src_offset; + int4 srcIdx = convert_int4(map1_data.odd) * src_step + (convert_int4(map1_data.even) <<((int4)(2))) + src_offset; uchar4 src_a, src_b, src_c, src_d; src_a = *((__global uchar4 *)((__global char*)src + srcIdx.s0)); src_b = *((__global uchar4 *)((__global char*)src + srcIdx.s1)); @@ -187,7 +187,7 @@ __kernel void remapNNSConstant_C4_D0(__global unsigned char* dst, __global unsig uchar16 dVal = *d; int16 con = (Gx >= 0 && Gx < (dst_cols<<2) && y >= 0 && y < dst_rows); - dst_data = (convert_uchar16(con) != (uchar16)0) ? dst_data : dVal; + dst_data = (convert_uchar16(con) != ((uchar16)(0))) ? dst_data : dVal; *d = dst_data; } @@ -216,7 +216,7 @@ __kernel void remapNNFConstant_C4_D0(__global unsigned char* dst, __global unsig map1_data = *((__global float8 *)((__global char*)map1 + map1Start)); int8 map1_dataZ = convert_int8_sat_rte(map1_data); - int4 srcIdx = map1_dataZ.odd * src_step + (map1_dataZ.even <<2) + src_offset; + int4 srcIdx = map1_dataZ.odd * src_step + (map1_dataZ.even <<((int4)(2))) + src_offset; uchar4 src_a, src_b, src_c, src_d; src_a = *((__global uchar4 *)((__global char*)src + srcIdx.s0)); src_b = *((__global uchar4 *)((__global char*)src + srcIdx.s1)); @@ -236,7 +236,7 @@ __kernel void remapNNFConstant_C4_D0(__global unsigned char* dst, __global unsig uchar16 dVal = *d; int16 con = (Gx >= 0 && Gx < (dst_cols<<2) && y >= 0 && y < dst_rows); - dst_data = (convert_uchar16(con) != (uchar16)0) ? dst_data : dVal; + dst_data = (convert_uchar16(con) != ((uchar16)(0))) ? dst_data : dVal; *d = dst_data; @@ -269,7 +269,7 @@ __kernel void remapNNSConstant_C1_D5(__global float* dst, __global float const * map1_data = *((__global short8 *)((__global char*)map1 + map1Start)); - int4 srcIdx = convert_int4(map1_data.odd) * src_step + convert_int4(map1_data.even <<(short4)2) + src_offset; + int4 srcIdx = convert_int4(map1_data.odd) * src_step + (convert_int4(map1_data.even) <<((int4)(2))) + src_offset; float4 src_data; src_data.s0 = *((__global float *)((__global char*)src + srcIdx.s0)); @@ -289,7 +289,7 @@ __kernel void remapNNSConstant_C1_D5(__global float* dst, __global float const * float4 dVal = *d; int4 con = (Gx >= 0 && Gx < (dst_cols<<2) && y >= 0 && y < dst_rows); - dst_data = (convert_float4(con) != 0) ? dst_data : dVal; + dst_data = (convert_float4(con) != (float4)(0)) ? dst_data : dVal; *d = dst_data; @@ -321,7 +321,7 @@ __kernel void remapNNFConstant_C1_D5(__global float* dst, __global float const * map1_data = *((__global float8 *)((__global char*)map1 + map1Start)); int8 map1_dataZ = convert_int8_sat_rte(map1_data); - int4 srcIdx = convert_int4(map1_dataZ.odd) * src_step + convert_int4(map1_dataZ.even <<2) + src_offset; + int4 srcIdx = convert_int4(map1_dataZ.odd) * src_step + convert_int4(map1_dataZ.even <<(int4)(2)) + src_offset; float4 src_data; src_data.s0 = *((__global float *)((__global char*)src + srcIdx.s0)); @@ -341,7 +341,7 @@ __kernel void remapNNFConstant_C1_D5(__global float* dst, __global float const * float4 dVal = *d; int4 con = (Gx >= 0 && Gx < (dst_cols<<2) && y >= 0 && y < dst_rows); - dst_data = (convert_float4(con) != 0) ? dst_data : dVal; + dst_data = (convert_float4(con) != (float4)(0)) ? dst_data : dVal; *d = dst_data; @@ -418,21 +418,21 @@ __kernel void remapLNFConstant_C1_D0(__global unsigned char* dst, __global unsig float4 u = temp.even; float4 v = temp.odd; - float4 ud = 1.f - u; - float4 vd = 1.f - v; + float4 ud = (float4)(1.0) - u; + float4 vd = (float4)(1.0) - v; //float8 map1_dataU = map1_dataD + 1; int4 map1_dataDx = map1_dataD.even; int4 map1_dataDy = map1_dataD.odd; - int4 map1_dataDx1 = map1_dataDx + 1; - int4 map1_dataDy1 = map1_dataDy + 1; + int4 map1_dataDx1 = map1_dataDx + (int4)(1); + int4 map1_dataDy1 = map1_dataDy + (int4)(1); int4 src_StartU = map1_dataDy * src_step + map1_dataDx + src_offset; int4 src_StartD = src_StartU + src_step; /* //not using the vload - int4 src_StartU1 = src_StartU + 1; - int4 src_StartD1 = src_StartD + 1; + int4 src_StartU1 = src_StartU + (int4)(1); + int4 src_StartD1 = src_StartD + (int4)(1); uchar4 a, b, c, d; a.x = *(src_StartU.x + src); @@ -476,10 +476,10 @@ __kernel void remapLNFConstant_C1_D0(__global unsigned char* dst, __global unsig int4 bc =(map1_dataDx1 >= src_cols || map1_dataDy >= src_rows || map1_dataDx1 < 0 || map1_dataDy < 0); int4 cc =(map1_dataDx >= src_cols || map1_dataDy1 >= src_rows || map1_dataDy1 < 0 || map1_dataDx < 0); int4 dc =(map1_dataDx1 >= src_cols || map1_dataDy1 >= src_rows || map1_dataDy1 < 0 || map1_dataDy1 < 0); - a = (convert_uchar4(ac) == (uchar4)0)? a : val; - b = (convert_uchar4(bc) == (uchar4)0)? b : val; - c = (convert_uchar4(cc) == (uchar4)0)? c : val; - d = (convert_uchar4(dc) == (uchar4)0)? d : val; + a = (convert_uchar4(ac) == (uchar4)(0))? a : val; + b = (convert_uchar4(bc) == (uchar4)(0))? b : val; + c = (convert_uchar4(cc) == (uchar4)(0))? c : val; + d = (convert_uchar4(dc) == (uchar4)(0))? d : val; uchar4 dst_data = convert_uchar4_sat_rte((convert_float4(a))* ud * vd +(convert_float4(b))* u * vd + (convert_float4(c))* ud * v + (convert_float4(d)) * u * v ); @@ -487,7 +487,7 @@ __kernel void remapLNFConstant_C1_D0(__global unsigned char* dst, __global unsig uchar4 dVal = *D; int4 con = (Gx >= 0 && Gx < dst_cols && y >= 0 && y < dst_rows); - dst_data = (convert_uchar4(con) != (uchar4)0) ? dst_data : dVal; + dst_data = (convert_uchar4(con) != (uchar4)(0)) ? dst_data : dVal; *D = dst_data; } @@ -531,7 +531,7 @@ __kernel void remapLNSConstant_C1_D0(__global unsigned char* dst, __global unsig uchar4 dVal = *d; int4 con = (Gx >= 0 && Gx < dst_cols && y >= 0 && y < dst_rows); - dst_data = (convert_uchar4(con) != (uchar4)0) ? dst_data : dVal; + dst_data = (convert_uchar4(con) != (uchar4)(0)) ? dst_data : dVal; *d = dst_data; @@ -567,17 +567,17 @@ __kernel void remapLNFConstant_C4_D0(__global unsigned char* dst, __global unsig float4 u = temp.even; float4 v = temp.odd; - float4 ud = 1.f - u; - float4 vd = 1.f - v; + float4 ud = (float4)(1.0) - u; + float4 vd = (float4)(1.0) - v; //float8 map1_dataU = map1_dataD + 1; int4 map1_dataDx = map1_dataD.even; int4 map1_dataDy = map1_dataD.odd; - int4 map1_dataDx1 = map1_dataDx + 1; - int4 map1_dataDy1 = map1_dataDy + 1; + int4 map1_dataDx1 = map1_dataDx + (int4)(1); + int4 map1_dataDy1 = map1_dataDy + (int4)(1); - int4 src_StartU = map1_dataDy * src_step + (map1_dataDx << 2) + src_offset; + int4 src_StartU = map1_dataDy * src_step + (convert_int4(map1_dataDx) << (int4)(2)) + src_offset; int4 src_StartD = src_StartU + src_step; uchar8 aU, bU, cU, dU, aD, bD, cD, dD; @@ -605,10 +605,10 @@ __kernel void remapLNFConstant_C4_D0(__global unsigned char* dst, __global unsig int16 dcc = (int16)((int4)(dc.x), (int4)(dc.y), (int4)(dc.z), (int4)(dc.w)); uchar16 val = (uchar16)(nval, nval, nval, nval); - a = (convert_uchar16(acc) == (uchar16)0)? a : val; - b = (convert_uchar16(bcc) == (uchar16)0)? b : val; - c = (convert_uchar16(ccc) == (uchar16)0)? c : val; - d = (convert_uchar16(dcc) == (uchar16)0)? d : val; + a = (convert_uchar16(acc) == (uchar16)(0))? a : val; + b = (convert_uchar16(bcc) == (uchar16)(0))? b : val; + c = (convert_uchar16(ccc) == (uchar16)(0))? c : val; + d = (convert_uchar16(dcc) == (uchar16)(0))? d : val; float16 U = (float16)((float4)(u.x), (float4)(u.y), (float4)(u.z), (float4)(u.w)); float16 V = (float16)((float4)(v.x), (float4)(v.y), (float4)(v.z), (float4)(v.w)); @@ -621,7 +621,7 @@ __kernel void remapLNFConstant_C4_D0(__global unsigned char* dst, __global unsig uchar16 dVal = *D; int16 con = (Gx >= 0 && Gx < (dst_cols<<2) && y >= 0 && y < dst_rows); - dst_data = (convert_uchar16(con) != (uchar16)0) ? dst_data : dVal; + dst_data = (convert_uchar16(con) != (uchar16)(0)) ? dst_data : dVal; *D = dst_data; } @@ -646,7 +646,7 @@ __kernel void remapLNSConstant_C4_D0(__global unsigned char* dst, __global unsig short8 map1_data; map1_data = *((__global short8 *)((__global char*)map1 + map1Start)); - int4 srcIdx = convert_int4(map1_data.odd) * src_step + convert_int4(map1_data.even <<(short4)2) + src_offset; + int4 srcIdx = convert_int4(map1_data.odd) * src_step + (convert_int4(map1_data.even) <<(int4)(2)) + src_offset; uchar4 src_a, src_b, src_c, src_d; src_a = *((__global uchar4 *)((__global char*)src + srcIdx.s0)); src_b = *((__global uchar4 *)((__global char*)src + srcIdx.s1)); @@ -666,7 +666,7 @@ __kernel void remapLNSConstant_C4_D0(__global unsigned char* dst, __global unsig uchar16 dVal = *d; int16 con = (Gx >= 0 && Gx < (dst_cols<<2) && y >= 0 && y < dst_rows); - dst_data = (convert_uchar16(con) != (uchar16)0) ? dst_data : dVal; + dst_data = (convert_uchar16(con) != (uchar16)(0)) ? dst_data : dVal; *d = dst_data; @@ -700,21 +700,21 @@ __kernel void remapLNFConstant_C1_D5(__global float* dst, __global float const * float4 u = temp.even; float4 v = temp.odd; - float4 ud = 1.f - u; - float4 vd = 1.f - v; + float4 ud = (float4)(1.0) - u; + float4 vd = (float4)(1.0) - v; //float8 map1_dataU = map1_dataD + 1; int4 map1_dataDx = map1_dataD.even; int4 map1_dataDy = map1_dataD.odd; - int4 map1_dataDx1 = map1_dataDx + 1; - int4 map1_dataDy1 = map1_dataDy + 1; + int4 map1_dataDx1 = map1_dataDx + (int4)(1); + int4 map1_dataDy1 = map1_dataDy + (int4)(1); - int4 src_StartU = map1_dataDy * src_step + (map1_dataDx << 2) + src_offset; + int4 src_StartU = map1_dataDy * src_step + (map1_dataDx << (int4)(2)) + src_offset; int4 src_StartD = src_StartU + src_step; /* //not using the vload - int4 src_StartU1 = src_StartU + 1; - int4 src_StartD1 = src_StartD + 1; + int4 src_StartU1 = src_StartU + (int4)(1); + int4 src_StartD1 = src_StartD + (int4)(1); float4 a, b, c, d; a.x = *(src_StartU.x + src); @@ -754,14 +754,14 @@ __kernel void remapLNFConstant_C1_D5(__global float* dst, __global float const * c = (float4)(aD.x, bD.x, cD.x, dD.x); d = (float4)(aD.y, bD.y, cD.y, dD.y); - int4 ac =(map1_dataDx >= src_cols || map1_dataDy >= src_rows || map1_dataDy< 0 || map1_dataDy < 0); - int4 bc =(map1_dataDx1 >= src_cols || map1_dataDy >= src_rows || map1_dataDx1 < 0 || map1_dataDy < 0); - int4 cc =(map1_dataDx >= src_cols || map1_dataDy1 >= src_rows || map1_dataDy1 < 0 || map1_dataDx < 0); - int4 dc =(map1_dataDx1 >= src_cols || map1_dataDy1 >= src_rows || map1_dataDy1 < 0 || map1_dataDy1 < 0); - a = (convert_float4(ac) == 0)? a : val; - b = (convert_float4(bc) == 0)? b : val; - c = (convert_float4(cc) == 0)? c : val; - d = (convert_float4(dc) == 0)? d : val; + int4 ac =(map1_dataDx >= (int4)(src_cols) || map1_dataDy >= (int4)(src_rows) || map1_dataDy < (int4)(0) || map1_dataDy < (int4)(0)); + int4 bc =(map1_dataDx1 >= (int4)(src_cols) || map1_dataDy >= (int4)(src_rows) || map1_dataDx1 < (int4)(0) || map1_dataDy < (int4)(0)); + int4 cc =(map1_dataDx >= (int4)(src_cols) || map1_dataDy1 >= (int4)(src_rows) || map1_dataDy1 < (int4)(0) || map1_dataDx < (int4)(0)); + int4 dc =(map1_dataDx1 >= (int4)(src_cols) || map1_dataDy1 >= (int4)(src_rows) || map1_dataDy1 < (int4)(0) || map1_dataDy1 < (int4)(0)); + a = (convert_float4(ac) == (float4)(0))? a : val; + b = (convert_float4(bc) == (float4)(0))? b : val; + c = (convert_float4(cc) == (float4)(0))? c : val; + d = (convert_float4(dc) == (float4)(0))? d : val; float4 dst_data = a * ud * vd + b * u * vd + c * ud * v + d * u * v ; @@ -769,7 +769,7 @@ __kernel void remapLNFConstant_C1_D5(__global float* dst, __global float const * float4 dVal = *D; int4 con = (Gx >= 0 && Gx < (dst_cols << 2) && y >= 0 && y < dst_rows); - dst_data = (convert_float4(con) != 0) ? dst_data : dVal; + dst_data = (convert_float4(con) != (float4)(0)) ? dst_data : dVal; *D = dst_data; } @@ -798,7 +798,7 @@ __kernel void remapLNSConstant_C1_D5(__global float* dst, __global float const * map1_data = *((__global short8 *)((__global char*)map1 + map1Start)); - int4 srcIdx = convert_int4(map1_data.odd) * src_step + convert_int4(map1_data.even <<(short4)2) + src_offset; + int4 srcIdx = convert_int4(map1_data.odd) * src_step + (convert_int4(map1_data.even) << (int4)(2)) + src_offset; float4 src_data; src_data.s0 = *((__global float *)((__global char*)src + srcIdx.s0)); @@ -818,7 +818,7 @@ __kernel void remapLNSConstant_C1_D5(__global float* dst, __global float const * float4 dVal = *d; int4 con = (Gx >= 0 && Gx < (dst_cols<<2) && y >= 0 && y < dst_rows); - dst_data = (convert_float4(con) != 0) ? dst_data : dVal; + dst_data = (convert_float4(con) != (float4)(0)) ? dst_data : dVal; *d = dst_data; @@ -918,7 +918,7 @@ __kernel void remapNNSConstant_C1_D0(__global unsigned char* dst, __read_only im __global uchar4* d = (__global uchar4 *)(dst + dstStart); uchar4 dVal = *d; int4 con = (Gx >= 0 && Gx < dst_cols && y >= 0 && y < dst_rows); - dst_data = (convert_uchar4(con) != (uchar4)0) ? dst_data : dVal; + dst_data = (convert_uchar4(con) != (uchar4)(0)) ? dst_data : dVal; *d = dst_data; } diff --git a/modules/ocl/src/matrix_operations.cpp b/modules/ocl/src/matrix_operations.cpp index 2a2d1f77d8..53c2821d6c 100644 --- a/modules/ocl/src/matrix_operations.cpp +++ b/modules/ocl/src/matrix_operations.cpp @@ -588,6 +588,13 @@ void set_to_withoutmask_run(const oclMat &dst, const Scalar &scalar, string kern sprintf(compile_option, "-D GENTYPE=int"); args.push_back( make_pair( sizeof(cl_int) , (void *)&val.ival.s[0] )); break; + case 2: + sprintf(compile_option, "-D GENTYPE=int2"); + cl_int2 i2val; + i2val.s[0] = val.ival.s[0]; + i2val.s[1] = val.ival.s[1]; + args.push_back( make_pair( sizeof(cl_int2) , (void *)&i2val )); + break; case 4: sprintf(compile_option, "-D GENTYPE=int4"); args.push_back( make_pair( sizeof(cl_int4) , (void *)&val.ival )); diff --git a/modules/ocl/src/threadsafe.cpp b/modules/ocl/src/threadsafe.cpp index 59b3d7b82f..9d952d328c 100644 --- a/modules/ocl/src/threadsafe.cpp +++ b/modules/ocl/src/threadsafe.cpp @@ -44,7 +44,7 @@ //M*/ #include "precomp.hpp" -#include "threadsafe.h" +#include "Threadsafe.h" CriticalSection::CriticalSection() { diff --git a/modules/ocl/test/test_imgproc.cpp b/modules/ocl/test/test_imgproc.cpp index 90ff0b4414..ff2f441718 100644 --- a/modules/ocl/test/test_imgproc.cpp +++ b/modules/ocl/test/test_imgproc.cpp @@ -958,7 +958,7 @@ TEST_P(Remap, Mat) if((interpolation == 1 && map1Type == CV_16SC2) ||(interpolation == 1 && map1Type == CV_16SC1 && map2Type == CV_16SC1)) { cout << "LINEAR don't support the map1Type and map2Type" << endl; - return; + return; } int bordertype[] = {cv::BORDER_CONSTANT,cv::BORDER_REPLICATE/*,BORDER_REFLECT,BORDER_WRAP,BORDER_REFLECT_101*/}; const char* borderstr[]={"BORDER_CONSTANT", "BORDER_REPLICATE"/*, "BORDER_REFLECT","BORDER_WRAP","BORDER_REFLECT_101"*/}; From 6e4eb722a6e426960f2e515cf35b28482fc4a8bc Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 17 Aug 2012 15:14:14 +0400 Subject: [PATCH 003/163] updated gpu performance tests now it executes only on one device added posibility to specify device on which tests will be executed --- modules/gpu/perf/perf_calib3d.cpp | 268 ++-- modules/gpu/perf/perf_core.cpp | 1830 ++++++++++---------------- modules/gpu/perf/perf_features2d.cpp | 234 ++-- modules/gpu/perf/perf_filters.cpp | 281 ++-- modules/gpu/perf/perf_imgproc.cpp | 1384 +++++++++---------- modules/gpu/perf/perf_labeling.cpp | 18 +- modules/gpu/perf/perf_main.cpp | 87 ++ modules/gpu/perf/perf_matop.cpp | 134 +- modules/gpu/perf/perf_objdetect.cpp | 83 +- modules/gpu/perf/perf_precomp.hpp | 8 + modules/gpu/perf/perf_utility.cpp | 41 +- modules/gpu/perf/perf_utility.hpp | 74 +- modules/gpu/perf/perf_video.cpp | 490 +++---- 13 files changed, 2079 insertions(+), 2853 deletions(-) diff --git a/modules/gpu/perf/perf_calib3d.cpp b/modules/gpu/perf/perf_calib3d.cpp index 7a9c6c3950..343a4e9fad 100644 --- a/modules/gpu/perf/perf_calib3d.cpp +++ b/modules/gpu/perf/perf_calib3d.cpp @@ -1,207 +1,180 @@ #include "perf_precomp.hpp" -#ifdef HAVE_CUDA +using namespace std; +using namespace testing; + +namespace { ////////////////////////////////////////////////////////////////////// // StereoBM -GPU_PERF_TEST_1(StereoBM, cv::gpu::DeviceInfo) +typedef pair pair_string; +DEF_PARAM_TEST_1(ImagePair, pair_string); + +PERF_TEST_P(ImagePair, Calib3D_StereoBM, Values(make_pair("gpu/perf/aloe.jpg", "gpu/perf/aloeR.jpg"))) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Mat img_l_host = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_l_host.empty()); - - cv::Mat img_r_host = readImage("gpu/perf/aloeR.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_r_host.empty()); - - cv::gpu::StereoBM_GPU bm(0, 256); - cv::gpu::GpuMat img_l(img_l_host); - cv::gpu::GpuMat img_r(img_r_host); - cv::gpu::GpuMat dst; - - bm(img_l, img_r, dst); - declare.time(5.0); + cv::Mat imgLeft = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(imgLeft.empty()); + + cv::Mat imgRight = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(imgRight.empty()); + + cv::gpu::StereoBM_GPU d_bm(0, 256); + cv::gpu::GpuMat d_imgLeft(imgLeft); + cv::gpu::GpuMat d_imgRight(imgRight); + cv::gpu::GpuMat d_dst; + + d_bm(d_imgLeft, d_imgRight, d_dst); + TEST_CYCLE() { - bm(img_l, img_r, dst); + d_bm(d_imgLeft, d_imgRight, d_dst); } } -INSTANTIATE_TEST_CASE_P(Calib3D, StereoBM, ALL_DEVICES); - ////////////////////////////////////////////////////////////////////// // StereoBeliefPropagation -GPU_PERF_TEST_1(StereoBeliefPropagation, cv::gpu::DeviceInfo) +PERF_TEST_P(ImagePair, Calib3D_StereoBeliefPropagation, Values(make_pair("gpu/stereobp/aloe-L.png", "gpu/stereobp/aloe-R.png"))) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Mat img_l_host = readImage("gpu/stereobp/aloe-L.png"); - ASSERT_FALSE(img_l_host.empty()); - - cv::Mat img_r_host = readImage("gpu/stereobp/aloe-R.png"); - ASSERT_FALSE(img_r_host.empty()); - - cv::gpu::StereoBeliefPropagation bp(64); - cv::gpu::GpuMat img_l(img_l_host); - cv::gpu::GpuMat img_r(img_r_host); - cv::gpu::GpuMat dst; - - bp(img_l, img_r, dst); - declare.time(10.0); + cv::Mat imgLeft = readImage(GetParam().first); + ASSERT_FALSE(imgLeft.empty()); + + cv::Mat imgRight = readImage(GetParam().second); + ASSERT_FALSE(imgRight.empty()); + + cv::gpu::StereoBeliefPropagation d_bp(64); + cv::gpu::GpuMat d_imgLeft(imgLeft); + cv::gpu::GpuMat d_imgRight(imgRight); + cv::gpu::GpuMat d_dst; + + d_bp(d_imgLeft, d_imgRight, d_dst); + TEST_CYCLE() { - bp(img_l, img_r, dst); + d_bp(d_imgLeft, d_imgRight, d_dst); } } -INSTANTIATE_TEST_CASE_P(Calib3D, StereoBeliefPropagation, ALL_DEVICES); - ////////////////////////////////////////////////////////////////////// // StereoConstantSpaceBP -GPU_PERF_TEST_1(StereoConstantSpaceBP, cv::gpu::DeviceInfo) +PERF_TEST_P(ImagePair, Calib3D_StereoConstantSpaceBP, Values(make_pair("gpu/stereobm/aloe-L.png", "gpu/stereobm/aloe-R.png"))) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Mat img_l_host = readImage("gpu/stereobm/aloe-L.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_l_host.empty()); - - cv::Mat img_r_host = readImage("gpu/stereobm/aloe-R.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_r_host.empty()); - - cv::gpu::StereoConstantSpaceBP csbp(128); - cv::gpu::GpuMat img_l(img_l_host); - cv::gpu::GpuMat img_r(img_r_host); - cv::gpu::GpuMat dst; - - csbp(img_l, img_r, dst); - declare.time(10.0); + cv::Mat imgLeft = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(imgLeft.empty()); + + cv::Mat imgRight = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(imgRight.empty()); + + cv::gpu::StereoConstantSpaceBP d_csbp(128); + cv::gpu::GpuMat d_imgLeft(imgLeft); + cv::gpu::GpuMat d_imgRight(imgRight); + cv::gpu::GpuMat d_dst; + + d_csbp(d_imgLeft, d_imgRight, d_dst); + TEST_CYCLE() { - csbp(img_l, img_r, dst); + d_csbp(d_imgLeft, d_imgRight, d_dst); } } -INSTANTIATE_TEST_CASE_P(Calib3D, StereoConstantSpaceBP, ALL_DEVICES); - ////////////////////////////////////////////////////////////////////// // DisparityBilateralFilter -GPU_PERF_TEST_1(DisparityBilateralFilter, cv::gpu::DeviceInfo) +PERF_TEST_P(ImagePair, Calib3D_DisparityBilateralFilter, Values(make_pair("gpu/stereobm/aloe-L.png", "gpu/stereobm/aloe-disp.png"))) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(img.empty()); - cv::Mat img_host = readImage("gpu/stereobm/aloe-L.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_host.empty()); + cv::Mat disp = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(disp.empty()); - cv::Mat disp_host = readImage("gpu/stereobm/aloe-disp.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(disp_host.empty()); + cv::gpu::DisparityBilateralFilter d_filter(128); + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_disp(disp); + cv::gpu::GpuMat d_dst; - cv::gpu::DisparityBilateralFilter f(128); - cv::gpu::GpuMat img(img_host); - cv::gpu::GpuMat disp(disp_host); - cv::gpu::GpuMat dst; - - f(disp, img, dst); + d_filter(d_disp, d_img, d_dst); TEST_CYCLE() { - f(disp, img, dst); + d_filter(d_disp, d_img, d_dst); } } -INSTANTIATE_TEST_CASE_P(Calib3D, DisparityBilateralFilter, ALL_DEVICES); - ////////////////////////////////////////////////////////////////////// // TransformPoints -IMPLEMENT_PARAM_CLASS(Count, int) +DEF_PARAM_TEST_1(Count, int); -GPU_PERF_TEST(TransformPoints, cv::gpu::DeviceInfo, Count) +PERF_TEST_P(Count, Calib3D_TransformPoints, Values(5000, 10000, 20000)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + int count = GetParam(); - int count = GET_PARAM(1); + cv::Mat src(1, count, CV_32FC3); + fillRandom(src, -100, 100); - cv::Mat src_host(1, count, CV_32FC3); - fill(src_host, -100, 100); - - cv::gpu::GpuMat src(src_host); cv::Mat rvec = cv::Mat::ones(1, 3, CV_32FC1); cv::Mat tvec = cv::Mat::ones(1, 3, CV_32FC1); - cv::gpu::GpuMat dst; - cv::gpu::transformPoints(src, rvec, tvec, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::transformPoints(d_src, rvec, tvec, d_dst); TEST_CYCLE() { - cv::gpu::transformPoints(src, rvec, tvec, dst); + cv::gpu::transformPoints(d_src, rvec, tvec, d_dst); } } -INSTANTIATE_TEST_CASE_P(Calib3D, TransformPoints, testing::Combine( - ALL_DEVICES, - testing::Values(5000, 10000, 20000))); - ////////////////////////////////////////////////////////////////////// // ProjectPoints -GPU_PERF_TEST(ProjectPoints, cv::gpu::DeviceInfo, Count) +PERF_TEST_P(Count, Calib3D_ProjectPoints, Values(5000, 10000, 20000)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + int count = GetParam(); - int count = GET_PARAM(1); + cv::Mat src(1, count, CV_32FC3); + fillRandom(src, -100, 100); - cv::Mat src_host(1, count, CV_32FC3); - fill(src_host, -100, 100); - - cv::gpu::GpuMat src(src_host); cv::Mat rvec = cv::Mat::ones(1, 3, CV_32FC1); cv::Mat tvec = cv::Mat::ones(1, 3, CV_32FC1); cv::Mat camera_mat = cv::Mat::ones(3, 3, CV_32FC1); - cv::gpu::GpuMat dst; - cv::gpu::projectPoints(src, rvec, tvec, camera_mat, cv::Mat(), dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::projectPoints(d_src, rvec, tvec, camera_mat, cv::Mat(), d_dst); TEST_CYCLE() { - cv::gpu::projectPoints(src, rvec, tvec, camera_mat, cv::Mat(), dst); + cv::gpu::projectPoints(d_src, rvec, tvec, camera_mat, cv::Mat(), d_dst); } } -INSTANTIATE_TEST_CASE_P(Calib3D, ProjectPoints, testing::Combine( - ALL_DEVICES, - testing::Values(5000, 10000, 20000))); - ////////////////////////////////////////////////////////////////////// // SolvePnPRansac -GPU_PERF_TEST(SolvePnPRansac, cv::gpu::DeviceInfo, Count) +PERF_TEST_P(Count, Calib3D_SolvePnPRansac, Values(5000, 10000, 20000)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + declare.time(3.0); - int count = GET_PARAM(1); + int count = GetParam(); cv::Mat object(1, count, CV_32FC3); - fill(object, -100, 100); + fillRandom(object, -100, 100); cv::Mat camera_mat(3, 3, CV_32FC1); - fill(camera_mat, 0.5, 1); + fillRandom(camera_mat, 0.5, 1); camera_mat.at(0, 1) = 0.f; camera_mat.at(1, 0) = 0.f; camera_mat.at(2, 0) = 0.f; @@ -211,9 +184,9 @@ GPU_PERF_TEST(SolvePnPRansac, cv::gpu::DeviceInfo, Count) std::vector image_vec; cv::Mat rvec_gold(1, 3, CV_32FC1); - fill(rvec_gold, 0, 1); + fillRandom(rvec_gold, 0, 1); cv::Mat tvec_gold(1, 3, CV_32FC1); - fill(tvec_gold, 0, 1); + fillRandom(tvec_gold, 0, 1); cv::projectPoints(object, rvec_gold, tvec_gold, camera_mat, dist_coef, image_vec); cv::Mat image(1, count, CV_32FC2, &image_vec[0]); @@ -223,80 +196,57 @@ GPU_PERF_TEST(SolvePnPRansac, cv::gpu::DeviceInfo, Count) cv::gpu::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); - declare.time(3.0); - TEST_CYCLE() { cv::gpu::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); } } -INSTANTIATE_TEST_CASE_P(Calib3D, SolvePnPRansac, testing::Combine( - ALL_DEVICES, - testing::Values(5000, 10000, 20000))); - ////////////////////////////////////////////////////////////////////// // ReprojectImageTo3D -GPU_PERF_TEST(ReprojectImageTo3D, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Calib3D_ReprojectImageTo3D, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src_host(size, depth); - fill(src_host, 5.0, 30.0); + cv::Mat src(size, depth); + fillRandom(src, 5.0, 30.0); cv::Mat Q(4, 4, CV_32FC1); - fill(Q, 0.1, 1.0); + fillRandom(Q, 0.1, 1.0); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::reprojectImageTo3D(src, dst, Q); + cv::gpu::reprojectImageTo3D(d_src, d_dst, Q); TEST_CYCLE() { - cv::gpu::reprojectImageTo3D(src, dst, Q); + cv::gpu::reprojectImageTo3D(d_src, d_dst, Q); } } -INSTANTIATE_TEST_CASE_P(Calib3D, ReprojectImageTo3D, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S))); - ////////////////////////////////////////////////////////////////////// // DrawColorDisp -GPU_PERF_TEST(DrawColorDisp, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Calib3D_DrawColorDisp, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + cv::Mat src(size, type); + fillRandom(src, 0, 255); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::drawColorDisp(src, dst, 255); + cv::gpu::drawColorDisp(d_src, d_dst, 255); TEST_CYCLE() { - cv::gpu::drawColorDisp(src, dst, 255); + cv::gpu::drawColorDisp(d_src, d_dst, 255); } } -INSTANTIATE_TEST_CASE_P(Calib3D, DrawColorDisp, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatDepth(CV_8U), MatDepth(CV_16S)))); - -#endif - +} // namespace diff --git a/modules/gpu/perf/perf_core.cpp b/modules/gpu/perf/perf_core.cpp index f413432041..b56713a70e 100644 --- a/modules/gpu/perf/perf_core.cpp +++ b/modules/gpu/perf/perf_core.cpp @@ -1,1883 +1,1513 @@ #include "perf_precomp.hpp" -#ifdef HAVE_CUDA +using namespace std; +using namespace testing; + +namespace { + +#define ARITHM_MAT_DEPTH Values(CV_8U, CV_16U, CV_32F, CV_64F) ////////////////////////////////////////////////////////////////////// // Merge -GPU_PERF_TEST(Merge, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) +PERF_TEST_P(Sz_Depth_Cn, Core_Merge, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, Values(2, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); - - std::vector src(channels); + std::vector d_src(channels); for (int i = 0; i < channels; ++i) - src[i] = cv::gpu::GpuMat(size, depth, cv::Scalar::all(i)); + d_src[i] = cv::gpu::GpuMat(size, depth, cv::Scalar::all(i)); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_dst; - cv::gpu::merge(src, dst); + cv::gpu::merge(d_src, d_dst); TEST_CYCLE() { - cv::gpu::merge(src, dst); + cv::gpu::merge(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Merge, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - testing::Values(2, 3, 4))); - ////////////////////////////////////////////////////////////////////// // Split -GPU_PERF_TEST(Split, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) +PERF_TEST_P(Sz_Depth_Cn, Core_Split, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, Values(2, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); + cv::gpu::GpuMat d_src(size, CV_MAKE_TYPE(depth, channels), cv::Scalar(1, 2, 3, 4)); - cv::gpu::GpuMat src(size, CV_MAKE_TYPE(depth, channels), cv::Scalar(1, 2, 3, 4)); + std::vector d_dst; - std::vector dst; - - cv::gpu::split(src, dst); + cv::gpu::split(d_src, d_dst); TEST_CYCLE() { - cv::gpu::split(src, dst); + cv::gpu::split(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Split, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - testing::Values(2, 3, 4))); - ////////////////////////////////////////////////////////////////////// -// Add_Mat +// AddMat -GPU_PERF_TEST(Add_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_AddMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0.0, 100.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0.0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::add(src1, src2, dst); + cv::gpu::add(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::add(src1, src2, dst); + cv::gpu::add(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Add_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// -// Add_Scalar +// AddScalar -GPU_PERF_TEST(Add_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_AddScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 100.0); - - cv::gpu::GpuMat src(src_host); cv::Scalar s(1, 2, 3, 4); - cv::gpu::GpuMat dst; - cv::gpu::add(src, s, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::add(d_src, s, d_dst); TEST_CYCLE() { - cv::gpu::add(src, s, dst); + cv::gpu::add(d_src, s, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Add_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// -// Subtract_Mat +// SubtractMat -GPU_PERF_TEST(Subtract_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_SubtractMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0.0, 100.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0.0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::subtract(src1, src2, dst); + cv::gpu::subtract(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::subtract(src1, src2, dst); + cv::gpu::subtract(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Subtract_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// -// Subtract_Scalar +// SubtractScalar -GPU_PERF_TEST(Subtract_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_SubtractScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 100.0); - - cv::gpu::GpuMat src(src_host); cv::Scalar s(1, 2, 3, 4); - cv::gpu::GpuMat dst; - cv::gpu::subtract(src, s, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::subtract(d_src, s, d_dst); TEST_CYCLE() { - cv::gpu::subtract(src, s, dst); + cv::gpu::subtract(d_src, s, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Subtract_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// -// Multiply_Mat +// MultiplyMat -GPU_PERF_TEST(Multiply_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_MultiplyMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0.0, 100.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0.0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::multiply(src1, src2, dst); + cv::gpu::multiply(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::multiply(src1, src2, dst); + cv::gpu::multiply(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Multiply_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// -// Multiply_Scalar +// MultiplyScalar -GPU_PERF_TEST(Multiply_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_MultiplyScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 100.0); - - cv::gpu::GpuMat src(src_host); cv::Scalar s(1, 2, 3, 4); - cv::gpu::GpuMat dst; - cv::gpu::multiply(src, s, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::multiply(d_src, s, d_dst); TEST_CYCLE() { - cv::gpu::multiply(src, s, dst); + cv::gpu::multiply(d_src, s, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Multiply_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// -// Divide_Mat +// DivideMat -GPU_PERF_TEST(Divide_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_DivideMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0.0, 100.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0.0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::divide(src1, src2, dst); + cv::gpu::divide(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::divide(src1, src2, dst); + cv::gpu::divide(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Divide_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// -// Divide_Scalar +// DivideScalar -GPU_PERF_TEST(Divide_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_DivideScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 100.0); - - cv::gpu::GpuMat src(src_host); cv::Scalar s(1, 2, 3, 4); - cv::gpu::GpuMat dst; - cv::gpu::divide(src, s, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::divide(d_src, s, d_dst); TEST_CYCLE() { - cv::gpu::divide(src, s, dst); + cv::gpu::divide(d_src, s, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Divide_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// -// Divide_Scalar_Inv +// DivideScalarInv -GPU_PERF_TEST(Divide_Scalar_Inv, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_DivideScalarInv, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 100.0); + double s = 100.0; - cv::gpu::GpuMat src(src_host); - double scale = 100.0; - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::divide(scale, src, dst); + cv::gpu::divide(s, d_src, d_dst); TEST_CYCLE() { - cv::gpu::divide(scale, src, dst); + cv::gpu::divide(s, d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Divide_Scalar_Inv, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// -// AbsDiff_Mat +// AbsDiffMat -GPU_PERF_TEST(AbsDiff_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_AbsDiffMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0.0, 100.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0.0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::absdiff(src1, src2, dst); + cv::gpu::absdiff(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::absdiff(src1, src2, dst); + cv::gpu::absdiff(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, AbsDiff_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// -// AbsDiff_Scalar +// AbsDiffScalar -GPU_PERF_TEST(AbsDiff_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_AbsDiffScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 100.0); - - cv::gpu::GpuMat src(src_host); cv::Scalar s(1, 2, 3, 4); - cv::gpu::GpuMat dst; - cv::gpu::absdiff(src, s, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::absdiff(d_src, s, d_dst); TEST_CYCLE() { - cv::gpu::absdiff(src, s, dst); + cv::gpu::absdiff(d_src, s, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, AbsDiff_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// // Abs -GPU_PERF_TEST(Abs, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_Abs, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_16S, CV_32F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 100.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::abs(src, dst); + cv::gpu::abs(d_src, d_dst); TEST_CYCLE() { - cv::gpu::abs(src, dst); + cv::gpu::abs(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Abs, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_16S, CV_32F))); - ////////////////////////////////////////////////////////////////////// // Sqr -GPU_PERF_TEST(Sqr, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_Sqr, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 100.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::sqr(src, dst); + cv::gpu::sqr(d_src, d_dst); TEST_CYCLE() { - cv::gpu::sqr(src, dst); + cv::gpu::sqr(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Sqr, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S, CV_32F))); - ////////////////////////////////////////////////////////////////////// // Sqrt -GPU_PERF_TEST(Sqrt, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_Sqrt, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 100.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::sqrt(src, dst); + cv::gpu::sqrt(d_src, d_dst); TEST_CYCLE() { - cv::gpu::sqrt(src, dst); + cv::gpu::sqrt(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Sqrt, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S, CV_32F))); - ////////////////////////////////////////////////////////////////////// // Log -GPU_PERF_TEST(Log, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_Log, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src, 1.0, 255.0); - cv::Mat src_host(size, depth); - fill(src_host, 1.0, 100.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::log(src, dst); + cv::gpu::log(d_src, d_dst); TEST_CYCLE() { - cv::gpu::log(src, dst); + cv::gpu::log(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Log, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S, CV_32F))); - ////////////////////////////////////////////////////////////////////// // Exp -GPU_PERF_TEST(Exp, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_Exp, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src, 1.0, 10.0); - cv::Mat src_host(size, depth); - fill(src_host, 1.0, 10.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::exp(src, dst); + cv::gpu::exp(d_src, d_dst); TEST_CYCLE() { - cv::gpu::exp(src, dst); + cv::gpu::exp(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Exp, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S, CV_32F))); - ////////////////////////////////////////////////////////////////////// // Pow -GPU_PERF_TEST(Pow, cv::gpu::DeviceInfo, cv::Size, MatDepth) +DEF_PARAM_TEST(Sz_Depth_Power, cv::Size, MatDepth, double); + +PERF_TEST_P(Sz_Depth_Power, Core_Pow, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F), Values(0.3, 2.0, 2.4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + double power = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src, 1.0, 10.0); - cv::Mat src_host(size, depth); - fill(src_host, 1.0, 10.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::pow(src, 2.3, dst); + cv::gpu::pow(d_src, power, d_dst); TEST_CYCLE() { - cv::gpu::pow(src, 2.3, dst); + cv::gpu::pow(d_src, power, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Pow, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S, CV_32F))); - ////////////////////////////////////////////////////////////////////// -// Compare_Mat +// CompareMat CV_ENUM(CmpCode, cv::CMP_EQ, cv::CMP_GT, cv::CMP_GE, cv::CMP_LT, cv::CMP_LE, cv::CMP_NE) -#define ALL_CMP_CODES testing::Values(CmpCode(cv::CMP_EQ), CmpCode(cv::CMP_NE), CmpCode(cv::CMP_GT), CmpCode(cv::CMP_GE), CmpCode(cv::CMP_LT), CmpCode(cv::CMP_LE)) +#define ALL_CMP_CODES ValuesIn(CmpCode::all()) -GPU_PERF_TEST(Compare_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth, CmpCode) +DEF_PARAM_TEST(Sz_Depth_Code, cv::Size, MatDepth, CmpCode); + +PERF_TEST_P(Sz_Depth_Code, Core_CompareMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, ALL_CMP_CODES)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int cmp_code = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int cmp_code = GET_PARAM(3); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0, 100.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::compare(src1, src2, dst, cmp_code); + cv::gpu::compare(d_src1, d_src2, d_dst, cmp_code); TEST_CYCLE() { - cv::gpu::compare(src1, src2, dst, cmp_code); + cv::gpu::compare(d_src1, d_src2, d_dst, cmp_code); } } -INSTANTIATE_TEST_CASE_P(Core, Compare_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - ALL_CMP_CODES)); - ////////////////////////////////////////////////////////////////////// -// Compare_Scalar +// CompareScalar -GPU_PERF_TEST(Compare_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth, CmpCode) +PERF_TEST_P(Sz_Depth_Code, Core_CompareScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, ALL_CMP_CODES)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int cmp_code = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int cmp_code = GET_PARAM(3); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0, 100.0); + cv::Scalar s = cv::Scalar::all(100); - cv::gpu::GpuMat src(src_host); - cv::Scalar s = cv::Scalar::all(50); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::compare(src, s, dst, cmp_code); + cv::gpu::compare(d_src, s, d_dst, cmp_code); TEST_CYCLE() { - cv::gpu::compare(src, s, dst, cmp_code); + cv::gpu::compare(d_src, s, d_dst, cmp_code); } } -INSTANTIATE_TEST_CASE_P(Core, Compare_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - ALL_CMP_CODES)); - ////////////////////////////////////////////////////////////////////// -// Bitwise_Not +// BitwiseNot -GPU_PERF_TEST(Bitwise_Not, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_BitwiseNot, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0, 100.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::bitwise_not(src, dst); + cv::gpu::bitwise_not(d_src, d_dst); TEST_CYCLE() { - cv::gpu::bitwise_not(src, dst); + cv::gpu::bitwise_not(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Bitwise_Not, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S))); - ////////////////////////////////////////////////////////////////////// -// Bitwise_And_Mat +// BitwiseAndMat -GPU_PERF_TEST(Bitwise_And_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_BitwiseAndMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0, 100.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::bitwise_and(src1, src2, dst); + cv::gpu::bitwise_and(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::bitwise_and(src1, src2, dst); + cv::gpu::bitwise_and(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Bitwise_And_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S))); - ////////////////////////////////////////////////////////////////////// -// Bitwise_And_Scalar +// BitwiseAndScalar -GPU_PERF_TEST(Bitwise_And_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) +PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseAndScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 100.0); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); - cv::Scalar s = cv::Scalar(50, 50, 50, 50); - cv::gpu::GpuMat dst; + cv::Scalar s = cv::Scalar::all(100); - cv::gpu::bitwise_and(src, s, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::bitwise_and(d_src, s, d_dst); TEST_CYCLE() { - cv::gpu::bitwise_and(src, s, dst); + cv::gpu::bitwise_and(d_src, s, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Bitwise_And_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S), - testing::Values(1, 3, 4))); - ////////////////////////////////////////////////////////////////////// -// Bitwise_Or_Mat +// BitwiseOrMat -GPU_PERF_TEST(Bitwise_Or_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_BitwiseOrMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0, 100.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::bitwise_or(src1, src2, dst); + cv::gpu::bitwise_or(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::bitwise_or(src1, src2, dst); + cv::gpu::bitwise_or(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Bitwise_Or_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S))); - ////////////////////////////////////////////////////////////////////// -// Bitwise_Or_Scalar +// BitwiseOrScalar -GPU_PERF_TEST(Bitwise_Or_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) +PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseOrScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 100.0); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); - cv::Scalar s = cv::Scalar(50, 50, 50, 50); - cv::gpu::GpuMat dst; + cv::Scalar s = cv::Scalar::all(100); - cv::gpu::bitwise_or(src, s, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::bitwise_or(d_src, s, d_dst); TEST_CYCLE() { - cv::gpu::bitwise_or(src, s, dst); + cv::gpu::bitwise_or(d_src, s, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Bitwise_Or_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S), - testing::Values(1, 3, 4))); - ////////////////////////////////////////////////////////////////////// -// Bitwise_Xor_Mat +// BitwiseXorMat -GPU_PERF_TEST(Bitwise_Xor_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_BitwiseXorMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0, 100.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::bitwise_xor(src1, src2, dst); + cv::gpu::bitwise_xor(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::bitwise_xor(src1, src2, dst); + cv::gpu::bitwise_xor(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Bitwise_Xor_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S))); - ////////////////////////////////////////////////////////////////////// -// Bitwise_Xor_Scalar +// BitwiseXorScalar -GPU_PERF_TEST(Bitwise_Xor_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) +PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseXorScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 100.0); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); - cv::Scalar s = cv::Scalar(50, 50, 50, 50); - cv::gpu::GpuMat dst; + cv::Scalar s = cv::Scalar::all(100); - cv::gpu::bitwise_xor(src, s, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::bitwise_xor(d_src, s, d_dst); TEST_CYCLE() { - cv::gpu::bitwise_xor(src, s, dst); + cv::gpu::bitwise_xor(d_src, s, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Bitwise_Xor_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S), - testing::Values(1, 3, 4))); - ////////////////////////////////////////////////////////////////////// // RShift -GPU_PERF_TEST(RShift, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) +PERF_TEST_P(Sz_Depth_Cn, Core_RShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 255.0); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); cv::Scalar_ val = cv::Scalar_::all(4); - cv::gpu::GpuMat dst; - cv::gpu::rshift(src, val, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::rshift(d_src, val, d_dst); TEST_CYCLE() { - cv::gpu::rshift(src, val, dst); + cv::gpu::rshift(d_src, val, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, RShift, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S), - testing::Values(1, 3, 4))); - ////////////////////////////////////////////////////////////////////// // LShift -GPU_PERF_TEST(LShift, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) +PERF_TEST_P(Sz_Depth_Cn, Core_LShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 255.0); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); cv::Scalar_ val = cv::Scalar_::all(4); - cv::gpu::GpuMat dst; - cv::gpu::lshift(src, val, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::lshift(d_src, val, d_dst); TEST_CYCLE() { - cv::gpu::lshift(src, val, dst); + cv::gpu::lshift(d_src, val, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, LShift, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S), - testing::Values(1, 3, 4))); - ////////////////////////////////////////////////////////////////////// -// Min_Mat +// MinMat -GPU_PERF_TEST(Min_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_MinMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0, 255.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0, 255.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::min(src1, src2, dst); + cv::gpu::min(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::min(src1, src2, dst); + cv::gpu::min(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Min_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F))); - ////////////////////////////////////////////////////////////////////// -// Min_Scalar +// MinScalar -GPU_PERF_TEST(Min_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_MinScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0, 255.0); - - cv::gpu::GpuMat src(src_host); double val = 50.0; - cv::gpu::GpuMat dst; - cv::gpu::min(src, val, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::min(d_src, val, d_dst); TEST_CYCLE() { - cv::gpu::min(src, val, dst); + cv::gpu::min(d_src, val, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Min_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F))); - ////////////////////////////////////////////////////////////////////// -// Max_Mat +// MaxMat -GPU_PERF_TEST(Max_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_MaxMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src1(size, depth); + fillRandom(src1); - cv::Mat src1_host(size, depth); - fill(src1_host, 0, 255.0); + cv::Mat src2(size, depth); + fillRandom(src2); - cv::Mat src2_host(size, depth); - fill(src2_host, 0, 255.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::max(src1, src2, dst); + cv::gpu::max(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::max(src1, src2, dst); + cv::gpu::max(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Max_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F))); - ////////////////////////////////////////////////////////////////////// -// Max_Scalar +// MaxScalar -GPU_PERF_TEST(Max_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_MaxScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0, 255.0); - - cv::gpu::GpuMat src(src_host); double val = 50.0; - cv::gpu::GpuMat dst; - cv::gpu::max(src, val, dst); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::max(d_src, val, d_dst); TEST_CYCLE() { - cv::gpu::max(src, val, dst); + cv::gpu::max(d_src, val, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Max_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F))); - ////////////////////////////////////////////////////////////////////// // AddWeighted -GPU_PERF_TEST(AddWeighted, cv::gpu::DeviceInfo, cv::Size, MatDepth, MatDepth, MatDepth) +DEF_PARAM_TEST(Sz_3Depth, cv::Size, MatDepth, MatDepth, MatDepth); + +PERF_TEST_P(Sz_3Depth, Core_AddWeighted, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F), + Values(CV_8U, CV_16U, CV_32F, CV_64F), + Values(CV_8U, CV_16U, CV_32F, CV_64F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth1 = GET_PARAM(1); + int depth2 = GET_PARAM(2); + int dst_depth = GET_PARAM(3); - cv::Size size = GET_PARAM(1); - int depth1 = GET_PARAM(2); - int depth2 = GET_PARAM(3); - int dst_depth = GET_PARAM(4); + cv::Mat src1(size, depth1); + fillRandom(src1); - cv::Mat src1_host(size, depth1); - fill(src1_host, 0, 100.0); + cv::Mat src2(size, depth2); + fillRandom(src2); - cv::Mat src2_host(size, depth2); - fill(src2_host, 0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::addWeighted(src1, 0.5, src2, 0.5, 10.0, dst, dst_depth); + cv::gpu::addWeighted(d_src1, 0.5, d_src2, 0.5, 10.0, d_dst, dst_depth); TEST_CYCLE() { - cv::gpu::addWeighted(src1, 0.5, src2, 0.5, 10.0, dst, dst_depth); + cv::gpu::addWeighted(d_src1, 0.5, d_src2, 0.5, 10.0, d_dst, dst_depth); } } -INSTANTIATE_TEST_CASE_P(Core, AddWeighted, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// // GEMM -#ifdef HAVE_CUBLAS CV_FLAGS(GemmFlags, 0, cv::GEMM_1_T, cv::GEMM_2_T, cv::GEMM_3_T) -#define ALL_GEMM_FLAGS testing::Values(GemmFlags(0), GemmFlags(cv::GEMM_1_T), GemmFlags(cv::GEMM_2_T), GemmFlags(cv::GEMM_3_T), GemmFlags(cv::GEMM_1_T | cv::GEMM_2_T), GemmFlags(cv::GEMM_1_T | cv::GEMM_3_T), GemmFlags(cv::GEMM_1_T | cv::GEMM_2_T | cv::GEMM_3_T)) +#define ALL_GEMM_FLAGS Values(0, CV_GEMM_A_T, CV_GEMM_B_T, CV_GEMM_C_T, CV_GEMM_A_T | CV_GEMM_B_T, CV_GEMM_A_T | CV_GEMM_C_T, CV_GEMM_A_T | CV_GEMM_B_T | CV_GEMM_C_T) -GPU_PERF_TEST(GEMM, cv::gpu::DeviceInfo, cv::Size, MatType, GemmFlags) +DEF_PARAM_TEST(Sz_Type_Flags, cv::Size, MatType, GemmFlags); + +PERF_TEST_P(Sz_Type_Flags, Core_GEMM, Combine( + Values(cv::Size(512, 512), cv::Size(1024, 1024)), + Values(CV_32FC1, CV_32FC2, CV_64FC1, CV_64FC2), + ALL_GEMM_FLAGS)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int flags = GET_PARAM(3); - - cv::Mat src1_host(size, type); - fill(src1_host, 0.0, 10.0); - - cv::Mat src2_host(size, type); - fill(src2_host, 0.0, 10.0); - - cv::Mat src3_host(size, type); - fill(src3_host, 0.0, 10.0); - - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat src3(src3_host); - cv::gpu::GpuMat dst; - - cv::gpu::gemm(src1, src2, 1.0, src3, 1.0, dst, flags); - declare.time(5.0); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); + int flags = GET_PARAM(2); + + cv::Mat src1(size, type); + fillRandom(src1); + + cv::Mat src2(size, type); + fillRandom(src2); + + cv::Mat src3(size, type); + fillRandom(src3); + + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_src3(src3); + cv::gpu::GpuMat d_dst; + + cv::gpu::gemm(d_src1, d_src2, 1.0, d_src3, 1.0, d_dst, flags); + TEST_CYCLE() { - cv::gpu::gemm(src1, src2, 1.0, src3, 1.0, dst, flags); + cv::gpu::gemm(d_src1, d_src2, 1.0, d_src3, 1.0, d_dst, flags); } } -INSTANTIATE_TEST_CASE_P(Core, GEMM, testing::Combine( - ALL_DEVICES, - testing::Values(cv::Size(512, 512), cv::Size(1024, 1024)), - testing::Values(CV_32FC1, CV_32FC2, CV_64FC1, CV_64FC2), - ALL_GEMM_FLAGS)); - -#endif ////////////////////////////////////////////////////////////////////// // Transpose -GPU_PERF_TEST(Transpose, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Type, Core_Transpose, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8UC1, CV_8UC4, CV_16UC2, CV_16SC2, CV_32SC1, CV_32SC2, CV_64FC1))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + cv::Mat src(size, type); + fillRandom(src); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 100.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::transpose(src, dst); + cv::gpu::transpose(d_src, d_dst); TEST_CYCLE() { - cv::gpu::transpose(src, dst); + cv::gpu::transpose(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Transpose, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC1, CV_8UC4, CV_16UC2, CV_16SC2, CV_32SC1, CV_32SC2, CV_64FC1))); - ////////////////////////////////////////////////////////////////////// // Flip enum {FLIP_BOTH = 0, FLIP_X = 1, FLIP_Y = -1}; CV_ENUM(FlipCode, FLIP_BOTH, FLIP_X, FLIP_Y) -#define ALL_FLIP_CODES testing::Values(FlipCode(FLIP_BOTH), FlipCode(FLIP_X), FlipCode(FLIP_Y)) +#define ALL_FLIP_CODES ValuesIn(FlipCode::all()) -GPU_PERF_TEST(Flip, cv::gpu::DeviceInfo, cv::Size, MatType, FlipCode) +DEF_PARAM_TEST(Sz_Depth_Cn_Code, cv::Size, MatDepth, int, FlipCode); + +PERF_TEST_P(Sz_Depth_Cn_Code, Core_Flip, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4), + ALL_FLIP_CODES)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int flipCode = GET_PARAM(3); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 100.0); + int type = CV_MAKE_TYPE(depth, channels); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::flip(src, dst, flipCode); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::flip(d_src, d_dst, flipCode); TEST_CYCLE() { - cv::gpu::flip(src, dst, flipCode); + cv::gpu::flip(d_src, d_dst, flipCode); } } -INSTANTIATE_TEST_CASE_P(Core, Flip, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16UC1, CV_16UC3, CV_16UC4, CV_32FC1, CV_32FC3, CV_32FC4), - ALL_FLIP_CODES)); - ////////////////////////////////////////////////////////////////////// -// LUT_OneChannel +// LutOneChannel -GPU_PERF_TEST(LUT_OneChannel, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Type, Core_LutOneChannel, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8UC1, CV_8UC3))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src_host(size, type); - fill(src_host, 0.0, 100.0); + cv::Mat src(size, type); + fillRandom(src); cv::Mat lut(1, 256, CV_8UC1); - fill(lut, 0.0, 100.0); + fillRandom(lut); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::LUT(src, lut, dst); + cv::gpu::LUT(d_src, lut, d_dst); TEST_CYCLE() { - cv::gpu::LUT(src, lut, dst); + cv::gpu::LUT(d_src, lut, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, LUT_OneChannel, testing::Combine( - ALL_DEVICES, +////////////////////////////////////////////////////////////////////// +// LutMultiChannel + +PERF_TEST_P(Sz_Type, Core_LutMultiChannel, Combine( GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC1, CV_8UC3))); - -////////////////////////////////////////////////////////////////////// -// LUT_MultiChannel - -GPU_PERF_TEST(LUT_MultiChannel, cv::gpu::DeviceInfo, cv::Size, MatType) + Values(CV_8UC3))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + cv::Mat src(size, type); + fillRandom(src); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 100.0); + cv::Mat lut(1, 256, CV_MAKE_TYPE(CV_8U, src.channels())); + fillRandom(lut); - cv::Mat lut(1, 256, CV_MAKE_TYPE(CV_8U, src_host.channels())); - fill(lut, 0.0, 100.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::LUT(src, lut, dst); + cv::gpu::LUT(d_src, lut, d_dst); TEST_CYCLE() { - cv::gpu::LUT(src, lut, dst); + cv::gpu::LUT(d_src, lut, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, LUT_MultiChannel, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC3))); - ////////////////////////////////////////////////////////////////////// -// Magnitude_Complex +// MagnitudeComplex -GPU_PERF_TEST(Magnitude_Complex, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, Core_MagnitudeComplex, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); + cv::Mat src(size, CV_32FC2); + fillRandom(src, -100.0, 100.0); - cv::Mat src_host(size, CV_32FC2); - fill(src_host, -100.0, 100.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::magnitude(src, dst); + cv::gpu::magnitude(d_src, d_dst); TEST_CYCLE() { - cv::gpu::magnitude(src, dst); + cv::gpu::magnitude(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Magnitude_Complex, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// -// Magnitude_Sqr_Complex +// MagnitudeSqrComplex -GPU_PERF_TEST(Magnitude_Sqr_Complex, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, Core_MagnitudeSqrComplex, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); + cv::Mat src(size, CV_32FC2); + fillRandom(src, -100.0, 100.0); - cv::Mat src_host(size, CV_32FC2); - fill(src_host, -100.0, 100.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::magnitudeSqr(src, dst); + cv::gpu::magnitudeSqr(d_src, d_dst); TEST_CYCLE() { - cv::gpu::magnitudeSqr(src, dst); + cv::gpu::magnitudeSqr(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Magnitude_Sqr_Complex, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // Magnitude -GPU_PERF_TEST(Magnitude, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, Core_Magnitude, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); + cv::Mat src1(size, CV_32FC1); + fillRandom(src1, -100.0, 100.0); - cv::Mat src1_host(size, CV_32FC1); - fill(src1_host, -100.0, 100.0); + cv::Mat src2(size, CV_32FC1); + fillRandom(src2, -100.0, 100.0); - cv::Mat src2_host(size, CV_32FC1); - fill(src2_host, -100.0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::magnitude(src1, src2, dst); + cv::gpu::magnitude(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::magnitude(src1, src2, dst); + cv::gpu::magnitude(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Magnitude, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// -// Magnitude_Sqr +// MagnitudeSqr -GPU_PERF_TEST(Magnitude_Sqr, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, Core_MagnitudeSqr, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); + cv::Mat src1(size, CV_32FC1); + fillRandom(src1, -100.0, 100.0); - cv::Mat src1_host(size, CV_32FC1); - fill(src1_host, -100.0, 100.0); + cv::Mat src2(size, CV_32FC1); + fillRandom(src2, -100.0, 100.0); - cv::Mat src2_host(size, CV_32FC1); - fill(src2_host, -100.0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::magnitudeSqr(src1, src2, dst); + cv::gpu::magnitudeSqr(d_src1, d_src2, d_dst); TEST_CYCLE() { - cv::gpu::magnitudeSqr(src1, src2, dst); + cv::gpu::magnitudeSqr(d_src1, d_src2, d_dst); } } -INSTANTIATE_TEST_CASE_P(Core, Magnitude_Sqr, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // Phase -IMPLEMENT_PARAM_CLASS(AngleInDegrees, bool) +DEF_PARAM_TEST(Sz_AngleInDegrees, cv::Size, bool); -GPU_PERF_TEST(Phase, cv::gpu::DeviceInfo, cv::Size, AngleInDegrees) +PERF_TEST_P(Sz_AngleInDegrees, Core_Phase, Combine(GPU_TYPICAL_MAT_SIZES, Bool())) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + bool angleInDegrees = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - bool angleInDegrees = GET_PARAM(2); + cv::Mat src1(size, CV_32FC1); + fillRandom(src1, -100.0, 100.0); - cv::Mat src1_host(size, CV_32FC1); - fill(src1_host, -100.0, 100.0); + cv::Mat src2(size, CV_32FC1); + fillRandom(src2, -100.0, 100.0); - cv::Mat src2_host(size, CV_32FC1); - fill(src2_host, -100.0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; - - cv::gpu::phase(src1, src2, dst, angleInDegrees); + cv::gpu::phase(d_src1, d_src2, d_dst, angleInDegrees); TEST_CYCLE() { - cv::gpu::phase(src1, src2, dst, angleInDegrees); + cv::gpu::phase(d_src1, d_src2, d_dst, angleInDegrees); } } -INSTANTIATE_TEST_CASE_P(Core, Phase, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(false, true))); - ////////////////////////////////////////////////////////////////////// // CartToPolar -GPU_PERF_TEST(CartToPolar, cv::gpu::DeviceInfo, cv::Size, AngleInDegrees) +PERF_TEST_P(Sz_AngleInDegrees, Core_CartToPolar, Combine(GPU_TYPICAL_MAT_SIZES, Bool())) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + bool angleInDegrees = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - bool angleInDegrees = GET_PARAM(2); + cv::Mat src1(size, CV_32FC1); + fillRandom(src1, -100.0, 100.0); - cv::Mat src1_host(size, CV_32FC1); - fill(src1_host, -100.0, 100.0); + cv::Mat src2(size, CV_32FC1); + fillRandom(src2, -100.0, 100.0); - cv::Mat src2_host(size, CV_32FC1); - fill(src2_host, -100.0, 100.0); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_magnitude; + cv::gpu::GpuMat d_angle; - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat magnitude; - cv::gpu::GpuMat angle; - - cv::gpu::cartToPolar(src1, src2, magnitude, angle, angleInDegrees); + cv::gpu::cartToPolar(d_src1, d_src2, d_magnitude, d_angle, angleInDegrees); TEST_CYCLE() { - cv::gpu::cartToPolar(src1, src2, magnitude, angle, angleInDegrees); + cv::gpu::cartToPolar(d_src1, d_src2, d_magnitude, d_angle, angleInDegrees); } } -INSTANTIATE_TEST_CASE_P(Core, CartToPolar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(false, true))); - ////////////////////////////////////////////////////////////////////// // PolarToCart -GPU_PERF_TEST(PolarToCart, cv::gpu::DeviceInfo, cv::Size, AngleInDegrees) +PERF_TEST_P(Sz_AngleInDegrees, Core_PolarToCart, Combine(GPU_TYPICAL_MAT_SIZES, Bool())) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + bool angleInDegrees = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - bool angleInDegrees = GET_PARAM(2); + cv::Mat magnitude(size, CV_32FC1); + fillRandom(magnitude, 0.0, 100.0); - cv::Mat magnitude_host(size, CV_32FC1); - fill(magnitude_host, 0.0, 100.0); + cv::Mat angle(size, CV_32FC1); + fillRandom(angle, 0.0, angleInDegrees ? 360.0 : 2 * CV_PI); - cv::Mat angle_host(size, CV_32FC1); - fill(angle_host, 0.0, angleInDegrees ? 360.0 : 2 * CV_PI); + cv::gpu::GpuMat d_magnitude(magnitude); + cv::gpu::GpuMat d_angle(angle); + cv::gpu::GpuMat d_x; + cv::gpu::GpuMat d_y; - cv::gpu::GpuMat magnitude(magnitude_host); - cv::gpu::GpuMat angle(angle_host); - cv::gpu::GpuMat x; - cv::gpu::GpuMat y; - - cv::gpu::polarToCart(magnitude, angle, x, y, angleInDegrees); + cv::gpu::polarToCart(d_magnitude, d_angle, d_x, d_y, angleInDegrees); TEST_CYCLE() { - cv::gpu::polarToCart(magnitude, angle, x, y, angleInDegrees); + cv::gpu::polarToCart(d_magnitude, d_angle, d_x, d_y, angleInDegrees); } } -INSTANTIATE_TEST_CASE_P(Core, PolarToCart, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(false, true))); - ////////////////////////////////////////////////////////////////////// // MeanStdDev -GPU_PERF_TEST(MeanStdDev, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, Core_MeanStdDev, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); + cv::Mat src(size, CV_8UC1); + fillRandom(src); - cv::Mat src_host(size, CV_8UC1); - fill(src_host, 0.0, 255.0); - - cv::gpu::GpuMat src(src_host); cv::Scalar mean; cv::Scalar stddev; - cv::gpu::GpuMat buf; - cv::gpu::meanStdDev(src, mean, stddev, buf); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + + cv::gpu::meanStdDev(d_src, mean, stddev, d_buf); TEST_CYCLE() { - cv::gpu::meanStdDev(src, mean, stddev, buf); + cv::gpu::meanStdDev(d_src, mean, stddev, d_buf); } } -INSTANTIATE_TEST_CASE_P(Core, MeanStdDev, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // Norm -GPU_PERF_TEST(Norm, cv::gpu::DeviceInfo, cv::Size, MatDepth, NormType) +DEF_PARAM_TEST(Sz_Depth_Norm, cv::Size, MatDepth, NormType); + +PERF_TEST_P(Sz_Depth_Norm, Core_Norm, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S, CV_32F), + Values(NormType(cv::NORM_INF), NormType(cv::NORM_L1), NormType(cv::NORM_L2)))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int normType = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int normType = GET_PARAM(3); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 255.0); - - cv::gpu::GpuMat src(src_host); double dst; - cv::gpu::GpuMat buf; - dst = cv::gpu::norm(src, normType, buf); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + + dst = cv::gpu::norm(d_src, normType, d_buf); TEST_CYCLE() { - dst = cv::gpu::norm(src, normType, buf); + dst = cv::gpu::norm(d_src, normType, d_buf); } } -INSTANTIATE_TEST_CASE_P(Core, Norm, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S, CV_32F), - testing::Values(NormType(cv::NORM_INF), NormType(cv::NORM_L1), NormType(cv::NORM_L2)))); - ////////////////////////////////////////////////////////////////////// // NormDiff -GPU_PERF_TEST(NormDiff, cv::gpu::DeviceInfo, cv::Size, NormType) +DEF_PARAM_TEST(Sz_Norm, cv::Size, NormType); + +PERF_TEST_P(Sz_Norm, Core_NormDiff, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(NormType(cv::NORM_INF), NormType(cv::NORM_L1), NormType(cv::NORM_L2)))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int normType = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int normType = GET_PARAM(2); + cv::Mat src1(size, CV_8UC1); + fillRandom(src1); - cv::Mat src1_host(size, CV_8UC1); - fill(src1_host, 0.0, 255.0); + cv::Mat src2(size, CV_8UC1); + fillRandom(src2); - cv::Mat src2_host(size, CV_8UC1); - fill(src2_host, 0.0, 255.0); - - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); double dst; - dst = cv::gpu::norm(src1, src2, normType); + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + + dst = cv::gpu::norm(d_src1, d_src2, normType); TEST_CYCLE() { - dst = cv::gpu::norm(src1, src2, normType); + dst = cv::gpu::norm(d_src1, d_src2, normType); } } -INSTANTIATE_TEST_CASE_P(Core, NormDiff, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(NormType(cv::NORM_INF), NormType(cv::NORM_L1), NormType(cv::NORM_L2)))); - ////////////////////////////////////////////////////////////////////// // Sum -GPU_PERF_TEST(Sum, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, Core_Sum, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); cv::Scalar dst; - cv::gpu::GpuMat buf; - dst = cv::gpu::sum(src, buf); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + + dst = cv::gpu::sum(d_src, d_buf); TEST_CYCLE() { - dst = cv::gpu::sum(src, buf); + dst = cv::gpu::sum(d_src, d_buf); } } -INSTANTIATE_TEST_CASE_P(Core, Sum, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16UC1, CV_16UC3, CV_16UC4, CV_32FC1, CV_32FC3, CV_32FC4))); - ////////////////////////////////////////////////////////////////////// -// Sum_Abs +// SumAbs -GPU_PERF_TEST(Sum_Abs, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, Core_SumAbs, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); cv::Scalar dst; - cv::gpu::GpuMat buf; - dst = cv::gpu::absSum(src, buf); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + + dst = cv::gpu::absSum(d_src, d_buf); TEST_CYCLE() { - dst = cv::gpu::absSum(src, buf); + dst = cv::gpu::absSum(d_src, d_buf); } } -INSTANTIATE_TEST_CASE_P(Core, Sum_Abs, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16UC1, CV_16UC3, CV_16UC4, CV_32FC1, CV_32FC3, CV_32FC4))); - ////////////////////////////////////////////////////////////////////// -// Sum_Sqr +// SumSqr -GPU_PERF_TEST(Sum_Sqr, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, Core_SumSqr, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); cv::Scalar dst; - cv::gpu::GpuMat buf; - dst = cv::gpu::sqrSum(src, buf); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + + dst = cv::gpu::sqrSum(d_src, d_buf); TEST_CYCLE() { - dst = cv::gpu::sqrSum(src, buf); + dst = cv::gpu::sqrSum(d_src, d_buf); } } -INSTANTIATE_TEST_CASE_P(Core, Sum_Sqr, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16UC1, CV_16UC3, CV_16UC4, CV_32FC1, CV_32FC3, CV_32FC4))); - ////////////////////////////////////////////////////////////////////// // MinMax -GPU_PERF_TEST(MinMax, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_MinMax, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 255.0); - - cv::gpu::GpuMat src(src_host); double minVal, maxVal; - cv::gpu::GpuMat buf; - cv::gpu::minMax(src, &minVal, &maxVal, cv::gpu::GpuMat(), buf); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + + cv::gpu::minMax(d_src, &minVal, &maxVal, cv::gpu::GpuMat(), d_buf); TEST_CYCLE() { - cv::gpu::minMax(src, &minVal, &maxVal, cv::gpu::GpuMat(), buf); + cv::gpu::minMax(d_src, &minVal, &maxVal, cv::gpu::GpuMat(), d_buf); } } -INSTANTIATE_TEST_CASE_P(Core, MinMax, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// // MinMaxLoc -GPU_PERF_TEST(MinMaxLoc, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_MinMaxLoc, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 255.0); - - cv::gpu::GpuMat src(src_host); double minVal, maxVal; cv::Point minLoc, maxLoc; - cv::gpu::GpuMat valbuf, locbuf; - cv::gpu::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc, cv::gpu::GpuMat(), valbuf, locbuf); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_valbuf, d_locbuf; + + cv::gpu::minMaxLoc(d_src, &minVal, &maxVal, &minLoc, &maxLoc, cv::gpu::GpuMat(), d_valbuf, d_locbuf); TEST_CYCLE() { - cv::gpu::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc, cv::gpu::GpuMat(), valbuf, locbuf); + cv::gpu::minMaxLoc(d_src, &minVal, &maxVal, &minLoc, &maxLoc, cv::gpu::GpuMat(), d_valbuf, d_locbuf); } } -INSTANTIATE_TEST_CASE_P(Core, MinMaxLoc, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// // CountNonZero -GPU_PERF_TEST(CountNonZero, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, Core_CountNonZero, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0.0, 1.5); - - cv::gpu::GpuMat src(src_host); int dst; - cv::gpu::GpuMat buf; - dst = cv::gpu::countNonZero(src, buf); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + + dst = cv::gpu::countNonZero(d_src, d_buf); TEST_CYCLE() { - dst = cv::gpu::countNonZero(src, buf); + dst = cv::gpu::countNonZero(d_src, d_buf); } } -INSTANTIATE_TEST_CASE_P(Core, CountNonZero, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - ////////////////////////////////////////////////////////////////////// // Reduce CV_ENUM(ReduceCode, CV_REDUCE_SUM, CV_REDUCE_AVG, CV_REDUCE_MAX, CV_REDUCE_MIN) -#define ALL_REDUCE_CODES testing::Values(CV_REDUCE_SUM, CV_REDUCE_AVG, CV_REDUCE_MAX, CV_REDUCE_MIN) +#define ALL_REDUCE_CODES ValuesIn(ReduceCode::all()) enum {Rows = 0, Cols = 1}; CV_ENUM(ReduceDim, Rows, Cols) +#define ALL_REDUCE_DIMS ValuesIn(ReduceDim::all()) -GPU_PERF_TEST(Reduce, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels, ReduceCode, ReduceDim) +DEF_PARAM_TEST(Sz_Depth_Cn_Code_Dim, cv::Size, MatDepth, int, ReduceCode, ReduceDim); + +PERF_TEST_P(Sz_Depth_Cn_Code_Dim, Core_Reduce, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_16S, CV_32F), + Values(1, 2, 3, 4), + ALL_REDUCE_CODES, + ALL_REDUCE_DIMS)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); - int reduceOp = GET_PARAM(4); - int dim = GET_PARAM(5); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); + int reduceOp = GET_PARAM(3); + int dim = GET_PARAM(4); int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 10.0); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::reduce(src, dst, dim, reduceOp); + cv::gpu::reduce(d_src, d_dst, dim, reduceOp); TEST_CYCLE() { - cv::gpu::reduce(src, dst, dim, reduceOp); + cv::gpu::reduce(d_src, d_dst, dim, reduceOp); } } -INSTANTIATE_TEST_CASE_P(Core, Reduce, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_16S, CV_32F), - testing::Values(1, 2, 3, 4), - ALL_REDUCE_CODES, - testing::Values(ReduceDim(Rows), ReduceDim(Cols)))); - -#endif +} // namespace diff --git a/modules/gpu/perf/perf_features2d.cpp b/modules/gpu/perf/perf_features2d.cpp index 8a81860176..ef9612b549 100644 --- a/modules/gpu/perf/perf_features2d.cpp +++ b/modules/gpu/perf/perf_features2d.cpp @@ -1,209 +1,179 @@ #include "perf_precomp.hpp" -#ifdef HAVE_CUDA +using namespace std; +using namespace testing; + +namespace { ////////////////////////////////////////////////////////////////////// // SURF -GPU_PERF_TEST_1(SURF, cv::gpu::DeviceInfo) +DEF_PARAM_TEST_1(Image, string); + +PERF_TEST_P(Image, Features2D_SURF, Values("gpu/perf/aloe.jpg")) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Mat img_host = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_host.empty()); - - cv::gpu::SURF_GPU surf; - - cv::gpu::GpuMat img(img_host); - cv::gpu::GpuMat keypoints, descriptors; - - surf(img, cv::gpu::GpuMat(), keypoints, descriptors); - declare.time(2.0); + cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(img.empty()); + + cv::gpu::SURF_GPU d_surf; + + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_keypoints, d_descriptors; + + d_surf(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); + TEST_CYCLE() { - surf(img, cv::gpu::GpuMat(), keypoints, descriptors); + d_surf(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); } } -INSTANTIATE_TEST_CASE_P(Features2D, SURF, ALL_DEVICES); - ////////////////////////////////////////////////////////////////////// // FAST -GPU_PERF_TEST_1(FAST, cv::gpu::DeviceInfo) +PERF_TEST_P(Image, Features2D_FAST, Values("gpu/perf/aloe.jpg")) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(img.empty()); - cv::Mat img_host = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_host.empty()); + cv::gpu::FAST_GPU d_fast(20); - cv::gpu::FAST_GPU fast(20); + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_keypoints; - cv::gpu::GpuMat img(img_host); - cv::gpu::GpuMat keypoints; - - fast(img, cv::gpu::GpuMat(), keypoints); + d_fast(d_img, cv::gpu::GpuMat(), d_keypoints); TEST_CYCLE() { - fast(img, cv::gpu::GpuMat(), keypoints); + d_fast(d_img, cv::gpu::GpuMat(), d_keypoints); } } -INSTANTIATE_TEST_CASE_P(Features2D, FAST, ALL_DEVICES); - ////////////////////////////////////////////////////////////////////// // ORB -GPU_PERF_TEST_1(ORB, cv::gpu::DeviceInfo) +PERF_TEST_P(Image, Features2D_ORB, Values("gpu/perf/aloe.jpg")) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(img.empty()); - cv::Mat img_host = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_host.empty()); + cv::gpu::ORB_GPU d_orb(4000); - cv::gpu::ORB_GPU orb(4000); + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_keypoints, d_descriptors; - cv::gpu::GpuMat img(img_host); - cv::gpu::GpuMat keypoints, descriptors; + d_orb(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); TEST_CYCLE() { - orb(img, cv::gpu::GpuMat(), keypoints, descriptors); + d_orb(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); } } -INSTANTIATE_TEST_CASE_P(Features2D, ORB, ALL_DEVICES); +////////////////////////////////////////////////////////////////////// +// BFMatch + +DEF_PARAM_TEST(DescSize_Norm, int, NormType); + +PERF_TEST_P(DescSize_Norm, Features2D_BFMatch, Combine(Values(64, 128, 256), Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))) +{ + declare.time(3.0); + + int desc_size = GET_PARAM(0); + int normType = GET_PARAM(1); + + int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; + + cv::Mat query(3000, desc_size, type); + fillRandom(query); + + cv::Mat train(3000, desc_size, type); + fillRandom(train); + + cv::gpu::BFMatcher_GPU d_matcher(normType); + + cv::gpu::GpuMat d_query(query); + cv::gpu::GpuMat d_train(train); + cv::gpu::GpuMat d_trainIdx, d_distance; + + d_matcher.matchSingle(d_query, d_train, d_trainIdx, d_distance); + + TEST_CYCLE() + { + d_matcher.matchSingle(d_query, d_train, d_trainIdx, d_distance); + } +} ////////////////////////////////////////////////////////////////////// -// BruteForceMatcher_match +// BFKnnMatch -IMPLEMENT_PARAM_CLASS(DescriptorSize, int) +DEF_PARAM_TEST(DescSize_K_Norm, int, int, NormType); -GPU_PERF_TEST(BruteForceMatcher_match, cv::gpu::DeviceInfo, DescriptorSize, NormType) +PERF_TEST_P(DescSize_K_Norm, Features2D_BFKnnMatch, Combine( + Values(64, 128, 256), + Values(2, 3), + Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + declare.time(3.0); - int desc_size = GET_PARAM(1); + int desc_size = GET_PARAM(0); + int k = GET_PARAM(1); int normType = GET_PARAM(2); int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; - cv::Mat query_host(3000, desc_size, type); - fill(query_host, 0.0, 10.0); + cv::Mat query(3000, desc_size, type); + fillRandom(query); - cv::Mat train_host(3000, desc_size, type); - fill(train_host, 0.0, 10.0); + cv::Mat train(3000, desc_size, type); + fillRandom(train); - cv::gpu::BFMatcher_GPU matcher(normType); + cv::gpu::BFMatcher_GPU d_matcher(normType); - cv::gpu::GpuMat query(query_host); - cv::gpu::GpuMat train(train_host); - cv::gpu::GpuMat trainIdx, distance; + cv::gpu::GpuMat d_query(query); + cv::gpu::GpuMat d_train(train); + cv::gpu::GpuMat d_trainIdx, d_distance, d_allDist; - matcher.matchSingle(query, train, trainIdx, distance); - - declare.time(3.0); + d_matcher.knnMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_allDist, k); TEST_CYCLE() { - matcher.matchSingle(query, train, trainIdx, distance); + d_matcher.knnMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_allDist, k); } } -INSTANTIATE_TEST_CASE_P(Features2D, BruteForceMatcher_match, testing::Combine( - ALL_DEVICES, - testing::Values(DescriptorSize(64), DescriptorSize(128), DescriptorSize(256)), - testing::Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))); - ////////////////////////////////////////////////////////////////////// -// BruteForceMatcher_knnMatch +// BFRadiusMatch -IMPLEMENT_PARAM_CLASS(K, int) - -GPU_PERF_TEST(BruteForceMatcher_knnMatch, cv::gpu::DeviceInfo, DescriptorSize, K, NormType) +PERF_TEST_P(DescSize_Norm, Features2D_BFRadiusMatch, Combine(Values(64, 128, 256), Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + declare.time(3.0); - int desc_size = GET_PARAM(1); - int k = GET_PARAM(2); - int normType = GET_PARAM(3); + int desc_size = GET_PARAM(0); + int normType = GET_PARAM(1); int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; - cv::Mat query_host(3000, desc_size, type); - fill(query_host, 0.0, 10.0); + cv::Mat query(3000, desc_size, type); + fillRandom(query, 0.0, 1.0); - cv::Mat train_host(3000, desc_size, type); - fill(train_host, 0.0, 10.0); + cv::Mat train(3000, desc_size, type); + fillRandom(train, 0.0, 1.0); - cv::gpu::BFMatcher_GPU matcher(normType); + cv::gpu::BFMatcher_GPU d_matcher(normType); - cv::gpu::GpuMat query(query_host); - cv::gpu::GpuMat train(train_host); - cv::gpu::GpuMat trainIdx, distance, allDist; + cv::gpu::GpuMat d_query(query); + cv::gpu::GpuMat d_train(train); + cv::gpu::GpuMat d_trainIdx, d_nMatches, d_distance; - matcher.knnMatchSingle(query, train, trainIdx, distance, allDist, k); - - declare.time(3.0); + d_matcher.radiusMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_nMatches, 2.0); TEST_CYCLE() { - matcher.knnMatchSingle(query, train, trainIdx, distance, allDist, k); + d_matcher.radiusMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_nMatches, 2.0); } } -INSTANTIATE_TEST_CASE_P(Features2D, BruteForceMatcher_knnMatch, testing::Combine( - ALL_DEVICES, - testing::Values(DescriptorSize(64), DescriptorSize(128), DescriptorSize(256)), - testing::Values(K(2), K(3)), - testing::Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))); - -////////////////////////////////////////////////////////////////////// -// BruteForceMatcher_radiusMatch - -GPU_PERF_TEST(BruteForceMatcher_radiusMatch, cv::gpu::DeviceInfo, DescriptorSize, NormType) -{ - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - int desc_size = GET_PARAM(1); - int normType = GET_PARAM(2); - - int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; - - cv::Mat query_host(3000, desc_size, type); - fill(query_host, 0.0, 1.0); - - cv::Mat train_host(3000, desc_size, type); - fill(train_host, 0.0, 1.0); - - cv::gpu::BFMatcher_GPU matcher(normType); - - cv::gpu::GpuMat query(query_host); - cv::gpu::GpuMat train(train_host); - cv::gpu::GpuMat trainIdx, nMatches, distance; - - matcher.radiusMatchSingle(query, train, trainIdx, distance, nMatches, 2.0); - - declare.time(3.0); - - TEST_CYCLE() - { - matcher.radiusMatchSingle(query, train, trainIdx, distance, nMatches, 2.0); - } -} - -INSTANTIATE_TEST_CASE_P(Features2D, BruteForceMatcher_radiusMatch, testing::Combine( - ALL_DEVICES, - testing::Values(DescriptorSize(64), DescriptorSize(128), DescriptorSize(256)), - testing::Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))); - -#endif +} // namespace diff --git a/modules/gpu/perf/perf_filters.cpp b/modules/gpu/perf/perf_filters.cpp index 0263e8063f..71dcd49e2b 100644 --- a/modules/gpu/perf/perf_filters.cpp +++ b/modules/gpu/perf/perf_filters.cpp @@ -1,308 +1,235 @@ #include "perf_precomp.hpp" -#ifdef HAVE_CUDA +using namespace std; +using namespace testing; + +namespace { ////////////////////////////////////////////////////////////////////// // Blur -IMPLEMENT_PARAM_CLASS(KernelSize, int) +DEF_PARAM_TEST(Sz_Type_KernelSz, cv::Size, MatType, int); -GPU_PERF_TEST(Blur, cv::gpu::DeviceInfo, cv::Size, MatType, KernelSize) +PERF_TEST_P(Sz_Type_KernelSz, Filters_Blur, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4), Values(3, 5, 7))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); + int ksize = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int ksize = GET_PARAM(3); + cv::Mat src(size, type); + fillRandom(src); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::blur(src, dst, cv::Size(ksize, ksize)); + cv::gpu::blur(d_src, d_dst, cv::Size(ksize, ksize)); TEST_CYCLE() { - cv::gpu::blur(src, dst, cv::Size(ksize, ksize)); + cv::gpu::blur(d_src, d_dst, cv::Size(ksize, ksize)); } } -INSTANTIATE_TEST_CASE_P(Filters, Blur, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)), - testing::Values(KernelSize(3), KernelSize(5), KernelSize(7)))); - ////////////////////////////////////////////////////////////////////// // Sobel -GPU_PERF_TEST(Sobel, cv::gpu::DeviceInfo, cv::Size, MatType, KernelSize) +PERF_TEST_P(Sz_Type_KernelSz, Filters_Sobel, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4, CV_32FC1), Values(3, 5, 7, 9, 11, 13, 15))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); + int ksize = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int ksize = GET_PARAM(3); + cv::Mat src(size, type); + fillRandom(src); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - cv::gpu::GpuMat buf; - - cv::gpu::Sobel(src, dst, -1, 1, 1, buf, ksize); + cv::gpu::Sobel(d_src, d_dst, -1, 1, 1, d_buf, ksize); TEST_CYCLE() { - cv::gpu::Sobel(src, dst, -1, 1, 1, buf, ksize); + cv::gpu::Sobel(d_src, d_dst, -1, 1, 1, d_buf, ksize); } } -INSTANTIATE_TEST_CASE_P(Filters, Sobel, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1)), - testing::Values(KernelSize(3), KernelSize(5), KernelSize(7), KernelSize(9), KernelSize(11), KernelSize(13), KernelSize(15)))); - ////////////////////////////////////////////////////////////////////// // Scharr -GPU_PERF_TEST(Scharr, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Type, Filters_Scharr, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4, CV_32FC1))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + cv::Mat src(size, type); + fillRandom(src); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - cv::gpu::GpuMat buf; - - cv::gpu::Scharr(src, dst, -1, 1, 0, buf); + cv::gpu::Scharr(d_src, d_dst, -1, 1, 0, d_buf); TEST_CYCLE() { - cv::gpu::Scharr(src, dst, -1, 1, 0, buf); + cv::gpu::Scharr(d_src, d_dst, -1, 1, 0, d_buf); } } -INSTANTIATE_TEST_CASE_P(Filters, Scharr, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1)))); - ////////////////////////////////////////////////////////////////////// // GaussianBlur -GPU_PERF_TEST(GaussianBlur, cv::gpu::DeviceInfo, cv::Size, MatType, KernelSize) +PERF_TEST_P(Sz_Type_KernelSz, Filters_GaussianBlur, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4, CV_32FC1), Values(3, 5, 7, 9, 11, 13, 15))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); + int ksize = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int ksize = GET_PARAM(3); + cv::Mat src(size, type); + fillRandom(src); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - cv::gpu::GpuMat buf; - - cv::gpu::GaussianBlur(src, dst, cv::Size(ksize, ksize), buf, 0.5); + cv::gpu::GaussianBlur(d_src, d_dst, cv::Size(ksize, ksize), d_buf, 0.5); TEST_CYCLE() { - cv::gpu::GaussianBlur(src, dst, cv::Size(ksize, ksize), buf, 0.5); + cv::gpu::GaussianBlur(d_src, d_dst, cv::Size(ksize, ksize), d_buf, 0.5); } } -INSTANTIATE_TEST_CASE_P(Filters, GaussianBlur, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1)), - testing::Values(KernelSize(3), KernelSize(5), KernelSize(7), KernelSize(9), KernelSize(11), KernelSize(13), KernelSize(15)))); - ////////////////////////////////////////////////////////////////////// // Laplacian -GPU_PERF_TEST(Laplacian, cv::gpu::DeviceInfo, cv::Size, MatType, KernelSize) +PERF_TEST_P(Sz_Type_KernelSz, Filters_Laplacian, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4), Values(1, 3))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); + int ksize = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int ksize = GET_PARAM(3); + cv::Mat src(size, type); + fillRandom(src); - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::Laplacian(src, dst, -1, ksize); + cv::gpu::Laplacian(d_src, d_dst, -1, ksize); TEST_CYCLE() { - cv::gpu::Laplacian(src, dst, -1, ksize); + cv::gpu::Laplacian(d_src, d_dst, -1, ksize); } } -INSTANTIATE_TEST_CASE_P(Filters, Laplacian, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1), MatType(CV_32FC4)), - testing::Values(KernelSize(1), KernelSize(3)))); - ////////////////////////////////////////////////////////////////////// // Erode -GPU_PERF_TEST(Erode, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Type, Filters_Erode, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::Mat src(size, type); + fillRandom(src); cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - cv::gpu::GpuMat buf; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; - cv::gpu::erode(src, dst, ker, buf); + cv::gpu::erode(d_src, d_dst, ker, d_buf); TEST_CYCLE() { - cv::gpu::erode(src, dst, ker, buf); + cv::gpu::erode(d_src, d_dst, ker, d_buf); } } -INSTANTIATE_TEST_CASE_P(Filters, Erode, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)))); - ////////////////////////////////////////////////////////////////////// // Dilate -GPU_PERF_TEST(Dilate, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Type, Filters_Dilate, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::Mat src(size, type); + fillRandom(src); cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - cv::gpu::GpuMat buf; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; - cv::gpu::dilate(src, dst, ker, buf); + cv::gpu::dilate(d_src, d_dst, ker, d_buf); TEST_CYCLE() { - cv::gpu::dilate(src, dst, ker, buf); + cv::gpu::dilate(d_src, d_dst, ker, d_buf); } } -INSTANTIATE_TEST_CASE_P(Filters, Dilate, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)))); - ////////////////////////////////////////////////////////////////////// // MorphologyEx CV_ENUM(MorphOp, cv::MORPH_OPEN, cv::MORPH_CLOSE, cv::MORPH_GRADIENT, cv::MORPH_TOPHAT, cv::MORPH_BLACKHAT) -#define ALL_MORPH_OPS testing::Values(MorphOp(cv::MORPH_OPEN), MorphOp(cv::MORPH_CLOSE), MorphOp(cv::MORPH_GRADIENT), MorphOp(cv::MORPH_TOPHAT), MorphOp(cv::MORPH_BLACKHAT)) +#define ALL_MORPH_OPS ValuesIn(MorphOp::all()) -GPU_PERF_TEST(MorphologyEx, cv::gpu::DeviceInfo, cv::Size, MatType, MorphOp) +DEF_PARAM_TEST(Sz_Type_Op, cv::Size, MatType, MorphOp); + +PERF_TEST_P(Sz_Type_Op, Filters_MorphologyEx, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4), ALL_MORPH_OPS)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); + int morphOp = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int morphOp = GET_PARAM(3); - - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::Mat src(size, type); + fillRandom(src); cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - cv::gpu::GpuMat buf1; - cv::gpu::GpuMat buf2; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf1; + cv::gpu::GpuMat d_buf2; - cv::gpu::morphologyEx(src, dst, morphOp, ker, buf1, buf2); + cv::gpu::morphologyEx(d_src, d_dst, morphOp, ker, d_buf1, d_buf2); TEST_CYCLE() { - cv::gpu::morphologyEx(src, dst, morphOp, ker, buf1, buf2); + cv::gpu::morphologyEx(d_src, d_dst, morphOp, ker, d_buf1, d_buf2); } } -INSTANTIATE_TEST_CASE_P(Filters, MorphologyEx, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)), - ALL_MORPH_OPS)); - ////////////////////////////////////////////////////////////////////// // Filter2D -GPU_PERF_TEST(Filter2D, cv::gpu::DeviceInfo, cv::Size, MatType, KernelSize) +PERF_TEST_P(Sz_Type_KernelSz, Filters_Filter2D, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4), Values(3, 5, 7, 9, 11, 13, 15))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); + int ksize = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int ksize = GET_PARAM(3); - - cv::Mat src_host(size, type); - fill(src_host, 0.0, 255.0); + cv::Mat src(size, type); + fillRandom(src); cv::Mat kernel(ksize, ksize, CV_32FC1); - fill(kernel, 0.0, 1.0); + fillRandom(kernel, 0.0, 1.0); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::filter2D(src, dst, -1, kernel); + cv::gpu::filter2D(d_src, d_dst, -1, kernel); TEST_CYCLE() { - cv::gpu::filter2D(src, dst, -1, kernel); + cv::gpu::filter2D(d_src, d_dst, -1, kernel); } } -INSTANTIATE_TEST_CASE_P(Filters, Filter2D, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1), MatType(CV_32FC4)), - testing::Values(KernelSize(3), KernelSize(5), KernelSize(7), KernelSize(9), KernelSize(11), KernelSize(13), KernelSize(15)))); - -#endif +} // namespace diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index 0dbcd34c65..a1614a79f3 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -1,188 +1,226 @@ #include "perf_precomp.hpp" -#ifdef HAVE_CUDA +using namespace std; +using namespace testing; + +namespace { ////////////////////////////////////////////////////////////////////// // Remap -GPU_PERF_TEST(Remap, cv::gpu::DeviceInfo, cv::Size, MatType, Interpolation, BorderMode) +enum{HALF_SIZE=0, UPSIDE_DOWN, REFLECTION_X, REFLECTION_BOTH}; +CV_ENUM(RemapMode, HALF_SIZE, UPSIDE_DOWN, REFLECTION_X, REFLECTION_BOTH); +#define ALL_REMAP_MODES ValuesIn(RemapMode::all()) + +void generateMap(cv::Mat& map_x, cv::Mat& map_y, int remapMode) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int interpolation = GET_PARAM(3); - int borderMode = GET_PARAM(4); - - cv::Mat src_host(size, type); - fill(src_host, 0, 255); - - cv::Mat xmap_host(size, CV_32FC1); - fill(xmap_host, 0, size.width); - - cv::Mat ymap_host(size, CV_32FC1); - fill(ymap_host, 0, size.height); - - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat xmap(xmap_host); - cv::gpu::GpuMat ymap(ymap_host); - cv::gpu::GpuMat dst; - - cv::gpu::remap(src, dst, xmap, ymap, interpolation, borderMode); - - declare.time(3.0); - - TEST_CYCLE() + for (int j = 0; j < map_x.rows; ++j) { - cv::gpu::remap(src, dst, xmap, ymap, interpolation, borderMode); + for (int i = 0; i < map_x.cols; ++i) + { + switch (remapMode) + { + case HALF_SIZE: + if (i > map_x.cols*0.25 && i < map_x.cols*0.75 && j > map_x.rows*0.25 && j < map_x.rows*0.75) + { + map_x.at(j,i) = 2 * (i - map_x.cols * 0.25) + 0.5; + map_y.at(j,i) = 2 * (j - map_x.rows * 0.25) + 0.5; + } + else + { + map_x.at(j,i) = 0; + map_y.at(j,i) = 0; + } + break; + case UPSIDE_DOWN: + map_x.at(j,i) = i; + map_y.at(j,i) = map_x.rows - j; + break; + case REFLECTION_X: + map_x.at(j,i) = map_x.cols - i; + map_y.at(j,i) = j; + break; + case REFLECTION_BOTH: + map_x.at(j,i) = map_x.cols - i; + map_y.at(j,i) = map_x.rows - j; + break; + } // end of switch + } } } -INSTANTIATE_TEST_CASE_P(ImgProc, Remap, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_CONSTANT), BorderMode(cv::BORDER_REFLECT), BorderMode(cv::BORDER_WRAP)))); +DEF_PARAM_TEST(Sz_Depth_Cn_Inter_Border_Mode, cv::Size, MatDepth, int, Interpolation, BorderMode, RemapMode); +PERF_TEST_P(Sz_Depth_Cn_Inter_Border_Mode, ImgProc_Remap, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4), + Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), + ALL_BORDER_MODES, + ALL_REMAP_MODES)) +{ + declare.time(3.0); + + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); + int interpolation = GET_PARAM(3); + int borderMode = GET_PARAM(4); + int remapMode = GET_PARAM(5); + + int type = CV_MAKE_TYPE(depth, channels); + + cv::Mat src(size, type); + fillRandom(src); + + cv::Mat xmap(size, CV_32FC1); + cv::Mat ymap(size, CV_32FC1); + + generateMap(xmap, ymap, remapMode); + + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_xmap(xmap); + cv::gpu::GpuMat d_ymap(ymap); + cv::gpu::GpuMat d_dst; + + cv::gpu::remap(d_src, d_dst, d_xmap, d_ymap, interpolation, borderMode); + + TEST_CYCLE() + { + cv::gpu::remap(d_src, d_dst, d_xmap, d_ymap, interpolation, borderMode); + } +} ////////////////////////////////////////////////////////////////////// // Resize -IMPLEMENT_PARAM_CLASS(Scale, double) +DEF_PARAM_TEST(Sz_Depth_Cn_Inter_Scale, cv::Size, MatDepth, int, Interpolation, double); -GPU_PERF_TEST(Resize, cv::gpu::DeviceInfo, cv::Size, MatType, Interpolation, Scale) +PERF_TEST_P(Sz_Depth_Cn_Inter_Scale, ImgProc_Resize, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4), + ALL_INTERPOLATIONS, + Values(0.5, 0.3, 2.0))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + declare.time(1.0); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int interpolation = GET_PARAM(3); double f = GET_PARAM(4); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + int type = CV_MAKE_TYPE(depth, channels); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::resize(src, dst, cv::Size(), f, f, interpolation); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - declare.time(1.0); + cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); TEST_CYCLE() { - cv::gpu::resize(src, dst, cv::Size(), f, f, interpolation); + cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); } } -INSTANTIATE_TEST_CASE_P(ImgProc, Resize, testing::Combine( - ALL_DEVICES, +////////////////////////////////////////////////////////////////////// +// ResizeArea + +DEF_PARAM_TEST(Sz_Depth_Cn_Scale, cv::Size, MatDepth, int, double); + +PERF_TEST_P(Sz_Depth_Cn_Scale, ImgProc_ResizeArea, Combine( GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), - Interpolation(cv::INTER_CUBIC), Interpolation(cv::INTER_AREA)), - testing::Values(Scale(0.5), Scale(0.3), Scale(2.0)))); - -GPU_PERF_TEST(ResizeArea, cv::gpu::DeviceInfo, cv::Size, MatType, Scale) + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4), + Values(0.2, 0.1, 0.05))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + declare.time(1.0); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int interpolation = cv::INTER_AREA; double f = GET_PARAM(3); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + int type = CV_MAKE_TYPE(depth, channels); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::resize(src, dst, cv::Size(), f, f, interpolation); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - declare.time(1.0); + cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); TEST_CYCLE() { - cv::gpu::resize(src, dst, cv::Size(), f, f, interpolation); + cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); } } -INSTANTIATE_TEST_CASE_P(ImgProc, ResizeArea, testing::Combine( - ALL_DEVICES, - testing::Values(perf::sz1080p/*, cv::Size(4096, 2048)*/), - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(Scale(0.2),Scale(0.1),Scale(0.05)))); - ////////////////////////////////////////////////////////////////////// // WarpAffine -GPU_PERF_TEST(WarpAffine, cv::gpu::DeviceInfo, cv::Size, MatType, Interpolation, BorderMode) -{ - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); +DEF_PARAM_TEST(Sz_Depth_Cn_Inter_Border, cv::Size, MatDepth, int, Interpolation, BorderMode); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); +PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpAffine, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4), + Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), + ALL_BORDER_MODES)) +{ + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int interpolation = GET_PARAM(3); int borderMode = GET_PARAM(4); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + int type = CV_MAKE_TYPE(depth, channels); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::Mat src(size, type); + fillRandom(src); const double aplha = CV_PI / 4; double mat[2][3] = { {std::cos(aplha), -std::sin(aplha), src.cols / 2}, {std::sin(aplha), std::cos(aplha), 0}}; cv::Mat M(2, 3, CV_64F, (void*) mat); - cv::gpu::warpAffine(src, dst, M, size, interpolation, borderMode); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::warpAffine(d_src, d_dst, M, size, interpolation, borderMode); TEST_CYCLE() { - cv::gpu::warpAffine(src, dst, M, size, interpolation, borderMode); + cv::gpu::warpAffine(d_src, d_dst, M, size, interpolation, borderMode); } } -INSTANTIATE_TEST_CASE_P(ImgProc, WarpAffine, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_CONSTANT), BorderMode(cv::BORDER_REFLECT), BorderMode(cv::BORDER_WRAP)))); - ////////////////////////////////////////////////////////////////////// // WarpPerspective -GPU_PERF_TEST(WarpPerspective, cv::gpu::DeviceInfo, cv::Size, MatType, Interpolation, BorderMode) +PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpPerspective, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4), + Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), + ALL_BORDER_MODES)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int interpolation = GET_PARAM(3); int borderMode = GET_PARAM(4); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + int type = CV_MAKE_TYPE(depth, channels); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::Mat src(size, type); + fillRandom(src); const double aplha = CV_PI / 4; double mat[3][3] = { {std::cos(aplha), -std::sin(aplha), src.cols / 2}, @@ -190,1160 +228,958 @@ GPU_PERF_TEST(WarpPerspective, cv::gpu::DeviceInfo, cv::Size, MatType, Interpola {0.0, 0.0, 1.0}}; cv::Mat M(3, 3, CV_64F, (void*) mat); - cv::gpu::warpPerspective(src, dst, M, size, interpolation, borderMode); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::warpPerspective(d_src, d_dst, M, size, interpolation, borderMode); TEST_CYCLE() { - cv::gpu::warpPerspective(src, dst, M, size, interpolation, borderMode); + cv::gpu::warpPerspective(d_src, d_dst, M, size, interpolation, borderMode); } } -INSTANTIATE_TEST_CASE_P(ImgProc, WarpPerspective, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_CONSTANT), BorderMode(cv::BORDER_REFLECT), BorderMode(cv::BORDER_WRAP)))); - ////////////////////////////////////////////////////////////////////// // CopyMakeBorder -GPU_PERF_TEST(CopyMakeBorder, cv::gpu::DeviceInfo, cv::Size, MatType, BorderMode) +DEF_PARAM_TEST(Sz_Depth_Cn_Border, cv::Size, MatDepth, int, BorderMode); + +PERF_TEST_P(Sz_Depth_Cn_Border, ImgProc_CopyMakeBorder, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4), + ALL_BORDER_MODES)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); + int borderMode = GET_PARAM(3); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int borderType = GET_PARAM(3); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::copyMakeBorder(src, dst, 5, 5, 5, 5, borderType); + cv::gpu::copyMakeBorder(d_src, d_dst, 5, 5, 5, 5, borderMode); TEST_CYCLE() { - cv::gpu::copyMakeBorder(src, dst, 5, 5, 5, 5, borderType); + cv::gpu::copyMakeBorder(d_src, d_dst, 5, 5, 5, 5, borderMode); } } -INSTANTIATE_TEST_CASE_P(ImgProc, CopyMakeBorder, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_CONSTANT), BorderMode(cv::BORDER_REFLECT), BorderMode(cv::BORDER_WRAP)))); - ////////////////////////////////////////////////////////////////////// // Threshold CV_ENUM(ThreshOp, cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC, cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV) -#define ALL_THRESH_OPS testing::Values(ThreshOp(cv::THRESH_BINARY), ThreshOp(cv::THRESH_BINARY_INV), ThreshOp(cv::THRESH_TRUNC), ThreshOp(cv::THRESH_TOZERO), ThreshOp(cv::THRESH_TOZERO_INV)) +#define ALL_THRESH_OPS ValuesIn(ThreshOp::all()) -GPU_PERF_TEST(Threshold, cv::gpu::DeviceInfo, cv::Size, MatDepth, ThreshOp) +DEF_PARAM_TEST(Sz_Depth_Op, cv::Size, MatDepth, ThreshOp); + +PERF_TEST_P(Sz_Depth_Op, ImgProc_Threshold, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F), + ALL_THRESH_OPS)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int threshOp = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int threshOp = GET_PARAM(3); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0, 255); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::threshold(src, dst, 100.0, 255.0, threshOp); + cv::gpu::threshold(d_src, d_dst, 100.0, 255.0, threshOp); TEST_CYCLE() { - cv::gpu::threshold(src, dst, 100.0, 255.0, threshOp); + cv::gpu::threshold(d_src, d_dst, 100.0, 255.0, threshOp); } } -INSTANTIATE_TEST_CASE_P(ImgProc, Threshold, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_32F), MatDepth(CV_64F)), - ALL_THRESH_OPS)); - ////////////////////////////////////////////////////////////////////// // Integral -GPU_PERF_TEST(Integral, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, ImgProc_Integral, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); + cv::Mat src(size, CV_8UC1); + fillRandom(src); - cv::Mat src_host(size, CV_8UC1); - fill(src_host, 0, 255); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - cv::gpu::GpuMat buf; - - cv::gpu::integralBuffered(src, dst, buf); + cv::gpu::integralBuffered(d_src, d_dst, d_buf); TEST_CYCLE() { - cv::gpu::integralBuffered(src, dst, buf); + cv::gpu::integralBuffered(d_src, d_dst, d_buf); } } -INSTANTIATE_TEST_CASE_P(ImgProc, Integral, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// -// Integral_Sqr +// IntegralSqr -GPU_PERF_TEST(Integral_Sqr, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, ImgProc_IntegralSqr, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); + cv::Mat src(size, CV_8UC1); + fillRandom(src); - cv::Mat src_host(size, CV_8UC1); - fill(src_host, 0, 255); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::sqrIntegral(src, dst); + cv::gpu::sqrIntegral(d_src, d_dst); TEST_CYCLE() { - cv::gpu::sqrIntegral(src, dst); + cv::gpu::sqrIntegral(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(ImgProc, Integral_Sqr, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// -// HistEven_OneChannel +// HistEvenC1 -GPU_PERF_TEST(HistEven_OneChannel, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, ImgProc_HistEvenC1, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_16S))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, depth); + fillRandom(src); - cv::Mat src_host(size, depth); - fill(src_host, 0, 255); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_hist; + cv::gpu::GpuMat d_buf; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat hist; - cv::gpu::GpuMat buf; - - cv::gpu::histEven(src, hist, buf, 30, 0, 180); + cv::gpu::histEven(d_src, d_hist, d_buf, 30, 0, 180); TEST_CYCLE() { - cv::gpu::histEven(src, hist, buf, 30, 0, 180); + cv::gpu::histEven(d_src, d_hist, d_buf, 30, 0, 180); } } -INSTANTIATE_TEST_CASE_P(ImgProc, HistEven_OneChannel, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_16S)))); - ////////////////////////////////////////////////////////////////////// -// HistEven_FourChannel +// HistEvenC4 -GPU_PERF_TEST(HistEven_FourChannel, cv::gpu::DeviceInfo, cv::Size, MatDepth) +PERF_TEST_P(Sz_Depth, ImgProc_HistEvenC4, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_16S))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); + cv::Mat src(size, CV_MAKE_TYPE(depth, 4)); + fillRandom(src); - cv::Mat src_host(size, CV_MAKE_TYPE(depth, 4)); - fill(src_host, 0, 255); - - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat hist[4]; - cv::gpu::GpuMat buf; int histSize[] = {30, 30, 30, 30}; int lowerLevel[] = {0, 0, 0, 0}; int upperLevel[] = {180, 180, 180, 180}; - cv::gpu::histEven(src, hist, buf, histSize, lowerLevel, upperLevel); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_hist[4]; + cv::gpu::GpuMat d_buf; + + cv::gpu::histEven(d_src, d_hist, d_buf, histSize, lowerLevel, upperLevel); TEST_CYCLE() { - cv::gpu::histEven(src, hist, buf, histSize, lowerLevel, upperLevel); + cv::gpu::histEven(d_src, d_hist, d_buf, histSize, lowerLevel, upperLevel); } } -INSTANTIATE_TEST_CASE_P(ImgProc, HistEven_FourChannel, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_16S)))); - ////////////////////////////////////////////////////////////////////// // CalcHist -GPU_PERF_TEST(CalcHist, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, ImgProc_CalcHist, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); + cv::Mat src(size, CV_8UC1); + fillRandom(src); - cv::Mat src_host(size, CV_8UC1); - fill(src_host, 0, 255); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_hist; + cv::gpu::GpuMat d_buf; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat hist; - cv::gpu::GpuMat buf; - - cv::gpu::calcHist(src, hist, buf); + cv::gpu::calcHist(d_src, d_hist, d_buf); TEST_CYCLE() { - cv::gpu::calcHist(src, hist, buf); + cv::gpu::calcHist(d_src, d_hist, d_buf); } } -INSTANTIATE_TEST_CASE_P(ImgProc, CalcHist, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // EqualizeHist -GPU_PERF_TEST(EqualizeHist, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, ImgProc_EqualizeHist, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); + cv::Mat src(size, CV_8UC1); + fillRandom(src); - cv::Mat src_host(size, CV_8UC1); - fill(src_host, 0, 255); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_hist; + cv::gpu::GpuMat d_buf; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - cv::gpu::GpuMat hist; - cv::gpu::GpuMat buf; - - cv::gpu::equalizeHist(src, dst, hist, buf); + cv::gpu::equalizeHist(d_src, d_dst, d_hist, d_buf); TEST_CYCLE() { - cv::gpu::equalizeHist(src, dst, hist, buf); + cv::gpu::equalizeHist(d_src, d_dst, d_hist, d_buf); } } -INSTANTIATE_TEST_CASE_P(ImgProc, EqualizeHist, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // ColumnSum -GPU_PERF_TEST(ColumnSum, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, ImgProc_ColumnSum, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); + cv::Mat src(size, CV_32FC1); + fillRandom(src); - cv::Mat src_host(size, CV_32FC1); - fill(src_host, 0, 255); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::columnSum(src, dst); + cv::gpu::columnSum(d_src, d_dst); TEST_CYCLE() { - cv::gpu::columnSum(src, dst); + cv::gpu::columnSum(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(ImgProc, ColumnSum, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // Canny -IMPLEMENT_PARAM_CLASS(AppertureSize, int) -IMPLEMENT_PARAM_CLASS(L2gradient, bool) +DEF_PARAM_TEST(Image_AppertureSz_L2gradient, string, int, bool); -GPU_PERF_TEST(Canny, cv::gpu::DeviceInfo, AppertureSize, L2gradient) +PERF_TEST_P(Image_AppertureSz_L2gradient, ImgProc_Canny, Combine( + Values("perf/800x600.jpg", "perf/1280x1024.jpg", "perf/1680x1050.jpg"), + Values(3, 5), + Bool())) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - + string fileName = GET_PARAM(0); int apperture_size = GET_PARAM(1); bool useL2gradient = GET_PARAM(2); - cv::Mat image_host = readImage("perf/1280x1024.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(image_host.empty()); + cv::Mat image = readImage(fileName, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(image.empty()); - cv::gpu::GpuMat image(image_host); - cv::gpu::GpuMat dst; - cv::gpu::CannyBuf buf; + cv::gpu::GpuMat d_image(image); + cv::gpu::GpuMat d_dst; + cv::gpu::CannyBuf d_buf; - cv::gpu::Canny(image, buf, dst, 50.0, 100.0, apperture_size, useL2gradient); + cv::gpu::Canny(d_image, d_buf, d_dst, 50.0, 100.0, apperture_size, useL2gradient); TEST_CYCLE() { - cv::gpu::Canny(image, buf, dst, 50.0, 100.0, apperture_size, useL2gradient); + cv::gpu::Canny(d_image, d_buf, d_dst, 50.0, 100.0, apperture_size, useL2gradient); } } -INSTANTIATE_TEST_CASE_P(ImgProc, Canny, testing::Combine( - ALL_DEVICES, - testing::Values(AppertureSize(3), AppertureSize(5)), - testing::Values(L2gradient(false), L2gradient(true)))); - ////////////////////////////////////////////////////////////////////// // MeanShiftFiltering -GPU_PERF_TEST_1(MeanShiftFiltering, cv::gpu::DeviceInfo) -{ - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); +DEF_PARAM_TEST_1(Image, string); - cv::Mat img = readImage("gpu/meanshift/cones.png"); +PERF_TEST_P(Image, ImgProc_MeanShiftFiltering, Values("gpu/meanshift/cones.png")) +{ + declare.time(5.0); + + cv::Mat img = readImage(GetParam()); ASSERT_FALSE(img.empty()); cv::Mat rgba; cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA); - cv::gpu::GpuMat src(rgba); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(rgba); + cv::gpu::GpuMat d_dst; - cv::gpu::meanShiftFiltering(src, dst, 50, 50); - - declare.time(5.0); + cv::gpu::meanShiftFiltering(d_src, d_dst, 50, 50); TEST_CYCLE() { - cv::gpu::meanShiftFiltering(src, dst, 50, 50); + cv::gpu::meanShiftFiltering(d_src, d_dst, 50, 50); } } -INSTANTIATE_TEST_CASE_P(ImgProc, MeanShiftFiltering, ALL_DEVICES); - ////////////////////////////////////////////////////////////////////// // MeanShiftProc -GPU_PERF_TEST_1(MeanShiftProc, cv::gpu::DeviceInfo) +PERF_TEST_P(Image, ImgProc_MeanShiftProc, Values("gpu/meanshift/cones.png")) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + declare.time(5.0); - cv::Mat img = readImage("gpu/meanshift/cones.png"); + cv::Mat img = readImage(GetParam()); ASSERT_FALSE(img.empty()); cv::Mat rgba; cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA); - cv::gpu::GpuMat src(rgba); - cv::gpu::GpuMat dstr; - cv::gpu::GpuMat dstsp; + cv::gpu::GpuMat d_src(rgba); + cv::gpu::GpuMat d_dstr; + cv::gpu::GpuMat d_dstsp; - cv::gpu::meanShiftProc(src, dstr, dstsp, 50, 50); - - declare.time(5.0); + cv::gpu::meanShiftProc(d_src, d_dstr, d_dstsp, 50, 50); TEST_CYCLE() { - cv::gpu::meanShiftProc(src, dstr, dstsp, 50, 50); + cv::gpu::meanShiftProc(d_src, d_dstr, d_dstsp, 50, 50); } } -INSTANTIATE_TEST_CASE_P(ImgProc, MeanShiftProc, ALL_DEVICES); - ////////////////////////////////////////////////////////////////////// // MeanShiftSegmentation -GPU_PERF_TEST_1(MeanShiftSegmentation, cv::gpu::DeviceInfo) +PERF_TEST_P(Image, ImgProc_MeanShiftSegmentation, Values("gpu/meanshift/cones.png")) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + declare.time(5.0); - cv::Mat img = readImage("gpu/meanshift/cones.png"); + cv::Mat img = readImage(GetParam()); ASSERT_FALSE(img.empty()); cv::Mat rgba; cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA); - cv::gpu::GpuMat src(rgba); cv::Mat dst; - meanShiftSegmentation(src, dst, 10, 10, 20); + cv::gpu::GpuMat d_src(rgba); - declare.time(5.0); + cv::gpu::meanShiftSegmentation(d_src, dst, 10, 10, 20); TEST_CYCLE() { - meanShiftSegmentation(src, dst, 10, 10, 20); + cv::gpu::meanShiftSegmentation(d_src, dst, 10, 10, 20); } } -INSTANTIATE_TEST_CASE_P(ImgProc, MeanShiftSegmentation, ALL_DEVICES); - ////////////////////////////////////////////////////////////////////// // BlendLinear -GPU_PERF_TEST(BlendLinear, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, ImgProc_BlendLinear, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_32F), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat img1_host(size, type); - fill(img1_host, 0, 255); + cv::Mat img1(size, type); + fillRandom(img1); - cv::Mat img2_host(size, type); - fill(img2_host, 0, 255); + cv::Mat img2(size, type); + fillRandom(img2); - cv::gpu::GpuMat img1(img1_host); - cv::gpu::GpuMat img2(img2_host); - cv::gpu::GpuMat weights1(size, CV_32FC1, cv::Scalar::all(0.5)); - cv::gpu::GpuMat weights2(size, CV_32FC1, cv::Scalar::all(0.5)); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_img1(img1); + cv::gpu::GpuMat d_img2(img2); + cv::gpu::GpuMat d_weights1(size, CV_32FC1, cv::Scalar::all(0.5)); + cv::gpu::GpuMat d_weights2(size, CV_32FC1, cv::Scalar::all(0.5)); + cv::gpu::GpuMat d_dst; - cv::gpu::blendLinear(img1, img2, weights1, weights2, dst); + cv::gpu::blendLinear(d_img1, d_img2, d_weights1, d_weights2, d_dst); TEST_CYCLE() { - cv::gpu::blendLinear(img1, img2, weights1, weights2, dst); + cv::gpu::blendLinear(d_img1, d_img2, d_weights1, d_weights2, d_dst); } } -INSTANTIATE_TEST_CASE_P(ImgProc, BlendLinear, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)))); - ////////////////////////////////////////////////////////////////////// // Convolve -IMPLEMENT_PARAM_CLASS(KSize, int) -IMPLEMENT_PARAM_CLASS(Ccorr, bool) +DEF_PARAM_TEST(Sz_KernelSz_Ccorr, cv::Size, int, bool); -GPU_PERF_TEST(Convolve, cv::gpu::DeviceInfo, cv::Size, KSize, Ccorr) +PERF_TEST_P(Sz_KernelSz_Ccorr, ImgProc_Convolve, Combine(GPU_TYPICAL_MAT_SIZES, Values(17, 27, 32, 64), Bool())) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int templ_size = GET_PARAM(2); - bool ccorr = GET_PARAM(3); - - cv::gpu::GpuMat image = cv::gpu::createContinuous(size, CV_32FC1); - image.setTo(cv::Scalar(1.0)); - - cv::gpu::GpuMat templ = cv::gpu::createContinuous(templ_size, templ_size, CV_32FC1); - templ.setTo(cv::Scalar(1.0)); - - cv::gpu::GpuMat dst; - cv::gpu::ConvolveBuf buf; - - cv::gpu::convolve(image, templ, dst, ccorr, buf); - declare.time(2.0); + cv::Size size = GET_PARAM(0); + int templ_size = GET_PARAM(1); + bool ccorr = GET_PARAM(2); + + cv::gpu::GpuMat d_image = cv::gpu::createContinuous(size, CV_32FC1); + d_image.setTo(cv::Scalar(1.0)); + + cv::gpu::GpuMat d_templ = cv::gpu::createContinuous(templ_size, templ_size, CV_32FC1); + d_templ.setTo(cv::Scalar(1.0)); + + cv::gpu::GpuMat d_dst; + cv::gpu::ConvolveBuf d_buf; + + cv::gpu::convolve(d_image, d_templ, d_dst, ccorr, d_buf); + TEST_CYCLE() { - cv::gpu::convolve(image, templ, dst, ccorr, buf); + cv::gpu::convolve(d_image, d_templ, d_dst, ccorr, d_buf); } } -INSTANTIATE_TEST_CASE_P(ImgProc, Convolve, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(KSize(3), KSize(9), KSize(17), KSize(27), KSize(32), KSize(64)), - testing::Values(Ccorr(false), Ccorr(true)))); - //////////////////////////////////////////////////////////////////////////////// -// MatchTemplate_8U +// MatchTemplate8U CV_ENUM(TemplateMethod, cv::TM_SQDIFF, cv::TM_SQDIFF_NORMED, cv::TM_CCORR, cv::TM_CCORR_NORMED, cv::TM_CCOEFF, cv::TM_CCOEFF_NORMED) -#define ALL_TEMPLATE_METHODS testing::Values(TemplateMethod(cv::TM_SQDIFF), TemplateMethod(cv::TM_SQDIFF_NORMED), TemplateMethod(cv::TM_CCORR), TemplateMethod(cv::TM_CCORR_NORMED), TemplateMethod(cv::TM_CCOEFF), TemplateMethod(cv::TM_CCOEFF_NORMED)) +#define ALL_TEMPLATE_METHODS ValuesIn(TemplateMethod::all()) -IMPLEMENT_PARAM_CLASS(TemplateSize, cv::Size) +DEF_PARAM_TEST(Sz_TemplateSz_Cn_Method, cv::Size, cv::Size, int, TemplateMethod); -GPU_PERF_TEST(MatchTemplate_8U, cv::gpu::DeviceInfo, cv::Size, TemplateSize, Channels, TemplateMethod) +PERF_TEST_P(Sz_TemplateSz_Cn_Method, ImgProc_MatchTemplate8U, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(cv::Size(5, 5), cv::Size(16, 16), cv::Size(30, 30)), + Values(1, 3, 4), + ALL_TEMPLATE_METHODS)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + cv::Size templ_size = GET_PARAM(1); + int cn = GET_PARAM(2); + int method = GET_PARAM(3); - cv::Size size = GET_PARAM(1); - cv::Size templ_size = GET_PARAM(2); - int cn = GET_PARAM(3); - int method = GET_PARAM(4); + cv::Mat image(size, CV_MAKE_TYPE(CV_8U, cn)); + fillRandom(image); - cv::Mat image_host(size, CV_MAKE_TYPE(CV_8U, cn)); - fill(image_host, 0, 255); + cv::Mat templ(templ_size, CV_MAKE_TYPE(CV_8U, cn)); + fillRandom(templ); - cv::Mat templ_host(templ_size, CV_MAKE_TYPE(CV_8U, cn)); - fill(templ_host, 0, 255); + cv::gpu::GpuMat d_image(image); + cv::gpu::GpuMat d_templ(templ); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat image(image_host); - cv::gpu::GpuMat templ(templ_host); - cv::gpu::GpuMat dst; - - cv::gpu::matchTemplate(image, templ, dst, method); + cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); TEST_CYCLE() { - cv::gpu::matchTemplate(image, templ, dst, method); + cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); } }; -INSTANTIATE_TEST_CASE_P(ImgProc, MatchTemplate_8U, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(TemplateSize(cv::Size(5, 5)), TemplateSize(cv::Size(16, 16)), TemplateSize(cv::Size(30, 30))), - testing::Values(Channels(1), Channels(3), Channels(4)), - ALL_TEMPLATE_METHODS)); - //////////////////////////////////////////////////////////////////////////////// -// MatchTemplate_32F +// MatchTemplate32F -GPU_PERF_TEST(MatchTemplate_32F, cv::gpu::DeviceInfo, cv::Size, TemplateSize, Channels, TemplateMethod) +PERF_TEST_P(Sz_TemplateSz_Cn_Method, ImgProc_MatchTemplate32F, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(cv::Size(5, 5), cv::Size(16, 16), cv::Size(30, 30)), + Values(1, 3, 4), + Values(TemplateMethod(cv::TM_SQDIFF), TemplateMethod(cv::TM_CCORR)))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + cv::Size templ_size = GET_PARAM(1); + int cn = GET_PARAM(2); + int method = GET_PARAM(3); - cv::Size size = GET_PARAM(1); - cv::Size templ_size = GET_PARAM(2); - int cn = GET_PARAM(3); - int method = GET_PARAM(4); + cv::Mat image(size, CV_MAKE_TYPE(CV_32F, cn)); + fillRandom(image); - cv::Mat image_host(size, CV_MAKE_TYPE(CV_32F, cn)); - fill(image_host, 0, 255); + cv::Mat templ(templ_size, CV_MAKE_TYPE(CV_32F, cn)); + fillRandom(templ); - cv::Mat templ_host(templ_size, CV_MAKE_TYPE(CV_32F, cn)); - fill(templ_host, 0, 255); + cv::gpu::GpuMat d_image(image); + cv::gpu::GpuMat d_templ(templ); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat image(image_host); - cv::gpu::GpuMat templ(templ_host); - cv::gpu::GpuMat dst; - - cv::gpu::matchTemplate(image, templ, dst, method); + cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); TEST_CYCLE() { - cv::gpu::matchTemplate(image, templ, dst, method); + cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); } }; -INSTANTIATE_TEST_CASE_P(ImgProc, MatchTemplate_32F, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(TemplateSize(cv::Size(5, 5)), TemplateSize(cv::Size(16, 16)), TemplateSize(cv::Size(30, 30))), - testing::Values(Channels(1), Channels(3), Channels(4)), - testing::Values(TemplateMethod(cv::TM_SQDIFF), TemplateMethod(cv::TM_CCORR)))); - ////////////////////////////////////////////////////////////////////// // MulSpectrums CV_FLAGS(DftFlags, 0, cv::DFT_INVERSE, cv::DFT_SCALE, cv::DFT_ROWS, cv::DFT_COMPLEX_OUTPUT, cv::DFT_REAL_OUTPUT) -GPU_PERF_TEST(MulSpectrums, cv::gpu::DeviceInfo, cv::Size, DftFlags) +DEF_PARAM_TEST(Sz_Flags, cv::Size, DftFlags); + +PERF_TEST_P(Sz_Flags, ImgProc_MulSpectrums, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(0, DftFlags(cv::DFT_ROWS)))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int flag = GET_PARAM(1); - cv::Size size = GET_PARAM(1); - int flag = GET_PARAM(2); + cv::Mat a(size, CV_32FC2); + fillRandom(a, 0, 100); - cv::Mat a_host(size, CV_32FC2); - fill(a_host, 0, 100); + cv::Mat b(size, CV_32FC2); + fillRandom(b, 0, 100); - cv::Mat b_host(size, CV_32FC2); - fill(b_host, 0, 100); + cv::gpu::GpuMat d_a(a); + cv::gpu::GpuMat d_b(b); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat a(a_host); - cv::gpu::GpuMat b(b_host); - cv::gpu::GpuMat dst; - - cv::gpu::mulSpectrums(a, b, dst, flag); + cv::gpu::mulSpectrums(d_a, d_b, d_dst, flag); TEST_CYCLE() { - cv::gpu::mulSpectrums(a, b, dst, flag); + cv::gpu::mulSpectrums(d_a, d_b, d_dst, flag); } } -INSTANTIATE_TEST_CASE_P(ImgProc, MulSpectrums, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(DftFlags(0), DftFlags(cv::DFT_ROWS)))); - ////////////////////////////////////////////////////////////////////// // MulAndScaleSpectrums -GPU_PERF_TEST(MulAndScaleSpectrums, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, ImgProc_MulAndScaleSpectrums, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); + cv::Size size = GetParam(); float scale = 1.f / size.area(); - cv::Mat src1_host(size, CV_32FC2); - fill(src1_host, 0, 100); + cv::Mat src1(size, CV_32FC2); + fillRandom(src1, 0, 100); - cv::Mat src2_host(size, CV_32FC2); - fill(src2_host, 0, 100); + cv::Mat src2(size, CV_32FC2); + fillRandom(src2, 0, 100); - cv::gpu::GpuMat src1(src1_host); - cv::gpu::GpuMat src2(src2_host); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; - cv::gpu::mulAndScaleSpectrums(src1, src2, dst, cv::DFT_ROWS, scale, false); + cv::gpu::mulAndScaleSpectrums(d_src1, d_src2, d_dst, cv::DFT_ROWS, scale, false); TEST_CYCLE() { - cv::gpu::mulAndScaleSpectrums(src1, src2, dst, cv::DFT_ROWS, scale, false); + cv::gpu::mulAndScaleSpectrums(d_src1, d_src2, d_dst, cv::DFT_ROWS, scale, false); } } -INSTANTIATE_TEST_CASE_P(ImgProc, MulAndScaleSpectrums, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // Dft -GPU_PERF_TEST(Dft, cv::gpu::DeviceInfo, cv::Size, DftFlags) +PERF_TEST_P(Sz_Flags, ImgProc_Dft, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(0, DftFlags(cv::DFT_ROWS), DftFlags(cv::DFT_INVERSE)))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); - int flag = GET_PARAM(2); - - cv::Mat src_host(size, CV_32FC2); - fill(src_host, 0, 100); - - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - cv::gpu::dft(src, dst, size, flag); - declare.time(2.0); + cv::Size size = GET_PARAM(0); + int flag = GET_PARAM(1); + + cv::Mat src(size, CV_32FC2); + fillRandom(src, 0, 100); + + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::dft(d_src, d_dst, size, flag); + TEST_CYCLE() { - cv::gpu::dft(src, dst, size, flag); + cv::gpu::dft(d_src, d_dst, size, flag); } } -INSTANTIATE_TEST_CASE_P(ImgProc, Dft, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(DftFlags(0), DftFlags(cv::DFT_ROWS), DftFlags(cv::DFT_INVERSE)))); - ////////////////////////////////////////////////////////////////////// // CornerHarris -IMPLEMENT_PARAM_CLASS(BlockSize, int) -IMPLEMENT_PARAM_CLASS(ApertureSize, int) +DEF_PARAM_TEST(Image_Type_Border_BlockSz_ApertureSz, string, MatType, BorderMode, int, int); -GPU_PERF_TEST(CornerHarris, cv::gpu::DeviceInfo, MatType, BorderMode, BlockSize, ApertureSize) +PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerHarris, Combine( + Values("gpu/stereobm/aloe-L.png"), + Values(CV_8UC1, CV_32FC1), + Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_REFLECT)), + Values(3, 5, 7), + Values(0, 3, 5, 7))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + double k = 0.5; + string fileName = GET_PARAM(0); int type = GET_PARAM(1); - int borderType = GET_PARAM(2); + int borderMode = GET_PARAM(2); int blockSize = GET_PARAM(3); int apertureSize = GET_PARAM(4); - cv::Mat img = readImage("gpu/stereobm/aloe-L.png", cv::IMREAD_GRAYSCALE); + cv::Mat img = readImage(fileName, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); img.convertTo(img, type, type == CV_32F ? 1.0 / 255.0 : 1.0); - cv::gpu::GpuMat src(img); - cv::gpu::GpuMat dst; - cv::gpu::GpuMat Dx; - cv::gpu::GpuMat Dy; - cv::gpu::GpuMat buf; + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_Dx; + cv::gpu::GpuMat d_Dy; + cv::gpu::GpuMat d_buf; - double k = 0.5; - - cv::gpu::cornerHarris(src, dst, Dx, Dy, buf, blockSize, apertureSize, k, borderType); + cv::gpu::cornerHarris(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, k, borderMode); TEST_CYCLE() { - cv::gpu::cornerHarris(src, dst, Dx, Dy, buf, blockSize, apertureSize, k, borderType); + cv::gpu::cornerHarris(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, k, borderMode); } } -INSTANTIATE_TEST_CASE_P(ImgProc, CornerHarris, testing::Combine( - ALL_DEVICES, - testing::Values(MatType(CV_8UC1), MatType(CV_32FC1)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_REFLECT)), - testing::Values(BlockSize(3), BlockSize(5), BlockSize(7)), - testing::Values(ApertureSize(0), ApertureSize(3), ApertureSize(5), ApertureSize(7)))); - ////////////////////////////////////////////////////////////////////// // CornerMinEigenVal -GPU_PERF_TEST(CornerMinEigenVal, cv::gpu::DeviceInfo, MatType, BorderMode, BlockSize, ApertureSize) +PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerMinEigenVal, Combine( + Values("gpu/stereobm/aloe-L.png"), + Values(CV_8UC1, CV_32FC1), + Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_REFLECT)), + Values(3, 5, 7), + Values(0, 3, 5, 7))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - + string fileName = GET_PARAM(0); int type = GET_PARAM(1); - int borderType = GET_PARAM(2); + int borderMode = GET_PARAM(2); int blockSize = GET_PARAM(3); int apertureSize = GET_PARAM(4); - cv::Mat img = readImage("gpu/stereobm/aloe-L.png", cv::IMREAD_GRAYSCALE); + cv::Mat img = readImage(fileName, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); img.convertTo(img, type, type == CV_32F ? 1.0 / 255.0 : 1.0); - cv::gpu::GpuMat src(img); - cv::gpu::GpuMat dst; - cv::gpu::GpuMat Dx; - cv::gpu::GpuMat Dy; - cv::gpu::GpuMat buf; + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_Dx; + cv::gpu::GpuMat d_Dy; + cv::gpu::GpuMat d_buf; - cv::gpu::cornerMinEigenVal(src, dst, Dx, Dy, buf, blockSize, apertureSize, borderType); + cv::gpu::cornerMinEigenVal(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, borderMode); TEST_CYCLE() { - cv::gpu::cornerMinEigenVal(src, dst, Dx, Dy, buf, blockSize, apertureSize, borderType); + cv::gpu::cornerMinEigenVal(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, borderMode); } } -INSTANTIATE_TEST_CASE_P(ImgProc, CornerMinEigenVal, testing::Combine( - ALL_DEVICES, - testing::Values(MatType(CV_8UC1), MatType(CV_32FC1)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_REFLECT)), - testing::Values(BlockSize(3), BlockSize(5), BlockSize(7)), - testing::Values(ApertureSize(0), ApertureSize(3), ApertureSize(5), ApertureSize(7)))); - ////////////////////////////////////////////////////////////////////// // BuildWarpPlaneMaps -GPU_PERF_TEST(BuildWarpPlaneMaps, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, ImgProc_BuildWarpPlaneMaps, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); + cv::Size size = GetParam(); cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); cv::Mat T = cv::Mat::zeros(1, 3, CV_32F); - cv::gpu::GpuMat map_x; - cv::gpu::GpuMat map_y; - cv::gpu::buildWarpPlaneMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, T, 1.0, map_x, map_y); + cv::gpu::GpuMat d_map_x; + cv::gpu::GpuMat d_map_y; + + cv::gpu::buildWarpPlaneMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, T, 1.0, d_map_x, d_map_y); TEST_CYCLE() { - cv::gpu::buildWarpPlaneMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, T, 1.0, map_x, map_y); + cv::gpu::buildWarpPlaneMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, T, 1.0, d_map_x, d_map_y); } } -INSTANTIATE_TEST_CASE_P(ImgProc, BuildWarpPlaneMaps, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // BuildWarpCylindricalMaps -GPU_PERF_TEST(BuildWarpCylindricalMaps, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, ImgProc_BuildWarpCylindricalMaps, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); + cv::Size size = GetParam(); cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); - cv::gpu::GpuMat map_x; - cv::gpu::GpuMat map_y; - cv::gpu::buildWarpCylindricalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, map_x, map_y); + cv::gpu::GpuMat d_map_x; + cv::gpu::GpuMat d_map_y; + + cv::gpu::buildWarpCylindricalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); TEST_CYCLE() { - cv::gpu::buildWarpCylindricalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, map_x, map_y); + cv::gpu::buildWarpCylindricalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); } } -INSTANTIATE_TEST_CASE_P(ImgProc, BuildWarpCylindricalMaps, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // BuildWarpSphericalMaps -GPU_PERF_TEST(BuildWarpSphericalMaps, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, ImgProc_BuildWarpSphericalMaps, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Size size = GET_PARAM(1); + cv::Size size = GetParam(); cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); - cv::gpu::GpuMat map_x; - cv::gpu::GpuMat map_y; - cv::gpu::buildWarpSphericalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, map_x, map_y); + cv::gpu::GpuMat d_map_x; + cv::gpu::GpuMat d_map_y; + + cv::gpu::buildWarpSphericalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); TEST_CYCLE() { - cv::gpu::buildWarpSphericalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, map_x, map_y); + cv::gpu::buildWarpSphericalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); } } -INSTANTIATE_TEST_CASE_P(ImgProc, BuildWarpSphericalMaps, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // Rotate -GPU_PERF_TEST(Rotate, cv::gpu::DeviceInfo, cv::Size, MatType, Interpolation) -{ - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); +DEF_PARAM_TEST(Sz_Depth_Cn_Inter, cv::Size, MatDepth, int, Interpolation); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); +PERF_TEST_P(Sz_Depth_Cn_Inter, ImgProc_Rotate, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4), + Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)))) +{ + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); int interpolation = GET_PARAM(3); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + int type = CV_MAKE_TYPE(depth, channels); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::rotate(src, dst, size, 30.0, 0, 0, interpolation); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::rotate(d_src, d_dst, size, 30.0, 0, 0, interpolation); TEST_CYCLE() { - cv::gpu::rotate(src, dst, size, 30.0, 0, 0, interpolation); + cv::gpu::rotate(d_src, d_dst, size, 30.0, 0, 0, interpolation); } } -INSTANTIATE_TEST_CASE_P(ImgProc, Rotate, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)))); - ////////////////////////////////////////////////////////////////////// // PyrDown -GPU_PERF_TEST(PyrDown, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, ImgProc_PyrDown, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::pyrDown(src, dst); + cv::gpu::pyrDown(d_src, d_dst); TEST_CYCLE() { - cv::gpu::pyrDown(src, dst); + cv::gpu::pyrDown(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(ImgProc, PyrDown, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)))); - ////////////////////////////////////////////////////////////////////// // PyrUp -GPU_PERF_TEST(PyrUp, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, ImgProc_PyrUp, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::pyrUp(src, dst); + cv::gpu::pyrUp(d_src, d_dst); TEST_CYCLE() { - cv::gpu::pyrUp(src, dst); + cv::gpu::pyrUp(d_src, d_dst); } } -INSTANTIATE_TEST_CASE_P(ImgProc, PyrUp, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)))); - ////////////////////////////////////////////////////////////////////// // CvtColor -GPU_PERF_TEST(CvtColor, cv::gpu::DeviceInfo, cv::Size, MatDepth, CvtColorInfo) +DEF_PARAM_TEST(Sz_Depth_Code, cv::Size, MatDepth, CvtColorInfo); + +PERF_TEST_P(Sz_Depth_Code, ImgProc_CvtColor, Combine( + GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + Values(CvtColorInfo(4, 4, cv::COLOR_RGBA2BGRA), + CvtColorInfo(4, 1, cv::COLOR_BGRA2GRAY), + CvtColorInfo(1, 4, cv::COLOR_GRAY2BGRA), + CvtColorInfo(3, 3, cv::COLOR_BGR2XYZ), + CvtColorInfo(3, 3, cv::COLOR_XYZ2BGR), + CvtColorInfo(3, 3, cv::COLOR_BGR2YCrCb), + CvtColorInfo(3, 3, cv::COLOR_YCrCb2BGR), + CvtColorInfo(3, 3, cv::COLOR_BGR2YUV), + CvtColorInfo(3, 3, cv::COLOR_YUV2BGR), + CvtColorInfo(3, 3, cv::COLOR_BGR2HSV), + CvtColorInfo(3, 3, cv::COLOR_HSV2BGR), + CvtColorInfo(3, 3, cv::COLOR_BGR2HLS), + CvtColorInfo(3, 3, cv::COLOR_HLS2BGR), + CvtColorInfo(3, 3, cv::COLOR_BGR2Lab), + CvtColorInfo(3, 3, cv::COLOR_RGB2Lab), + CvtColorInfo(3, 3, cv::COLOR_BGR2Luv), + CvtColorInfo(3, 3, cv::COLOR_RGB2Luv), + CvtColorInfo(3, 3, cv::COLOR_Lab2BGR), + CvtColorInfo(3, 3, cv::COLOR_Lab2RGB), + CvtColorInfo(3, 3, cv::COLOR_Luv2BGR), + CvtColorInfo(3, 3, cv::COLOR_Luv2RGB), + CvtColorInfo(1, 3, cv::COLOR_BayerBG2BGR), + CvtColorInfo(1, 3, cv::COLOR_BayerGB2BGR), + CvtColorInfo(1, 3, cv::COLOR_BayerRG2BGR), + CvtColorInfo(1, 3, cv::COLOR_BayerGR2BGR), + CvtColorInfo(4, 4, cv::COLOR_RGBA2mRGBA)))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + CvtColorInfo info = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - CvtColorInfo info = GET_PARAM(3); + cv::Mat src(size, CV_MAKETYPE(depth, info.scn)); + fillRandom(src); - cv::Mat src_host(size, CV_MAKETYPE(depth, info.scn)); - fill(src_host, 0, 255); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - if (info.code >= cv::COLOR_BayerBG2BGR && info.code <= cv::COLOR_BayerGR2BGR) - info.dcn = 4; - - cv::gpu::cvtColor(src, dst, info.code, info.dcn); + cv::gpu::cvtColor(d_src, d_dst, info.code, info.dcn); TEST_CYCLE() { - cv::gpu::cvtColor(src, dst, info.code, info.dcn); + cv::gpu::cvtColor(d_src, d_dst, info.code, info.dcn); } } -INSTANTIATE_TEST_CASE_P(ImgProc, CvtColor, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_32F)), - testing::Values(CvtColorInfo(4, 4, cv::COLOR_RGBA2BGRA), - CvtColorInfo(4, 1, cv::COLOR_BGRA2GRAY), - CvtColorInfo(1, 4, cv::COLOR_GRAY2BGRA), - CvtColorInfo(3, 3, cv::COLOR_BGR2XYZ), - CvtColorInfo(3, 3, cv::COLOR_XYZ2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2YCrCb), - CvtColorInfo(3, 3, cv::COLOR_YCrCb2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2YUV), - CvtColorInfo(3, 3, cv::COLOR_YUV2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2HSV), - CvtColorInfo(3, 3, cv::COLOR_HSV2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2HLS), - CvtColorInfo(3, 3, cv::COLOR_HLS2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2Lab), - CvtColorInfo(3, 3, cv::COLOR_RGB2Lab), - CvtColorInfo(3, 3, cv::COLOR_BGR2Luv), - CvtColorInfo(3, 3, cv::COLOR_RGB2Luv), - CvtColorInfo(3, 3, cv::COLOR_Lab2BGR), - CvtColorInfo(3, 3, cv::COLOR_Lab2RGB), - CvtColorInfo(3, 3, cv::COLOR_Luv2BGR), - CvtColorInfo(3, 3, cv::COLOR_Luv2RGB), - CvtColorInfo(1, 3, cv::COLOR_BayerBG2BGR), - CvtColorInfo(1, 3, cv::COLOR_BayerGB2BGR), - CvtColorInfo(1, 3, cv::COLOR_BayerRG2BGR), - CvtColorInfo(1, 3, cv::COLOR_BayerGR2BGR), - CvtColorInfo(4, 4, cv::COLOR_RGBA2mRGBA)))); - ////////////////////////////////////////////////////////////////////// // SwapChannels -GPU_PERF_TEST(SwapChannels, cv::gpu::DeviceInfo, cv::Size) +PERF_TEST_P(Sz, ImgProc_SwapChannels, GPU_TYPICAL_MAT_SIZES) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GetParam(); - cv::Size size = GET_PARAM(1); - - cv::Mat src_host(size, CV_8UC4); - fill(src_host, 0, 255); - - cv::gpu::GpuMat src(src_host); + cv::Mat src(size, CV_8UC4); + fillRandom(src); const int dstOrder[] = {2, 1, 0, 3}; - cv::gpu::swapChannels(src, dstOrder); + cv::gpu::GpuMat d_src(src); + + cv::gpu::swapChannels(d_src, dstOrder); TEST_CYCLE() { - cv::gpu::swapChannels(src, dstOrder); + cv::gpu::swapChannels(d_src, dstOrder); } } -INSTANTIATE_TEST_CASE_P(ImgProc, SwapChannels, testing::Combine(ALL_DEVICES, GPU_TYPICAL_MAT_SIZES)); - ////////////////////////////////////////////////////////////////////// // AlphaComp CV_ENUM(AlphaOp, cv::gpu::ALPHA_OVER, cv::gpu::ALPHA_IN, cv::gpu::ALPHA_OUT, cv::gpu::ALPHA_ATOP, cv::gpu::ALPHA_XOR, cv::gpu::ALPHA_PLUS, cv::gpu::ALPHA_OVER_PREMUL, cv::gpu::ALPHA_IN_PREMUL, cv::gpu::ALPHA_OUT_PREMUL, cv::gpu::ALPHA_ATOP_PREMUL, cv::gpu::ALPHA_XOR_PREMUL, cv::gpu::ALPHA_PLUS_PREMUL, cv::gpu::ALPHA_PREMUL) +#define ALL_ALPHA_OPS ValuesIn(AlphaOp::all()) -GPU_PERF_TEST(AlphaComp, cv::gpu::DeviceInfo, cv::Size, MatType, AlphaOp) +DEF_PARAM_TEST(Sz_Type_Op, cv::Size, MatType, AlphaOp); + +PERF_TEST_P(Sz_Type_Op, ImgProc_AlphaComp, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC4, CV_16UC4, CV_32SC4, CV_32FC4), ALL_ALPHA_OPS)) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int type = GET_PARAM(1); + int alpha_op = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int alpha_op = GET_PARAM(3); + cv::Mat img1(size, type); + fillRandom(img1); - cv::Mat img1_host(size, type); - fill(img1_host, 0, 255); + cv::Mat img2(size, type); + fillRandom(img2); - cv::Mat img2_host(size, type); - fill(img2_host, 0, 255); + cv::gpu::GpuMat d_img1(img1); + cv::gpu::GpuMat d_img2(img2); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat img1(img1_host); - cv::gpu::GpuMat img2(img2_host); - cv::gpu::GpuMat dst; - - cv::gpu::alphaComp(img1, img2, dst, alpha_op); + cv::gpu::alphaComp(d_img1, d_img2, d_dst, alpha_op); TEST_CYCLE() { - cv::gpu::alphaComp(img1, img2, dst, alpha_op); + cv::gpu::alphaComp(d_img1, d_img2, d_dst, alpha_op); } } -INSTANTIATE_TEST_CASE_P(ImgProc, AlphaComp, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC4), MatType(CV_16UC4), MatType(CV_32SC4), MatType(CV_32FC4)), - testing::Values(AlphaOp(cv::gpu::ALPHA_OVER), - AlphaOp(cv::gpu::ALPHA_IN), - AlphaOp(cv::gpu::ALPHA_OUT), - AlphaOp(cv::gpu::ALPHA_ATOP), - AlphaOp(cv::gpu::ALPHA_XOR), - AlphaOp(cv::gpu::ALPHA_PLUS), - AlphaOp(cv::gpu::ALPHA_OVER_PREMUL), - AlphaOp(cv::gpu::ALPHA_IN_PREMUL), - AlphaOp(cv::gpu::ALPHA_OUT_PREMUL), - AlphaOp(cv::gpu::ALPHA_ATOP_PREMUL), - AlphaOp(cv::gpu::ALPHA_XOR_PREMUL), - AlphaOp(cv::gpu::ALPHA_PLUS_PREMUL), - AlphaOp(cv::gpu::ALPHA_PREMUL)))); - ////////////////////////////////////////////////////////////////////// -// ImagePyramid +// ImagePyramidBuild -GPU_PERF_TEST(ImagePyramid_build, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, ImgProc_ImagePyramidBuild, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); + cv::gpu::GpuMat d_src(src); - cv::gpu::ImagePyramid pyr; + cv::gpu::ImagePyramid d_pyr; - pyr.build(src, 5); + d_pyr.build(d_src, 5); TEST_CYCLE() { - pyr.build(src, 5); + d_pyr.build(d_src, 5); } } -INSTANTIATE_TEST_CASE_P(ImgProc, ImagePyramid_build, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)))); +////////////////////////////////////////////////////////////////////// +// ImagePyramidGetLayer -GPU_PERF_TEST(ImagePyramid_getLayer, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, ImgProc_ImagePyramidGetLayer, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + cv::Mat src(size, type); + fillRandom(src); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; + cv::Size dstSize(size.width / 2 + 10, size.height / 2 + 10); - cv::gpu::ImagePyramid pyr(src, 3); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - pyr.getLayer(dst, cv::Size(size.width / 2 + 10, size.height / 2 + 10)); + cv::gpu::ImagePyramid d_pyr(d_src, 3); + + d_pyr.getLayer(d_dst, dstSize); TEST_CYCLE() { - pyr.getLayer(dst, cv::Size(size.width / 2 + 10, size.height / 2 + 10)); + d_pyr.getLayer(d_dst, dstSize); } } -INSTANTIATE_TEST_CASE_P(ImgProc, ImagePyramid_getLayer, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)))); - ////////////////////////////////////////////////////////////////////// // HoughLines -IMPLEMENT_PARAM_CLASS(DoSort, bool) +DEF_PARAM_TEST(Sz_DoSort, cv::Size, bool); -GPU_PERF_TEST(HoughLines, cv::gpu::DeviceInfo, cv::Size, DoSort) +PERF_TEST_P(Sz_DoSort, ImgProc_HoughLines, Combine(GPU_TYPICAL_MAT_SIZES, Bool())) { declare.time(30.0); - const cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - const cv::Size size = GET_PARAM(1); - const bool doSort = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const bool doSort = GET_PARAM(1); const float rho = 1.0f; const float theta = CV_PI / 180.0f; @@ -1365,6 +1201,7 @@ GPU_PERF_TEST(HoughLines, cv::gpu::DeviceInfo, cv::Size, DoSort) cv::gpu::GpuMat d_lines; cv::gpu::GpuMat d_accum; cv::gpu::GpuMat d_buf; + cv::gpu::HoughLines(d_src, d_lines, d_accum, d_buf, rho, theta, threshold, doSort); TEST_CYCLE() @@ -1373,9 +1210,4 @@ GPU_PERF_TEST(HoughLines, cv::gpu::DeviceInfo, cv::Size, DoSort) } } -INSTANTIATE_TEST_CASE_P(ImgProc, HoughLines, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(DoSort(false), DoSort(true)))); - -#endif +} // namespace diff --git a/modules/gpu/perf/perf_labeling.cpp b/modules/gpu/perf/perf_labeling.cpp index 2c537ebbeb..86d67ff93b 100644 --- a/modules/gpu/perf/perf_labeling.cpp +++ b/modules/gpu/perf/perf_labeling.cpp @@ -41,14 +41,16 @@ #include "perf_precomp.hpp" -#ifdef HAVE_CUDA +using namespace std; +using namespace testing; -GPU_PERF_TEST(ConnectedComponents, cv::gpu::DeviceInfo, cv::Size) +namespace { + +DEF_PARAM_TEST_1(Image, string); + +PERF_TEST_P(Image, Labeling_ConnectedComponents, Values("gpu/labeling/aloe-disp.png")) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Mat image = readImage("gpu/labeling/aloe-disp.png", cv::IMREAD_GRAYSCALE); + cv::Mat image = readImage(GetParam(), cv::IMREAD_GRAYSCALE); // cv::threshold(image, image, 150, 255, CV_THRESH_BINARY); @@ -70,6 +72,4 @@ GPU_PERF_TEST(ConnectedComponents, cv::gpu::DeviceInfo, cv::Size) } } -INSTANTIATE_TEST_CASE_P(Labeling, ConnectedComponents, testing::Combine(ALL_DEVICES, testing::Values(cv::Size(261, 262)))); - -#endif \ No newline at end of file +} // namespace diff --git a/modules/gpu/perf/perf_main.cpp b/modules/gpu/perf/perf_main.cpp index 0cd4002775..988c95ae0e 100644 --- a/modules/gpu/perf/perf_main.cpp +++ b/modules/gpu/perf/perf_main.cpp @@ -2,11 +2,98 @@ #ifdef HAVE_CUDA +using namespace std; +using namespace cv; +using namespace cv::gpu; +using namespace cvtest; +using namespace testing; + +void printInfo() +{ +#if defined _WIN32 +# if defined _WIN64 + puts("OS: Windows x64"); +# else + puts("OS: Windows x32"); +# endif +#elif defined linux +# if defined _LP64 + puts("OS: Linux x64"); +# else + puts("OS: Linux x32"); +# endif +#elif defined __APPLE__ +# if defined _LP64 + puts("OS: Apple x64"); +# else + puts("OS: Apple x32"); +# endif +#endif + + int driver; + cudaDriverGetVersion(&driver); + + printf("CUDA Driver version: %d\n", driver); + printf("CUDA Runtime version: %d\n", CUDART_VERSION); + + puts("GPU module was compiled for the following GPU archs:"); + printf(" BIN: %s\n", CUDA_ARCH_BIN); + printf(" PTX: %s\n\n", CUDA_ARCH_PTX); + + int deviceCount = getCudaEnabledDeviceCount(); + printf("CUDA device count: %d\n\n", deviceCount); + + for (int i = 0; i < deviceCount; ++i) + { + DeviceInfo info(i); + + printf("Device %d:\n", i); + printf(" Name: %s\n", info.name().c_str()); + printf(" Compute capability version: %d.%d\n", info.majorVersion(), info.minorVersion()); + printf(" Multi Processor Count: %d\n", info.multiProcessorCount()); + printf(" Total memory: %d Mb\n", static_cast(static_cast(info.totalMemory() / 1024.0) / 1024.0)); + printf(" Free memory: %d Mb\n", static_cast(static_cast(info.freeMemory() / 1024.0) / 1024.0)); + if (!info.isCompatible()) + puts(" !!! This device is NOT compatible with current GPU module build\n"); + printf("\n"); + } +} + int main(int argc, char **argv) { + CommandLineParser parser(argc, (const char**)argv, + "{ print_info_only | print_info_only | false | Print information about system and exit }" + "{ device | device | 0 | Device on which tests will be executed }"); + + printInfo(); + + if (parser.get("print_info_only")) + return 0; + + int device = parser.get("device"); + + if (device < 0 || device >= getCudaEnabledDeviceCount()) + { + cerr << "Incorrect device number - " << device << endl; + return -1; + } + + DeviceInfo info(device); + if (!info.isCompatible()) + { + cerr << "Device " << device << " [" << info.name() << "] is NOT compatible with current GPU module build" << endl; + return -1; + } + + std::cout << "Run tests on device " << device << '\n' << std::endl; + + setDevice(device); + testing::InitGoogleTest(&argc, argv); perf::TestBase::Init(argc, argv); return RUN_ALL_TESTS(); + + return 0; } #else diff --git a/modules/gpu/perf/perf_matop.cpp b/modules/gpu/perf/perf_matop.cpp index 5cc24402c0..c014b19da8 100644 --- a/modules/gpu/perf/perf_matop.cpp +++ b/modules/gpu/perf/perf_matop.cpp @@ -1,141 +1,115 @@ #include "perf_precomp.hpp" -#ifdef HAVE_CUDA +using namespace std; +using namespace testing; + +namespace { ////////////////////////////////////////////////////////////////////// // SetTo -GPU_PERF_TEST(SetTo, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, MatOp_SetTo, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F, CV_64F), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::gpu::GpuMat src(size, type); cv::Scalar val(1, 2, 3, 4); - src.setTo(val); + cv::gpu::GpuMat d_src(size, type); + + d_src.setTo(val); TEST_CYCLE() { - src.setTo(val); + d_src.setTo(val); } } -INSTANTIATE_TEST_CASE_P(MatOp, SetTo, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4), - MatType(CV_64FC1), MatType(CV_64FC3), MatType(CV_64FC4)))); - ////////////////////////////////////////////////////////////////////// // SetToMasked -GPU_PERF_TEST(SetToMasked, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, MatOp_SetToMasked, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F, CV_64F), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + cv::Mat src(size, type); + fillRandom(src); - cv::Mat mask_host(size, CV_8UC1); - fill(mask_host, 0, 2); + cv::Mat mask(size, CV_8UC1); + fillRandom(mask, 0, 2); - cv::gpu::GpuMat src(src_host); cv::Scalar val(1, 2, 3, 4); - cv::gpu::GpuMat mask(mask_host); - src.setTo(val, mask); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_mask(mask); + + d_src.setTo(val, d_mask); TEST_CYCLE() { - src.setTo(val, mask); + d_src.setTo(val, d_mask); } } -INSTANTIATE_TEST_CASE_P(MatOp, SetToMasked, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4), - MatType(CV_64FC1), MatType(CV_64FC3), MatType(CV_64FC4)))); - ////////////////////////////////////////////////////////////////////// // CopyToMasked -GPU_PERF_TEST(CopyToMasked, cv::gpu::DeviceInfo, cv::Size, MatType) +PERF_TEST_P(Sz_Depth_Cn, MatOp_CopyToMasked, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F, CV_64F), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth = GET_PARAM(1); + int channels = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); + int type = CV_MAKE_TYPE(depth, channels); - cv::Mat src_host(size, type); - fill(src_host, 0, 255); + cv::Mat src(size, type); + fillRandom(src); - cv::Mat mask_host(size, CV_8UC1); - fill(mask_host, 0, 2); + cv::Mat mask(size, CV_8UC1); + fillRandom(mask, 0, 2); - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat mask(mask_host); - cv::gpu::GpuMat dst; + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_mask(mask); + cv::gpu::GpuMat d_dst; - src.copyTo(dst, mask); + d_src.copyTo(d_dst, d_mask); TEST_CYCLE() { - src.copyTo(dst, mask); + d_src.copyTo(d_dst, d_mask); } } -INSTANTIATE_TEST_CASE_P(MatOp, CopyToMasked, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4), - MatType(CV_64FC1), MatType(CV_64FC3), MatType(CV_64FC4)))); - ////////////////////////////////////////////////////////////////////// // ConvertTo -GPU_PERF_TEST(ConvertTo, cv::gpu::DeviceInfo, cv::Size, MatDepth, MatDepth) +DEF_PARAM_TEST(Sz_2Depth, cv::Size, MatDepth, MatDepth); + +PERF_TEST_P(Sz_2Depth, MatOp_ConvertTo, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F, CV_64F), Values(CV_8U, CV_16U, CV_32F, CV_64F))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Size size = GET_PARAM(0); + int depth1 = GET_PARAM(1); + int depth2 = GET_PARAM(2); - cv::Size size = GET_PARAM(1); - int depth1 = GET_PARAM(2); - int depth2 = GET_PARAM(3); + cv::Mat src(size, depth1); + fillRandom(src); - cv::Mat src_host(size, depth1); - fill(src_host, 0, 255); + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat src(src_host); - cv::gpu::GpuMat dst; - - src.convertTo(dst, depth2, 0.5, 1.0); + d_src.convertTo(d_dst, depth2, 0.5, 1.0); TEST_CYCLE() { - src.convertTo(dst, depth2, 0.5, 1.0); + d_src.convertTo(d_dst, depth2, 0.5, 1.0); } } -INSTANTIATE_TEST_CASE_P(MatOp, ConvertTo, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_32F), MatDepth(CV_64F)), - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_32F), MatDepth(CV_64F)))); - -#endif +} // namespace diff --git a/modules/gpu/perf/perf_objdetect.cpp b/modules/gpu/perf/perf_objdetect.cpp index c376586c9b..9c1f7919f9 100644 --- a/modules/gpu/perf/perf_objdetect.cpp +++ b/modules/gpu/perf/perf_objdetect.cpp @@ -1,85 +1,84 @@ #include "perf_precomp.hpp" -#ifdef HAVE_CUDA +using namespace std; +using namespace testing; + +namespace { /////////////////////////////////////////////////////////////// // HOG -GPU_PERF_TEST_1(HOG, cv::gpu::DeviceInfo) +DEF_PARAM_TEST_1(Image, string); + +PERF_TEST_P(Image, ObjDetect_HOG, Values("gpu/hog/road.png")) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(img.empty()); - cv::Mat img_host = readImage("gpu/hog/road.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_host.empty()); - - cv::gpu::GpuMat img(img_host); std::vector found_locations; - cv::gpu::HOGDescriptor hog; - hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector()); + cv::gpu::GpuMat d_img(img); - hog.detectMultiScale(img, found_locations); + cv::gpu::HOGDescriptor d_hog; + d_hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector()); + + d_hog.detectMultiScale(d_img, found_locations); TEST_CYCLE() { - hog.detectMultiScale(img, found_locations); + d_hog.detectMultiScale(d_img, found_locations); } } -INSTANTIATE_TEST_CASE_P(ObjDetect, HOG, ALL_DEVICES); - /////////////////////////////////////////////////////////////// // HaarClassifier -GPU_PERF_TEST_1(HaarClassifier, cv::gpu::DeviceInfo) +typedef pair pair_string; +DEF_PARAM_TEST_1(ImageAndCascade, pair_string); + +PERF_TEST_P(ImageAndCascade, ObjDetect_HaarClassifier, + Values(make_pair("gpu/haarcascade/group_1_640x480_VGA.pgm", "gpu/perf/haarcascade_frontalface_alt.xml"))) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(img.empty()); - cv::Mat img_host = readImage("gpu/haarcascade/group_1_640x480_VGA.pgm", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_host.empty()); + cv::gpu::CascadeClassifier_GPU d_cascade; - cv::gpu::CascadeClassifier_GPU cascade; + ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second))); - ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/perf/haarcascade_frontalface_alt.xml"))); + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_objects_buffer; - cv::gpu::GpuMat img(img_host); - cv::gpu::GpuMat objects_buffer; - - cascade.detectMultiScale(img, objects_buffer); + d_cascade.detectMultiScale(d_img, d_objects_buffer); TEST_CYCLE() { - cascade.detectMultiScale(img, objects_buffer); + d_cascade.detectMultiScale(d_img, d_objects_buffer); } } -INSTANTIATE_TEST_CASE_P(ObjDetect, HaarClassifier, ALL_DEVICES); +/////////////////////////////////////////////////////////////// +// LBP cascade -//===================== LBP cascade ==========================// -GPU_PERF_TEST_1(LBPClassifier, cv::gpu::DeviceInfo) +PERF_TEST_P(ImageAndCascade, ObjDetect_LBPClassifier, + Values(make_pair("gpu/haarcascade/group_1_640x480_VGA.pgm", "gpu/lbpcascade/lbpcascade_frontalface.xml"))) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(img.empty()); - cv::Mat img_host = readImage("gpu/haarcascade/group_1_640x480_VGA.pgm", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_host.empty()); + cv::gpu::CascadeClassifier_GPU d_cascade; + ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second))); + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_gpu_rects; - cv::gpu::GpuMat img(img_host); - cv::gpu::GpuMat gpu_rects; - cv::gpu::CascadeClassifier_GPU cascade; - ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/lbpcascade/lbpcascade_frontalface.xml"))); + d_cascade.detectMultiScale(d_img, d_gpu_rects); - cascade.detectMultiScale(img, gpu_rects); TEST_CYCLE() { - cascade.detectMultiScale(img, gpu_rects); + d_cascade.detectMultiScale(d_img, d_gpu_rects); } } -INSTANTIATE_TEST_CASE_P(ObjDetect, LBPClassifier, ALL_DEVICES); - -#endif +} // namespace diff --git a/modules/gpu/perf/perf_precomp.hpp b/modules/gpu/perf/perf_precomp.hpp index 19608bde10..be3f234a35 100644 --- a/modules/gpu/perf/perf_precomp.hpp +++ b/modules/gpu/perf/perf_precomp.hpp @@ -11,6 +11,10 @@ #include "cvconfig.h" +#ifdef HAVE_CUDA +#include +#endif + #include "opencv2/ts/ts.hpp" #include "opencv2/ts/ts_perf.hpp" @@ -18,6 +22,10 @@ #include "opencv2/highgui/highgui.hpp" #include "opencv2/gpu/gpu.hpp" #include "opencv2/calib3d/calib3d.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/video/video.hpp" +#include "opencv2/nonfree/nonfree.hpp" +#include "opencv2/legacy/legacy.hpp" #include "perf_utility.hpp" diff --git a/modules/gpu/perf/perf_utility.cpp b/modules/gpu/perf/perf_utility.cpp index bf6bdfe739..42862f49d1 100644 --- a/modules/gpu/perf/perf_utility.cpp +++ b/modules/gpu/perf/perf_utility.cpp @@ -4,12 +4,17 @@ using namespace std; using namespace cv; using namespace cv::gpu; -void fill(Mat& m, double a, double b) +void fillRandom(Mat& m, double a, double b) { RNG rng(123456789); rng.fill(m, RNG::UNIFORM, Scalar::all(a), Scalar::all(b)); } +Mat readImage(const string& fileName, int flags) +{ + return imread(perf::TestBase::getDataPath(fileName), flags); +} + void PrintTo(const CvtColorInfo& info, ostream* os) { static const char* str[] = @@ -184,37 +189,3 @@ void PrintTo(const CvtColorInfo& info, ostream* os) *os << str[info.code]; } - -void cv::gpu::PrintTo(const DeviceInfo& info, ostream* os) -{ - *os << info.name(); -} - -Mat readImage(const string& fileName, int flags) -{ - return imread(perf::TestBase::getDataPath(fileName), flags); -} - -const vector& devices() -{ - static vector devs; - static bool first = true; - - if (first) - { - int deviceCount = getCudaEnabledDeviceCount(); - - devs.reserve(deviceCount); - - for (int i = 0; i < deviceCount; ++i) - { - DeviceInfo info(i); - if (info.isCompatible()) - devs.push_back(info); - } - - first = false; - } - - return devs; -} diff --git a/modules/gpu/perf/perf_utility.hpp b/modules/gpu/perf/perf_utility.hpp index 8693cfc3c0..b717030ff3 100644 --- a/modules/gpu/perf/perf_utility.hpp +++ b/modules/gpu/perf/perf_utility.hpp @@ -1,13 +1,21 @@ #ifndef __OPENCV_PERF_GPU_UTILITY_HPP__ #define __OPENCV_PERF_GPU_UTILITY_HPP__ -void fill(cv::Mat& m, double a, double b); +#include "opencv2/core/core.hpp" +#include "opencv2/core/gpumat.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/ts/ts_perf.hpp" + +void fillRandom(cv::Mat& m, double a = 0.0, double b = 255.0); +cv::Mat readImage(const std::string& fileName, int flags = cv::IMREAD_COLOR); using perf::MatType; using perf::MatDepth; CV_ENUM(BorderMode, cv::BORDER_REFLECT101, cv::BORDER_REPLICATE, cv::BORDER_CONSTANT, cv::BORDER_REFLECT, cv::BORDER_WRAP) - CV_ENUM(Interpolation, cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_CUBIC, cv::INTER_AREA) +#define ALL_BORDER_MODES testing::ValuesIn(BorderMode::all()) +CV_ENUM(Interpolation, cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_CUBIC, cv::INTER_AREA) +#define ALL_INTERPOLATIONS testing::ValuesIn(Interpolation::all()) CV_ENUM(NormType, cv::NORM_INF, cv::NORM_L1, cv::NORM_L2, cv::NORM_HAMMING) struct CvtColorInfo @@ -18,60 +26,18 @@ struct CvtColorInfo explicit CvtColorInfo(int scn_=0, int dcn_=0, int code_=0) : scn(scn_), dcn(dcn_), code(code_) {} }; - void PrintTo(const CvtColorInfo& info, std::ostream* os); -#define IMPLEMENT_PARAM_CLASS(name, type) \ - class name \ - { \ - public: \ - name ( type arg = type ()) : val_(arg) {} \ - operator type () const {return val_;} \ - private: \ - type val_; \ - }; \ - inline void PrintTo( name param, std::ostream* os) \ - { \ - *os << #name << " = " << testing::PrintToString(static_cast< type >(param)); \ - } - -IMPLEMENT_PARAM_CLASS(Channels, int) - -namespace cv { namespace gpu -{ - void PrintTo(const cv::gpu::DeviceInfo& info, std::ostream* os); -}} - -#define GPU_PERF_TEST(name, ...) \ - struct name : perf::TestBaseWithParam< std::tr1::tuple< __VA_ARGS__ > > \ - { \ - public: \ - name() {} \ - protected: \ - void PerfTestBody(); \ - }; \ - TEST_P(name, perf){ RunPerfTestBody(); } \ - void name :: PerfTestBody() - -#define GPU_PERF_TEST_1(name, param_type) \ - struct name : perf::TestBaseWithParam< param_type > \ - { \ - public: \ - name() {} \ - protected: \ - void PerfTestBody(); \ - }; \ - TEST_P(name, perf){ RunPerfTestBody(); } \ - void name :: PerfTestBody() - -#define GPU_TYPICAL_MAT_SIZES testing::Values(perf::szSXGA, perf::sz1080p, cv::Size(1800, 1500)) - -cv::Mat readImage(const std::string& fileName, int flags = cv::IMREAD_COLOR); - -const std::vector& devices(); - -#define ALL_DEVICES testing::ValuesIn(devices()) - #define GET_PARAM(k) std::tr1::get< k >(GetParam()) +#define DEF_PARAM_TEST(name, ...) typedef ::perf::TestBaseWithParam< std::tr1::tuple< __VA_ARGS__ > > name +#define DEF_PARAM_TEST_1(name, param_type) typedef ::perf::TestBaseWithParam< param_type > name + +DEF_PARAM_TEST_1(Sz, cv::Size); +typedef perf::Size_MatType Sz_Type; +DEF_PARAM_TEST(Sz_Depth, cv::Size, MatDepth); +DEF_PARAM_TEST(Sz_Depth_Cn, cv::Size, MatDepth, int); + +#define GPU_TYPICAL_MAT_SIZES testing::Values(perf::szSXGA, perf::sz720p, perf::sz1080p) + #endif // __OPENCV_PERF_GPU_UTILITY_HPP__ diff --git a/modules/gpu/perf/perf_video.cpp b/modules/gpu/perf/perf_video.cpp index 6e577a4a40..a5a1e4da57 100644 --- a/modules/gpu/perf/perf_video.cpp +++ b/modules/gpu/perf/perf_video.cpp @@ -1,305 +1,277 @@ #include "perf_precomp.hpp" -#ifdef HAVE_CUDA +using namespace std; +using namespace testing; + +namespace { ////////////////////////////////////////////////////// // BroxOpticalFlow -GPU_PERF_TEST_1(BroxOpticalFlow, cv::gpu::DeviceInfo) +typedef pair pair_string; + +DEF_PARAM_TEST_1(ImagePair, pair_string); + +PERF_TEST_P(ImagePair, Video_BroxOpticalFlow, Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + declare.time(10); - cv::Mat frame0_host = readImage("gpu/opticalflow/frame0.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame0_host.empty()); + cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame0.empty()); - cv::Mat frame1_host = readImage("gpu/opticalflow/frame1.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame1_host.empty()); + cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame1.empty()); - frame0_host.convertTo(frame0_host, CV_32FC1, 1.0 / 255.0); - frame1_host.convertTo(frame1_host, CV_32FC1, 1.0 / 255.0); + frame0.convertTo(frame0, CV_32FC1, 1.0 / 255.0); + frame1.convertTo(frame1, CV_32FC1, 1.0 / 255.0); - cv::gpu::GpuMat frame0(frame0_host); - cv::gpu::GpuMat frame1(frame1_host); - cv::gpu::GpuMat u; - cv::gpu::GpuMat v; + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_u; + cv::gpu::GpuMat d_v; cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); - d_flow(frame0, frame1, u, v); - - declare.time(10); + d_flow(d_frame0, d_frame1, d_u, d_v); TEST_CYCLE() { - d_flow(frame0, frame1, u, v); + d_flow(d_frame0, d_frame1, d_u, d_v); } } -INSTANTIATE_TEST_CASE_P(Video, BroxOpticalFlow, ALL_DEVICES); - ////////////////////////////////////////////////////// // InterpolateFrames -GPU_PERF_TEST_1(InterpolateFrames, cv::gpu::DeviceInfo) +PERF_TEST_P(ImagePair, Video_InterpolateFrames, Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame0.empty()); - cv::Mat frame0_host = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame0_host.empty()); + cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame1.empty()); - cv::Mat frame1_host = readImage("gpu/perf/aloeR.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame1_host.empty()); + frame0.convertTo(frame0, CV_32FC1, 1.0 / 255.0); + frame1.convertTo(frame1, CV_32FC1, 1.0 / 255.0); - frame0_host.convertTo(frame0_host, CV_32FC1, 1.0 / 255.0); - frame1_host.convertTo(frame1_host, CV_32FC1, 1.0 / 255.0); - - cv::gpu::GpuMat frame0(frame0_host); - cv::gpu::GpuMat frame1(frame1_host); - cv::gpu::GpuMat fu, fv; - cv::gpu::GpuMat bu, bv; + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_fu, d_fv; + cv::gpu::GpuMat d_bu, d_bv; cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); - d_flow(frame0, frame1, fu, fv); - d_flow(frame1, frame0, bu, bv); + d_flow(d_frame0, d_frame1, d_fu, d_fv); + d_flow(d_frame1, d_frame0, d_bu, d_bv); - cv::gpu::GpuMat newFrame; - cv::gpu::GpuMat buf; + cv::gpu::GpuMat d_newFrame; + cv::gpu::GpuMat d_buf; - cv::gpu::interpolateFrames(frame0, frame1, fu, fv, bu, bv, 0.5f, newFrame, buf); + cv::gpu::interpolateFrames(d_frame0, d_frame1, d_fu, d_fv, d_bu, d_bv, 0.5f, d_newFrame, d_buf); TEST_CYCLE() { - cv::gpu::interpolateFrames(frame0, frame1, fu, fv, bu, bv, 0.5f, newFrame, buf); + cv::gpu::interpolateFrames(d_frame0, d_frame1, d_fu, d_fv, d_bu, d_bv, 0.5f, d_newFrame, d_buf); } } -INSTANTIATE_TEST_CASE_P(Video, InterpolateFrames, ALL_DEVICES); - ////////////////////////////////////////////////////// // CreateOpticalFlowNeedleMap -GPU_PERF_TEST_1(CreateOpticalFlowNeedleMap, cv::gpu::DeviceInfo) +PERF_TEST_P(ImagePair, Video_CreateOpticalFlowNeedleMap, Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); + cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame0.empty()); - cv::Mat frame0_host = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame0_host.empty()); + cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame1.empty()); - cv::Mat frame1_host = readImage("gpu/perf/aloeR.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame1_host.empty()); + frame0.convertTo(frame0, CV_32FC1, 1.0 / 255.0); + frame1.convertTo(frame1, CV_32FC1, 1.0 / 255.0); - frame0_host.convertTo(frame0_host, CV_32FC1, 1.0 / 255.0); - frame1_host.convertTo(frame1_host, CV_32FC1, 1.0 / 255.0); - - cv::gpu::GpuMat frame0(frame0_host); - cv::gpu::GpuMat frame1(frame1_host); - cv::gpu::GpuMat u, v; + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_u; + cv::gpu::GpuMat d_v; cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); - d_flow(frame0, frame1, u, v); + d_flow(d_frame0, d_frame1, d_u, d_v); - cv::gpu::GpuMat vertex, colors; + cv::gpu::GpuMat d_vertex, d_colors; - cv::gpu::createOpticalFlowNeedleMap(u, v, vertex, colors); + cv::gpu::createOpticalFlowNeedleMap(d_u, d_v, d_vertex, d_colors); TEST_CYCLE() { - cv::gpu::createOpticalFlowNeedleMap(u, v, vertex, colors); + cv::gpu::createOpticalFlowNeedleMap(d_u, d_v, d_vertex, d_colors); } } -INSTANTIATE_TEST_CASE_P(Video, CreateOpticalFlowNeedleMap, ALL_DEVICES); - ////////////////////////////////////////////////////// // GoodFeaturesToTrack -IMPLEMENT_PARAM_CLASS(MinDistance, double) +DEF_PARAM_TEST(Image_MinDistance, string, double); -GPU_PERF_TEST(GoodFeaturesToTrack, cv::gpu::DeviceInfo, MinDistance) +PERF_TEST_P(Image_MinDistance, Video_GoodFeaturesToTrack, Combine(Values("gpu/perf/aloe.jpg"), Values(0.0, 3.0))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - + string fileName = GET_PARAM(0); double minDistance = GET_PARAM(1); - cv::Mat image_host = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(image_host.empty()); + cv::Mat image = readImage(fileName, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(image.empty()); - cv::gpu::GoodFeaturesToTrackDetector_GPU detector(8000, 0.01, minDistance); + cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(8000, 0.01, minDistance); - cv::gpu::GpuMat image(image_host); - cv::gpu::GpuMat pts; + cv::gpu::GpuMat d_image(image); + cv::gpu::GpuMat d_pts; - detector(image, pts); + d_detector(d_image, d_pts); TEST_CYCLE() { - detector(image, pts); + d_detector(d_image, d_pts); } } -INSTANTIATE_TEST_CASE_P(Video, GoodFeaturesToTrack, testing::Combine( - ALL_DEVICES, - testing::Values(MinDistance(0.0), MinDistance(3.0)))); - ////////////////////////////////////////////////////// // PyrLKOpticalFlowSparse -IMPLEMENT_PARAM_CLASS(GraySource, bool) -IMPLEMENT_PARAM_CLASS(Points, int) -IMPLEMENT_PARAM_CLASS(WinSize, int) -IMPLEMENT_PARAM_CLASS(Levels, int) -IMPLEMENT_PARAM_CLASS(Iters, int) +DEF_PARAM_TEST(ImagePair_Gray_NPts_WinSz_Levels_Iters, pair_string, bool, int, int, int, int); -GPU_PERF_TEST(PyrLKOpticalFlowSparse, cv::gpu::DeviceInfo, GraySource, Points, WinSize, Levels, Iters) +PERF_TEST_P(ImagePair_Gray_NPts_WinSz_Levels_Iters, Video_PyrLKOpticalFlowSparse, Combine( + Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png")), + Bool(), + Values(1000, 2000, 4000, 8000), + Values(9, 13, 17, 21), + Values(1, 2, 3), + Values(1, 10, 30))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - + pair_string imagePair = GET_PARAM(0); bool useGray = GET_PARAM(1); int points = GET_PARAM(2); int winSize = GET_PARAM(3); int levels = GET_PARAM(4); int iters = GET_PARAM(5); - cv::Mat frame0_host = readImage("gpu/opticalflow/frame0.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); - ASSERT_FALSE(frame0_host.empty()); + cv::Mat frame0 = readImage(imagePair.first, useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); + ASSERT_FALSE(frame0.empty()); - cv::Mat frame1_host = readImage("gpu/opticalflow/frame1.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); - ASSERT_FALSE(frame1_host.empty()); + cv::Mat frame1 = readImage(imagePair.second, useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); + ASSERT_FALSE(frame1.empty()); cv::Mat gray_frame; if (useGray) - gray_frame = frame0_host; + gray_frame = frame0; else - cv::cvtColor(frame0_host, gray_frame, cv::COLOR_BGR2GRAY); + cv::cvtColor(frame0, gray_frame, cv::COLOR_BGR2GRAY); - cv::gpu::GpuMat pts; + cv::gpu::GpuMat d_pts; - cv::gpu::GoodFeaturesToTrackDetector_GPU detector(points, 0.01, 0.0); - detector(cv::gpu::GpuMat(gray_frame), pts); + cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(points, 0.01, 0.0); + d_detector(cv::gpu::GpuMat(gray_frame), d_pts); - cv::gpu::PyrLKOpticalFlow pyrLK; - pyrLK.winSize = cv::Size(winSize, winSize); - pyrLK.maxLevel = levels - 1; - pyrLK.iters = iters; + cv::gpu::PyrLKOpticalFlow d_pyrLK; + d_pyrLK.winSize = cv::Size(winSize, winSize); + d_pyrLK.maxLevel = levels - 1; + d_pyrLK.iters = iters; - cv::gpu::GpuMat frame0(frame0_host); - cv::gpu::GpuMat frame1(frame1_host); - cv::gpu::GpuMat nextPts; - cv::gpu::GpuMat status; + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_nextPts; + cv::gpu::GpuMat d_status; - pyrLK.sparse(frame0, frame1, pts, nextPts, status); + d_pyrLK.sparse(d_frame0, d_frame1, d_pts, d_nextPts, d_status); TEST_CYCLE() { - pyrLK.sparse(frame0, frame1, pts, nextPts, status); + d_pyrLK.sparse(d_frame0, d_frame1, d_pts, d_nextPts, d_status); } } -INSTANTIATE_TEST_CASE_P(Video, PyrLKOpticalFlowSparse, testing::Combine( - ALL_DEVICES, - testing::Values(GraySource(true), GraySource(false)), - testing::Values(Points(1000), Points(2000), Points(4000), Points(8000)), - testing::Values(WinSize(9), WinSize(13), WinSize(17), WinSize(21)), - testing::Values(Levels(1), Levels(2), Levels(3)), - testing::Values(Iters(1), Iters(10), Iters(30)))); - ////////////////////////////////////////////////////// // PyrLKOpticalFlowDense -GPU_PERF_TEST(PyrLKOpticalFlowDense, cv::gpu::DeviceInfo, WinSize, Levels, Iters) -{ - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); +DEF_PARAM_TEST(ImagePair_WinSz_Levels_Iters, pair_string, int, int, int); +PERF_TEST_P(ImagePair_WinSz_Levels_Iters, Video_PyrLKOpticalFlowDense, Combine( + Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png")), + Values(3, 5, 7, 9, 13, 17, 21), + Values(1, 2, 3), + Values(1, 10))) +{ + declare.time(30); + + pair_string imagePair = GET_PARAM(0); int winSize = GET_PARAM(1); int levels = GET_PARAM(2); int iters = GET_PARAM(3); - cv::Mat frame0_host = readImage("gpu/opticalflow/frame0.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame0_host.empty()); + cv::Mat frame0 = readImage(imagePair.first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame0.empty()); - cv::Mat frame1_host = readImage("gpu/opticalflow/frame1.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame1_host.empty()); + cv::Mat frame1 = readImage(imagePair.second, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame1.empty()); - cv::gpu::GpuMat frame0(frame0_host); - cv::gpu::GpuMat frame1(frame1_host); - cv::gpu::GpuMat u; - cv::gpu::GpuMat v; + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_u; + cv::gpu::GpuMat d_v; - cv::gpu::PyrLKOpticalFlow pyrLK; + cv::gpu::PyrLKOpticalFlow d_pyrLK; + d_pyrLK.winSize = cv::Size(winSize, winSize); + d_pyrLK.maxLevel = levels - 1; + d_pyrLK.iters = iters; - pyrLK.winSize = cv::Size(winSize, winSize); - pyrLK.maxLevel = levels - 1; - pyrLK.iters = iters; - - pyrLK.dense(frame0, frame1, u, v); - - declare.time(30); + d_pyrLK.dense(d_frame0, d_frame1, d_u, d_v); TEST_CYCLE() { - pyrLK.dense(frame0, frame1, u, v); + d_pyrLK.dense(d_frame0, d_frame1, d_u, d_v); } } -INSTANTIATE_TEST_CASE_P(Video, PyrLKOpticalFlowDense, testing::Combine( - ALL_DEVICES, - testing::Values(WinSize(3), WinSize(5), WinSize(7), WinSize(9), WinSize(13), WinSize(17), WinSize(21)), - testing::Values(Levels(1), Levels(2), Levels(3)), - testing::Values(Iters(1), Iters(10)))); - ////////////////////////////////////////////////////// -// FarnebackOpticalFlowTest +// FarnebackOpticalFlow -GPU_PERF_TEST_1(FarnebackOpticalFlowTest, cv::gpu::DeviceInfo) +PERF_TEST_P(ImagePair, Video_FarnebackOpticalFlow, Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) { - cv::gpu::DeviceInfo devInfo = GetParam(); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Mat frame0_host = readImage("gpu/opticalflow/frame0.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame0_host.empty()); - - cv::Mat frame1_host = readImage("gpu/opticalflow/frame1.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame1_host.empty()); - - cv::gpu::GpuMat frame0(frame0_host); - cv::gpu::GpuMat frame1(frame1_host); - cv::gpu::GpuMat u; - cv::gpu::GpuMat v; - - cv::gpu::FarnebackOpticalFlow farneback; - - farneback(frame0, frame1, u, v); - declare.time(10); + cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame0.empty()); + + cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame1.empty()); + + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_u; + cv::gpu::GpuMat d_v; + + cv::gpu::FarnebackOpticalFlow d_farneback; + + d_farneback(d_frame0, d_frame1, d_u, d_v); + TEST_CYCLE() { - farneback(frame0, frame1, u, v); + d_farneback(d_frame0, d_frame1, d_u, d_v); } } -INSTANTIATE_TEST_CASE_P(Video, FarnebackOpticalFlowTest, ALL_DEVICES); - ////////////////////////////////////////////////////// // FGDStatModel -GPU_PERF_TEST(FGDStatModel, cv::gpu::DeviceInfo, std::string) -{ - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); +DEF_PARAM_TEST_1(Video, string); - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); +PERF_TEST_P(Video, Video_FGDStatModel, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) +{ + declare.time(10); + + string inputFile = perf::TestBase::getDataPath(GetParam()); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -312,8 +284,6 @@ GPU_PERF_TEST(FGDStatModel, cv::gpu::DeviceInfo, std::string) cv::gpu::FGDStatModel d_model(4); d_model.create(d_frame); - declare.time(10); - for (int i = 0; i < 10; ++i) { cap >> frame; @@ -327,23 +297,16 @@ GPU_PERF_TEST(FGDStatModel, cv::gpu::DeviceInfo, std::string) } } -INSTANTIATE_TEST_CASE_P(Video, FGDStatModel, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")))); - ////////////////////////////////////////////////////// // MOG -IMPLEMENT_PARAM_CLASS(LearningRate, double) +DEF_PARAM_TEST(Video_Cn_LearningRate, string, int, double); -GPU_PERF_TEST(MOG, cv::gpu::DeviceInfo, std::string, Channels, LearningRate) +PERF_TEST_P(Video_Cn_LearningRate, Video_MOG, Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), Values(1, 3, 4), Values(0.0, 0.01))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - int cn = GET_PARAM(2); - double learningRate = GET_PARAM(3); + string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + int cn = GET_PARAM(1); + double learningRate = GET_PARAM(2); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -351,8 +314,8 @@ GPU_PERF_TEST(MOG, cv::gpu::DeviceInfo, std::string, Channels, LearningRate) cv::Mat frame; cv::gpu::GpuMat d_frame; - cv::gpu::MOG_GPU mog; - cv::gpu::GpuMat foreground; + cv::gpu::MOG_GPU d_mog; + cv::gpu::GpuMat d_foreground; cap >> frame; ASSERT_FALSE(frame.empty()); @@ -369,7 +332,7 @@ GPU_PERF_TEST(MOG, cv::gpu::DeviceInfo, std::string, Channels, LearningRate) d_frame.upload(frame); - mog(d_frame, foreground, learningRate); + d_mog(d_frame, d_foreground, learningRate); for (int i = 0; i < 10; ++i) { @@ -389,27 +352,20 @@ GPU_PERF_TEST(MOG, cv::gpu::DeviceInfo, std::string, Channels, LearningRate) d_frame.upload(frame); startTimer(); next(); - mog(d_frame, foreground, learningRate); + d_mog(d_frame, d_foreground, learningRate); stopTimer(); } } -INSTANTIATE_TEST_CASE_P(Video, MOG, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")), - testing::Values(Channels(1), Channels(3), Channels(4)), - testing::Values(LearningRate(0.0), LearningRate(0.01)))); - ////////////////////////////////////////////////////// // MOG2 -GPU_PERF_TEST(MOG2_update, cv::gpu::DeviceInfo, std::string, Channels) -{ - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); +DEF_PARAM_TEST(Video_Cn, string, int); - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - int cn = GET_PARAM(2); +PERF_TEST_P(Video_Cn, Video_MOG2, Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), Values(1, 3, 4))) +{ + string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + int cn = GET_PARAM(1); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -417,8 +373,8 @@ GPU_PERF_TEST(MOG2_update, cv::gpu::DeviceInfo, std::string, Channels) cv::Mat frame; cv::gpu::GpuMat d_frame; - cv::gpu::MOG2_GPU mog2; - cv::gpu::GpuMat foreground; + cv::gpu::MOG2_GPU d_mog2; + cv::gpu::GpuMat d_foreground; cap >> frame; ASSERT_FALSE(frame.empty()); @@ -435,7 +391,7 @@ GPU_PERF_TEST(MOG2_update, cv::gpu::DeviceInfo, std::string, Channels) d_frame.upload(frame); - mog2(d_frame, foreground); + d_mog2(d_frame, d_foreground); for (int i = 0; i < 10; ++i) { @@ -455,23 +411,18 @@ GPU_PERF_TEST(MOG2_update, cv::gpu::DeviceInfo, std::string, Channels) d_frame.upload(frame); startTimer(); next(); - mog2(d_frame, foreground); + d_mog2(d_frame, d_foreground); stopTimer(); } } -INSTANTIATE_TEST_CASE_P(Video, MOG2_update, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")), - testing::Values(Channels(1), Channels(3), Channels(4)))); +////////////////////////////////////////////////////// +// MOG2GetBackgroundImage -GPU_PERF_TEST(MOG2_getBackgroundImage, cv::gpu::DeviceInfo, std::string, Channels) +PERF_TEST_P(Video_Cn, Video_MOG2GetBackgroundImage, Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - int cn = GET_PARAM(2); + string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + int cn = GET_PARAM(1); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -479,8 +430,8 @@ GPU_PERF_TEST(MOG2_getBackgroundImage, cv::gpu::DeviceInfo, std::string, Channel cv::Mat frame; cv::gpu::GpuMat d_frame; - cv::gpu::MOG2_GPU mog2; - cv::gpu::GpuMat foreground; + cv::gpu::MOG2_GPU d_mog2; + cv::gpu::GpuMat d_foreground; for (int i = 0; i < 10; ++i) { @@ -499,33 +450,25 @@ GPU_PERF_TEST(MOG2_getBackgroundImage, cv::gpu::DeviceInfo, std::string, Channel d_frame.upload(frame); - mog2(d_frame, foreground); + d_mog2(d_frame, d_foreground); } - cv::gpu::GpuMat background; - mog2.getBackgroundImage(background); + cv::gpu::GpuMat d_background; + d_mog2.getBackgroundImage(d_background); TEST_CYCLE() { - mog2.getBackgroundImage(background); + d_mog2.getBackgroundImage(d_background); } } -INSTANTIATE_TEST_CASE_P(Video, MOG2_getBackgroundImage, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")), - testing::Values(Channels(1), Channels(3), Channels(4)))); - ////////////////////////////////////////////////////// // VIBE -GPU_PERF_TEST(VIBE, cv::gpu::DeviceInfo, std::string, Channels) +PERF_TEST_P(Video_Cn, Video_VIBE, Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), Values(1, 3, 4))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - int cn = GET_PARAM(2); + string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + int cn = GET_PARAM(1); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -545,10 +488,10 @@ GPU_PERF_TEST(VIBE, cv::gpu::DeviceInfo, std::string, Channels) } cv::gpu::GpuMat d_frame(frame); - cv::gpu::VIBE_GPU vibe; - cv::gpu::GpuMat foreground; + cv::gpu::VIBE_GPU d_vibe; + cv::gpu::GpuMat d_foreground; - vibe(d_frame, foreground); + d_vibe(d_frame, d_foreground); for (int i = 0; i < 10; ++i) { @@ -568,28 +511,21 @@ GPU_PERF_TEST(VIBE, cv::gpu::DeviceInfo, std::string, Channels) d_frame.upload(frame); startTimer(); next(); - vibe(d_frame, foreground); + d_vibe(d_frame, d_foreground); stopTimer(); } } -INSTANTIATE_TEST_CASE_P(Video, VIBE, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")), - testing::Values(Channels(1), Channels(3), Channels(4)))); - ////////////////////////////////////////////////////// // GMG -IMPLEMENT_PARAM_CLASS(MaxFeatures, int) +DEF_PARAM_TEST(Video_Cn_MaxFeatures, string, int, int); -GPU_PERF_TEST(GMG, cv::gpu::DeviceInfo, std::string, Channels, MaxFeatures) +PERF_TEST_P(Video_Cn_MaxFeatures, Video_GMG, Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), Values(1, 3, 4), Values(20, 40, 60))) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - int cn = GET_PARAM(2); - int maxFeatures = GET_PARAM(3); + std::string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + int cn = GET_PARAM(1); + int maxFeatures = GET_PARAM(2); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -611,10 +547,10 @@ GPU_PERF_TEST(GMG, cv::gpu::DeviceInfo, std::string, Channels, MaxFeatures) cv::gpu::GpuMat d_frame(frame); cv::gpu::GpuMat d_fgmask; - cv::gpu::GMG_GPU gmg; - gmg.maxFeatures = maxFeatures; + cv::gpu::GMG_GPU d_gmg; + d_gmg.maxFeatures = maxFeatures; - gmg(d_frame, d_fgmask); + d_gmg(d_frame, d_fgmask); for (int i = 0; i < 150; ++i) { @@ -638,32 +574,21 @@ GPU_PERF_TEST(GMG, cv::gpu::DeviceInfo, std::string, Channels, MaxFeatures) d_frame.upload(frame); startTimer(); next(); - gmg(d_frame, d_fgmask); + d_gmg(d_frame, d_fgmask); stopTimer(); } } -INSTANTIATE_TEST_CASE_P(Video, GMG, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")), - testing::Values(Channels(1), Channels(3), Channels(4)), - testing::Values(MaxFeatures(20), MaxFeatures(40), MaxFeatures(60)))); - ////////////////////////////////////////////////////// // VideoWriter -#ifdef WIN32 - -GPU_PERF_TEST(VideoWriter, cv::gpu::DeviceInfo, std::string) +PERF_TEST_P(Video, Video_VideoWriter, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) { + string inputFile = perf::TestBase::getDataPath(GetParam()); + string outputFile = cv::tempfile(".avi"); + const double FPS = 25.0; - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - std::string outputFile = cv::tempfile(".avi"); - cv::VideoCapture reader(inputFile); ASSERT_TRUE( reader.isOpened() ); @@ -690,39 +615,26 @@ GPU_PERF_TEST(VideoWriter, cv::gpu::DeviceInfo, std::string) } } -INSTANTIATE_TEST_CASE_P(Video, VideoWriter, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")))); - -#endif // WIN32 - ////////////////////////////////////////////////////// // VideoReader -GPU_PERF_TEST(VideoReader, cv::gpu::DeviceInfo, std::string) +PERF_TEST_P(Video, Video_VideoReader, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) { - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - - cv::gpu::VideoReader_GPU reader(inputFile); - ASSERT_TRUE( reader.isOpened() ); - - cv::gpu::GpuMat frame; - - reader.read(frame); - declare.time(20); + string inputFile = perf::TestBase::getDataPath(GetParam()); + + cv::gpu::VideoReader_GPU d_reader(inputFile); + ASSERT_TRUE( d_reader.isOpened() ); + + cv::gpu::GpuMat d_frame; + + d_reader.read(d_frame); + TEST_CYCLE_N(10) { - reader.read(frame); + d_reader.read(d_frame); } } -INSTANTIATE_TEST_CASE_P(Video, VideoReader, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")))); - -#endif +} // namespace From 362df96cb9670c1757f1aae77541010da6bbe0a4 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 17 Aug 2012 15:16:45 +0400 Subject: [PATCH 004/163] renamed perf_main.cpp to main.cpp --- modules/gpu/perf/{perf_main.cpp => main.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/gpu/perf/{perf_main.cpp => main.cpp} (100%) diff --git a/modules/gpu/perf/perf_main.cpp b/modules/gpu/perf/main.cpp similarity index 100% rename from modules/gpu/perf/perf_main.cpp rename to modules/gpu/perf/main.cpp From 2634dc6cce264af42379961c64c0ac84a9ba0074 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 17 Aug 2012 15:22:29 +0400 Subject: [PATCH 005/163] removed license comments --- modules/gpu/perf/perf_labeling.cpp | 41 ------------------------------ 1 file changed, 41 deletions(-) diff --git a/modules/gpu/perf/perf_labeling.cpp b/modules/gpu/perf/perf_labeling.cpp index 86d67ff93b..bd1bcf144d 100644 --- a/modules/gpu/perf/perf_labeling.cpp +++ b/modules/gpu/perf/perf_labeling.cpp @@ -1,44 +1,3 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -//M*/ - #include "perf_precomp.hpp" using namespace std; From 00546f24e006c0454dd138f8faec81891543dabe Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 17 Aug 2012 15:50:35 +0400 Subject: [PATCH 006/163] updated mark_nvidia.py script --- modules/gpu/misc/mark_nvidia.py | 357 +++++++++++++++----------------- 1 file changed, 168 insertions(+), 189 deletions(-) diff --git a/modules/gpu/misc/mark_nvidia.py b/modules/gpu/misc/mark_nvidia.py index fd543e9f5f..88070117d9 100644 --- a/modules/gpu/misc/mark_nvidia.py +++ b/modules/gpu/misc/mark_nvidia.py @@ -1,255 +1,234 @@ import sys, re spaces = '[\s]*' -symbols = '[\s\w\d,.=:|]*' +symbols = '[\s\w\d,.:|]*' def pattern1(prefix, test): - return re.compile(spaces + 'perf::' + prefix + '/' + test + '::' + '\(' + symbols + '\)' + spaces) + return re.compile(spaces + prefix + '_' + test + '::' + symbols + '::' + '\(' + symbols + '\)' + spaces) -def pattern2(prefix, test, cvtype): - return re.compile(spaces + 'perf::' + prefix + '/' + test + '::' + '\(' + symbols + cvtype + symbols + '\)' + spaces) +def pattern2(prefix, test, param1): + return re.compile(spaces + prefix + '_' + test + '::' + symbols + '::' + '\(' + symbols + param1 + symbols + '\)' + spaces) -def pattern3(prefix, test, cvtype, param1): - return re.compile(spaces + 'perf::' + prefix + '/' + test + '::' + '\(' + symbols + cvtype + symbols + param1 + symbols + '\)' + spaces) +def pattern3(prefix, test, param1, param2): + return re.compile(spaces + prefix + '_' + test + '::' + symbols + '::' + '\(' + symbols + param1 + symbols + param2 + symbols + '\)' + spaces) -def pattern4(prefix, test, cvtype, param1, param2): - return re.compile(spaces + 'perf::' + prefix + '/' + test + '::' + '\(' + symbols + cvtype + symbols + param1 + symbols + param2 + symbols + '\)' + spaces) +def pattern4(prefix, test, param1, param2, param3): + return re.compile(spaces + prefix + '_' + test + '::' + symbols + '::' + '\(' + symbols + param1 + symbols + param2 + symbols + param3 + symbols + '\)' + spaces) + +def pattern5(prefix, test, param1, param2, param3, param5): + return re.compile(spaces + prefix + '_' + test + '::' + symbols + '::' + '\(' + symbols + param1 + symbols + param2 + symbols + param3 + symbols + param4 + symbols + '\)' + spaces) npp_patterns = [ ############################################################## # Core - - # Core/Add_Mat (CV_8U | CV_16U | CV_32F) - pattern2('Core', 'Add_Mat', '8U'), - pattern2('Core', 'Add_Mat', '16U'), - pattern2('Core', 'Add_Mat', '32F'), - - # Core/Add_Scalar (CV_8U | CV_16U | CV_32F) - pattern2('Core', 'Add_Scalar', '8U'), - pattern2('Core', 'Add_Scalar', '16U'), - pattern2('Core', 'Add_Scalar', '32F'), - - # Core/Subtract_Mat (CV_8U | CV_16U | CV_32F) - pattern2('Core', 'Subtract_Mat', '8U'), - pattern2('Core', 'Subtract_Mat', '16U'), - pattern2('Core', 'Subtract_Mat', '32F'), - - # Core/Subtract_Scalar (CV_8U | CV_16U | CV_32F) - pattern2('Core', 'Subtract_Scalar', '8U'), - pattern2('Core', 'Subtract_Scalar', '16U'), - pattern2('Core', 'Subtract_Scalar', '32F'), - - # Core/Multiply_Mat (CV_8U | CV_16U | CV_32F) - pattern2('Core', 'Multiply_Mat', '8U'), - pattern2('Core', 'Multiply_Mat', '16U'), - pattern2('Core', 'Multiply_Mat', '32F'), - - # Core/Multiply_Scalar (CV_8U | CV_16U | CV_32F) - pattern2('Core', 'Multiply_Scalar', '8U'), - pattern2('Core', 'Multiply_Scalar', '16U'), - pattern2('Core', 'Multiply_Scalar', '32F'), - - # Core/Divide_Mat (CV_8U | CV_16U | CV_32F) - pattern2('Core', 'Divide_Mat', '8U'), - pattern2('Core', 'Divide_Mat', '16U'), - pattern2('Core', 'Divide_Mat', '32F'), - - # Core/Divide_Scalar (CV_8U | CV_16U | CV_32F) - pattern2('Core', 'Divide_Scalar', '8U'), - pattern2('Core', 'Divide_Scalar', '16U'), - pattern2('Core', 'Divide_Scalar', '32F'), - - # Core/AbsDiff_Mat (CV_8U | CV_16U | CV_32F) - pattern2('Core', 'AbsDiff_Mat', '8U'), - pattern2('Core', 'AbsDiff_Mat', '16U'), - pattern2('Core', 'AbsDiff_Mat', '32F'), - - # Core/AbsDiff_Scalar (CV_8U | CV_16U | CV_32F) - pattern2('Core', 'AbsDiff_Scalar', '8U'), - pattern2('Core', 'AbsDiff_Scalar', '16U'), - pattern2('Core', 'AbsDiff_Scalar', '32F'), - # Core/Abs + # Core_AddMat (CV_8U | CV_16U | CV_32F) + pattern2('Core', 'AddMat', '8U'), + pattern2('Core', 'AddMat', '16U'), + pattern2('Core', 'AddMat', '32F'), + + # Core_AddScalar (CV_8U | CV_16U | CV_32F) + pattern2('Core', 'AddScalar', '8U'), + pattern2('Core', 'AddScalar', '16U'), + pattern2('Core', 'AddScalar', '32F'), + + # Core_SubtractMat (CV_8U | CV_16U | CV_32F) + pattern2('Core', 'SubtractMat', '8U'), + pattern2('Core', 'SubtractMat', '16U'), + pattern2('Core', 'SubtractMat', '32F'), + + # Core_SubtractScalar (CV_8U | CV_16U | CV_32F) + pattern2('Core', 'SubtractScalar', '8U'), + pattern2('Core', 'SubtractScalar', '16U'), + pattern2('Core', 'SubtractScalar', '32F'), + + # Core_MultiplyMat (CV_8U | CV_16U | CV_32F) + pattern2('Core', 'MultiplyMat', '8U'), + pattern2('Core', 'MultiplyMat', '16U'), + pattern2('Core', 'MultiplyMat', '32F'), + + # Core_MultiplyScalar (CV_8U | CV_16U | CV_32F) + pattern2('Core', 'MultiplyScalar', '8U'), + pattern2('Core', 'MultiplyScalar', '16U'), + pattern2('Core', 'MultiplyScalar', '32F'), + + # Core_DivideMat (CV_8U | CV_16U | CV_32F) + pattern2('Core', 'DivideMat', '8U'), + pattern2('Core', 'DivideMat', '16U'), + pattern2('Core', 'DivideMat', '32F'), + + # Core_Divide_Scalar (CV_8U | CV_16U | CV_32F) + pattern2('Core', 'DivideScalar', '8U'), + pattern2('Core', 'DivideScalar', '16U'), + pattern2('Core', 'DivideScalar', '32F'), + + # Core_AbsDiff_Mat (CV_8U | CV_16U | CV_32F) + pattern2('Core', 'AbsDiffMat', '8U'), + pattern2('Core', 'AbsDiffMat', '16U'), + pattern2('Core', 'AbsDiffMat', '32F'), + + # Core_AbsDiffScalar (CV_8U | CV_16U | CV_32F) + pattern2('Core', 'AbsDiffScalar', '8U'), + pattern2('Core', 'AbsDiffScalar', '16U'), + pattern2('Core', 'AbsDiffScalar', '32F'), + + # Core_Abs pattern1('Core', 'Abs'), - # Core/Sqr + # Core_Sqr pattern1('Core', 'Sqr'), - # Core/Sqrt + # Core_Sqrt pattern1('Core', 'Sqrt'), - # Core/Log + # Core_Log pattern1('Core', 'Log'), - # Core/Exp + # Core_Exp pattern1('Core', 'Exp'), - # Core/Bitwise_And_Scalar - pattern1('Core', 'Bitwise_And_Scalar'), + # Core_BitwiseAndScalar + pattern1('Core', 'BitwiseAndScalar'), - # Core/Bitwise_Or_Scalar - pattern1('Core', 'Bitwise_Or_Scalar'), + # Core_BitwiseOrScalar + pattern1('Core', 'BitwiseOrScalar'), - # Core/Bitwise_Xor_Scalar - pattern1('Core', 'Bitwise_Xor_Scalar'), + # Core_BitwiseXorScalar + pattern1('Core', 'BitwiseXorScalar'), - # Core/RShift + # Core_RShift pattern1('Core', 'RShift'), - # Core/LShift + # Core_LShift pattern1('Core', 'LShift'), - # Core/Transpose + # Core_Transpose pattern1('Core', 'Transpose'), - # Core/Flip + # Core_Flip pattern1('Core', 'Flip'), - # Core/LUT_OneChannel - pattern1('Core', 'LUT_OneChannel'), + # Core_LutOneChannel + pattern1('Core', 'LutOneChannel'), - # Core/LUT_MultiChannel - pattern1('Core', 'LUT_MultiChannel'), + # Core_LutMultiChannel + pattern1('Core', 'LutMultiChannel'), - # Core/Magnitude_Complex - pattern1('Core', 'Magnitude_Complex'), + # Core_MagnitudeComplex + pattern1('Core', 'MagnitudeComplex'), - # Core/Magnitude_Sqr_Complex - pattern1('Core', 'Magnitude_Sqr_Complex'), + # Core_MagnitudeSqrComplex + pattern1('Core', 'MagnitudeSqrComplex'), - # Core/MeanStdDev + # Core_MeanStdDev pattern1('Core', 'MeanStdDev'), - # Core/NormDiff + # Core_NormDiff pattern1('Core', 'NormDiff'), - + ############################################################## # Filters - # Filters/Blur + # Filters_Blur pattern1('Filters', 'Blur'), - - # Filters/Erode + + # Filters_Erode pattern1('Filters', 'Erode'), - - # Filters/Dilate + + # Filters_Dilate pattern1('Filters', 'Dilate'), - - # Filters/MorphologyEx + + # Filters_MorphologyEx pattern1('Filters', 'MorphologyEx'), - + ############################################################## # ImgProc - - # ImgProc/Resize (8UC1 | 8UC4, INTER_NEAREST | INTER_LINEAR) - pattern3('ImgProc', 'Resize', '8UC1', 'INTER_NEAREST'), - pattern3('ImgProc', 'Resize', '8UC4', 'INTER_NEAREST'), - pattern3('ImgProc', 'Resize', '8UC1', 'INTER_LINEAR'), - pattern3('ImgProc', 'Resize', '8UC4', 'INTER_LINEAR'), - - # ImgProc/Resize (8UC4, INTER_CUBIC) - pattern3('ImgProc', 'Resize', '8UC4', 'INTER_CUBIC'), - - # ImgProc/WarpAffine (8UC1 | 8UC3 | 8UC4 | 32FC1 | 32FC3 | 32FC4, INTER_NEAREST | INTER_LINEAR | INTER_CUBIC, BORDER_CONSTANT) - pattern4('ImgProc', 'WarpAffine', '8UC1', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '8UC1', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '8UC1', 'INTER_CUBIC', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '8UC3', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '8UC3', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '8UC3', 'INTER_CUBIC', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '8UC4', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '8UC4', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '8UC4', 'INTER_CUBIC', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '32FC1', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '32FC1', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '32FC1', 'INTER_CUBIC', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '32FC3', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '32FC3', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '32FC3', 'INTER_CUBIC', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '32FC4', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '32FC4', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpAffine', '32FC4', 'INTER_CUBIC', 'BORDER_CONSTANT'), - - # ImgProc/WarpPerspective (8UC1 | 8UC3 | 8UC4 | 32FC1 | 32FC3 | 32FC4, INTER_NEAREST | INTER_LINEAR | INTER_CUBIC, BORDER_CONSTANT) - pattern4('ImgProc', 'WarpPerspective', '8UC1', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '8UC1', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '8UC1', 'INTER_CUBIC', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '8UC3', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '8UC3', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '8UC3', 'INTER_CUBIC', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '8UC4', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '8UC4', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '8UC4', 'INTER_CUBIC', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '32FC1', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '32FC1', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '32FC1', 'INTER_CUBIC', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '32FC3', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '32FC3', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '32FC3', 'INTER_CUBIC', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '32FC4', 'INTER_NEAREST', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '32FC4', 'INTER_LINEAR', 'BORDER_CONSTANT'), - pattern4('ImgProc', 'WarpPerspective', '32FC4', 'INTER_CUBIC', 'BORDER_CONSTANT'), - - # ImgProc/CopyMakeBorder (8UC1 | 8UC4 | 32SC1 | 32FC1, BORDER_CONSTANT) - pattern3('ImgProc', 'CopyMakeBorder', '8UC1', 'BORDER_CONSTANT'), - pattern3('ImgProc', 'CopyMakeBorder', '8UC4', 'BORDER_CONSTANT'), - pattern3('ImgProc', 'CopyMakeBorder', '32SC1', 'BORDER_CONSTANT'), - pattern3('ImgProc', 'CopyMakeBorder', '32FC1', 'BORDER_CONSTANT'), - - # ImgProc/Threshold (32F, THRESH_TRUNC) + + # ImgProc_Resize (8U, 1 | 4, INTER_NEAREST | INTER_LINEAR) + pattern4('ImgProc', 'Resize', '8U', '1', 'INTER_NEAREST'), + pattern4('ImgProc', 'Resize', '8U', '4', 'INTER_NEAREST'), + pattern4('ImgProc', 'Resize', '8U', '1', 'INTER_LINEAR'), + pattern4('ImgProc', 'Resize', '8U', '4', 'INTER_LINEAR'), + + # ImgProc_Resize (8U, 4, INTER_CUBIC) + pattern4('ImgProc', 'Resize', '8U', '4', 'INTER_CUBIC'), + + # ImgProc_WarpAffine (8U | 32F, INTER_NEAREST | INTER_LINEAR | INTER_CUBIC, BORDER_CONSTANT) + pattern4('ImgProc', 'WarpAffine', '8U' , 'INTER_NEAREST', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'WarpAffine', '8U' , 'INTER_LINEAR', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'WarpAffine', '8U' , 'INTER_CUBIC', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'WarpAffine', '32F', 'INTER_NEAREST', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'WarpAffine', '32F', 'INTER_LINEAR', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'WarpAffine', '32F', 'INTER_CUBIC', 'BORDER_CONSTANT'), + + # ImgProc_WarpPerspective (8U | 32F, INTER_NEAREST | INTER_LINEAR | INTER_CUBIC, BORDER_CONSTANT) + pattern4('ImgProc', 'WarpPerspective', '8U' , 'INTER_NEAREST', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'WarpPerspective', '8U' , 'INTER_LINEAR', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'WarpPerspective', '8U' , 'INTER_CUBIC', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'WarpPerspective', '32F', 'INTER_NEAREST', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'WarpPerspective', '32F', 'INTER_LINEAR', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'WarpPerspective', '32F', 'INTER_CUBIC', 'BORDER_CONSTANT'), + + # ImgProc_CopyMakeBorder (8UC1 | 8UC4 | 32SC1 | 32FC1, BORDER_CONSTANT) + pattern4('ImgProc', 'CopyMakeBorder', '8U' , '1', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'CopyMakeBorder', '8U' , '4', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'CopyMakeBorder', '32S', '1', 'BORDER_CONSTANT'), + pattern4('ImgProc', 'CopyMakeBorder', '32F', '1', 'BORDER_CONSTANT'), + + # ImgProc_Threshold (32F, THRESH_TRUNC) pattern3('ImgProc', 'Threshold', '32F', 'THRESH_TRUNC'), - # ImgProc/Integral_Sqr - pattern1('ImgProc', 'Integral_Sqr'), + # ImgProc_IntegralSqr + pattern1('ImgProc', 'IntegralSqr'), - # ImgProc/HistEven_OneChannel - pattern1('ImgProc', 'HistEven_OneChannel'), + # ImgProc_HistEven_OneChannel + pattern1('ImgProc', 'HistEvenOneChannel'), - # ImgProc/HistEven_FourChannel - pattern1('ImgProc', 'HistEven_FourChannel'), + # ImgProc_HistEven_FourChannel + pattern1('ImgProc', 'HistEvenFourChannel'), - # ImgProc/Rotate + # ImgProc_Rotate pattern1('ImgProc', 'Rotate'), - # ImgProc/SwapChannels + # ImgProc_SwapChannels pattern1('ImgProc', 'SwapChannels'), - # ImgProc/AlphaComp + # ImgProc_AlphaComp pattern1('ImgProc', 'AlphaComp'), - # ImgProc/ImagePyramid_build - pattern1('ImgProc', 'ImagePyramid_build'), + # ImgProc_ImagePyramidBuild + pattern1('ImgProc', 'ImagePyramidBuild'), + + # ImgProc_ImagePyramid_getLayer + pattern1('ImgProc', 'ImagePyramidGetLayer'), - # ImgProc/ImagePyramid_getLayer - pattern1('ImgProc', 'ImagePyramid_getLayer'), - ############################################################## # MatOp - - # MatOp/SetTo (8UC4 | 16UC1 | 16UC4 | 32FC1 | 32FC4) - pattern2('MatOp', 'SetTo', '8UC4'), - pattern2('MatOp', 'SetTo', '16UC1'), - pattern2('MatOp', 'SetTo', '16UC4'), - pattern2('MatOp', 'SetTo', '32FC1'), - pattern2('MatOp', 'SetTo', '32FC4'), - - # MatOp/SetToMasked (8UC4 | 16UC1 | 16UC4 | 32FC1 | 32FC4) - pattern2('MatOp', 'SetToMasked', '8UC4'), - pattern2('MatOp', 'SetToMasked', '16UC1'), - pattern2('MatOp', 'SetToMasked', '16UC4'), - pattern2('MatOp', 'SetToMasked', '32FC1'), - pattern2('MatOp', 'SetToMasked', '32FC4'), - - # MatOp/CopyToMasked (8UC1 | 8UC3 |8UC4 | 16UC1 | 16UC3 | 16UC4 | 32FC1 | 32FC3 | 32FC4) - pattern2('MatOp', 'CopyToMasked', '8UC1'), - pattern2('MatOp', 'CopyToMasked', '8UC3'), - pattern2('MatOp', 'CopyToMasked', '8UC4'), - pattern2('MatOp', 'CopyToMasked', '16UC1'), - pattern2('MatOp', 'CopyToMasked', '16UC3'), - pattern2('MatOp', 'CopyToMasked', '16UC4'), - pattern2('MatOp', 'CopyToMasked', '32FC1'), - pattern2('MatOp', 'CopyToMasked', '32FC3'), - pattern2('MatOp', 'CopyToMasked', '32FC4'), + + # MatOp_SetTo (8UC4 | 16UC1 | 16UC4 | 32FC1 | 32FC4) + pattern3('MatOp', 'SetTo', '8U' , '4'), + pattern3('MatOp', 'SetTo', '16U', '1'), + pattern3('MatOp', 'SetTo', '16U', '4'), + pattern3('MatOp', 'SetTo', '32F', '1'), + pattern3('MatOp', 'SetTo', '32F', '4'), + + # MatOp_SetToMasked (8UC4 | 16UC1 | 16UC4 | 32FC1 | 32FC4) + pattern3('MatOp', 'SetToMasked', '8U' , '4'), + pattern3('MatOp', 'SetToMasked', '16U', '1'), + pattern3('MatOp', 'SetToMasked', '16U', '4'), + pattern3('MatOp', 'SetToMasked', '32F', '1'), + pattern3('MatOp', 'SetToMasked', '32F', '4'), + + # MatOp_CopyToMasked (8UC1 | 8UC3 |8UC4 | 16UC1 | 16UC3 | 16UC4 | 32FC1 | 32FC3 | 32FC4) + pattern3('MatOp', 'CopyToMasked', '8U' , '1'), + pattern3('MatOp', 'CopyToMasked', '8U' , '3'), + pattern3('MatOp', 'CopyToMasked', '8U' , '4'), + pattern3('MatOp', 'CopyToMasked', '16U', '1'), + pattern3('MatOp', 'CopyToMasked', '16U', '3'), + pattern3('MatOp', 'CopyToMasked', '16U', '4'), + pattern3('MatOp', 'CopyToMasked', '32F', '1'), + pattern3('MatOp', 'CopyToMasked', '32F', '3'), + pattern3('MatOp', 'CopyToMasked', '32F', '4'), ] cublasPattern = pattern1('Core', 'GEMM') @@ -260,7 +239,7 @@ if __name__ == "__main__": inputFile = open(sys.argv[1], 'r') lines = inputFile.readlines() inputFile.close() - + for i in range(len(lines)): if cublasPattern.match(lines[i]): From 93172bab87c2c9bab596b964a16256a2f479b303 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 17 Aug 2012 16:12:32 +0400 Subject: [PATCH 007/163] added --cpu flag (run tests on CPU) --- modules/gpu/perf/main.cpp | 124 +++++++++++++++++------------- modules/gpu/perf/perf_utility.cpp | 2 + modules/gpu/perf/perf_utility.hpp | 2 + 3 files changed, 75 insertions(+), 53 deletions(-) diff --git a/modules/gpu/perf/main.cpp b/modules/gpu/perf/main.cpp index 988c95ae0e..865362f880 100644 --- a/modules/gpu/perf/main.cpp +++ b/modules/gpu/perf/main.cpp @@ -1,107 +1,125 @@ #include "perf_precomp.hpp" -#ifdef HAVE_CUDA - using namespace std; using namespace cv; using namespace cv::gpu; using namespace cvtest; using namespace testing; -void printInfo() +void printOsInfo() { #if defined _WIN32 # if defined _WIN64 - puts("OS: Windows x64"); + cout << "OS: Windows x64 \n" << endl; # else - puts("OS: Windows x32"); + cout << "OS: Windows x32 \n" << endl; # endif #elif defined linux # if defined _LP64 - puts("OS: Linux x64"); + cout << "OS: Linux x64 \n" << endl; # else - puts("OS: Linux x32"); + cout << "OS: Linux x32 \n" << endl; # endif #elif defined __APPLE__ # if defined _LP64 - puts("OS: Apple x64"); + cout << "OS: Apple x64 \n" << endl; # else - puts("OS: Apple x32"); + cout << "OS: Apple x32 \n" << endl; # endif #endif +} +void printCudaInfo() +{ +#ifndef HAVE_CUDA + cout << "OpenCV was built without CUDA support \n" << endl; +#else int driver; cudaDriverGetVersion(&driver); - printf("CUDA Driver version: %d\n", driver); - printf("CUDA Runtime version: %d\n", CUDART_VERSION); + cout << "CUDA Driver version: " << driver << '\n'; + cout << "CUDA Runtime version: " << CUDART_VERSION << '\n'; - puts("GPU module was compiled for the following GPU archs:"); - printf(" BIN: %s\n", CUDA_ARCH_BIN); - printf(" PTX: %s\n\n", CUDA_ARCH_PTX); + cout << endl; + + cout << "GPU module was compiled for the following GPU archs:" << endl; + cout << " BIN: " << CUDA_ARCH_BIN << '\n'; + cout << " PTX: " << CUDA_ARCH_PTX << '\n'; + + cout << endl; int deviceCount = getCudaEnabledDeviceCount(); - printf("CUDA device count: %d\n\n", deviceCount); + cout << "CUDA device count: " << deviceCount << '\n'; + + cout << endl; for (int i = 0; i < deviceCount; ++i) { DeviceInfo info(i); - printf("Device %d:\n", i); - printf(" Name: %s\n", info.name().c_str()); - printf(" Compute capability version: %d.%d\n", info.majorVersion(), info.minorVersion()); - printf(" Multi Processor Count: %d\n", info.multiProcessorCount()); - printf(" Total memory: %d Mb\n", static_cast(static_cast(info.totalMemory() / 1024.0) / 1024.0)); - printf(" Free memory: %d Mb\n", static_cast(static_cast(info.freeMemory() / 1024.0) / 1024.0)); + cout << "Device [" << i << "] \n"; + cout << "\t Name: " << info.name() << '\n'; + cout << "\t Compute capability: " << info.majorVersion() << '.' << info.minorVersion()<< '\n'; + cout << "\t Multi Processor Count: " << info.multiProcessorCount() << '\n'; + cout << "\t Total memory: " << static_cast(static_cast(info.totalMemory() / 1024.0) / 1024.0) << " Mb \n"; + cout << "\t Free memory: " << static_cast(static_cast(info.freeMemory() / 1024.0) / 1024.0) << " Mb \n"; if (!info.isCompatible()) - puts(" !!! This device is NOT compatible with current GPU module build\n"); - printf("\n"); + cout << "\t !!! This device is NOT compatible with current GPU module build \n"; + + cout << endl; } +#endif } int main(int argc, char **argv) { - CommandLineParser parser(argc, (const char**)argv, - "{ print_info_only | print_info_only | false | Print information about system and exit }" - "{ device | device | 0 | Device on which tests will be executed }"); + CommandLineParser cmd(argc, argv, + "{ print_info_only | print_info_only | false | Print information about system and exit }" + "{ device | device | 0 | Device on which tests will be executed }" + "{ cpu | cpu | false | Run tests on cpu }" + ); - printInfo(); + printOsInfo(); + printCudaInfo(); - if (parser.get("print_info_only")) + if (cmd.get("print_info_only")) return 0; - int device = parser.get("device"); + int device = cmd.get("device"); + bool cpu = cmd.get("cpu"); +#ifndef HAVE_CUDA + cpu = true; +#endif - if (device < 0 || device >= getCudaEnabledDeviceCount()) + if (cpu) { - cerr << "Incorrect device number - " << device << endl; - return -1; - } + runOnGpu = false; - DeviceInfo info(device); - if (!info.isCompatible()) + cout << "Run tests on CPU \n" << endl; + } + else { - cerr << "Device " << device << " [" << info.name() << "] is NOT compatible with current GPU module build" << endl; - return -1; + runOnGpu = true; + + if (device < 0 || device >= getCudaEnabledDeviceCount()) + { + cerr << "Incorrect device index - " << device << endl; + return -1; + } + + DeviceInfo info(device); + if (!info.isCompatible()) + { + cerr << "Device " << device << " [" << info.name() << "] is NOT compatible with current GPU module build" << endl; + return -1; + } + + setDevice(device); + + cout << "Run tests on device " << device << " [" << info.name() << "] \n" << endl; } - std::cout << "Run tests on device " << device << '\n' << std::endl; - - setDevice(device); - testing::InitGoogleTest(&argc, argv); perf::TestBase::Init(argc, argv); return RUN_ALL_TESTS(); - - return 0; } - -#else - -int main() -{ - printf("OpenCV was built without CUDA support\n"); - return 0; -} - -#endif diff --git a/modules/gpu/perf/perf_utility.cpp b/modules/gpu/perf/perf_utility.cpp index 42862f49d1..3be162b933 100644 --- a/modules/gpu/perf/perf_utility.cpp +++ b/modules/gpu/perf/perf_utility.cpp @@ -4,6 +4,8 @@ using namespace std; using namespace cv; using namespace cv::gpu; +bool runOnGpu = true; + void fillRandom(Mat& m, double a, double b) { RNG rng(123456789); diff --git a/modules/gpu/perf/perf_utility.hpp b/modules/gpu/perf/perf_utility.hpp index b717030ff3..2d21fffb57 100644 --- a/modules/gpu/perf/perf_utility.hpp +++ b/modules/gpu/perf/perf_utility.hpp @@ -6,6 +6,8 @@ #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/ts/ts_perf.hpp" +extern bool runOnGpu; + void fillRandom(cv::Mat& m, double a = 0.0, double b = 255.0); cv::Mat readImage(const std::string& fileName, int flags = cv::IMREAD_COLOR); From 6da9b9f13739994e5a291b9106eb353b66b8a2b4 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Fri, 17 Aug 2012 01:23:25 +0400 Subject: [PATCH 008/163] Android toolchain: libstdc++ and libsupc are removed from explicit link libraries # Please enter the commit message for your changes. Lines starting # with '#' will be kept; you may remove them yourself if you want to. # An empty message aborts the commit. # On branch master # Your branch is ahead of 'origin/master' by 1 commit. # # Changes to be committed: # (use "git reset HEAD^1 ..." to unstage) # # modified: android/android.toolchain.cmake # --- android/android.toolchain.cmake | 131 ++++++++++++++++---------------- 1 file changed, 66 insertions(+), 65 deletions(-) diff --git a/android/android.toolchain.cmake b/android/android.toolchain.cmake index 3c89806ac0..37c9ad15ff 100644 --- a/android/android.toolchain.cmake +++ b/android/android.toolchain.cmake @@ -1,6 +1,6 @@ # ------------------------------------------------------------------------------ # Android CMake toolchain file, for use with the Android NDK r5-r8 -# Requires cmake 2.6.3 or newer (2.8.3 or newer is recommended). +# Requires cmake 2.6.3 or newer (2.8.5 or newer is recommended). # See home page: http://code.google.com/p/android-cmake/ # # The file is mantained by the OpenCV project. And also can be found at @@ -44,7 +44,8 @@ # ANDROID_ABI=armeabi-v7a - specifies the target Application Binary # Interface (ABI). This option nearly matches to the APP_ABI variable # used by ndk-build tool from Android NDK. -# Possible values are: +# +# Possible targets are: # "armeabi" - matches to the NDK ABI with the same name. # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. # "armeabi-v7a" - matches to the NDK ABI with the same name. @@ -55,7 +56,9 @@ # sets VFPV3 as floating-point unit (has 32 registers instead of 16). # "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP. # "x86" - matches to the NDK ABI with the same name. -# See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. +# See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. +# "mips" - matches to the NDK ABI with the same name +# (not testes on real devices) # # ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. # Option is read-only when standalone toolchain used. @@ -183,12 +186,13 @@ # - modified August 2012 # [+] updated for NDK r8b # [~] all intermediate files generated by toolchain are moved into CMakeFiles +# [~] libstdc++ and libsupc are removed from explicit link libraries # ------------------------------------------------------------------------------ cmake_minimum_required( VERSION 2.6.3 ) if( DEFINED CMAKE_CROSSCOMPILING ) - #subsequent toolchain loading is not really needed + # subsequent toolchain loading is not really needed return() endif() @@ -199,7 +203,7 @@ endif() # this one is important set( CMAKE_SYSTEM_NAME Linux ) -#this one not so much +# this one not so much set( CMAKE_SYSTEM_VERSION 1 ) set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) @@ -331,11 +335,11 @@ macro( __COPY_IF_DIFFERENT _source _destination ) endmacro() -#stl version: by default gnustl_static will be used +# stl version: by default gnustl_static will be used set( ANDROID_USE_STLPORT FALSE CACHE BOOL "Experimental: use stlport_static instead of gnustl_static") mark_as_advanced( ANDROID_USE_STLPORT ) -#fight against cygwin +# fight against cygwin set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools") mark_as_advanced( ANDROID_FORBID_SYGWIN ) if( ANDROID_FORBID_SYGWIN ) @@ -344,7 +348,7 @@ if( ANDROID_FORBID_SYGWIN ) endif() if( CMAKE_HOST_WIN32 ) - #remove cygwin from PATH + # remove cygwin from PATH set( __new_path "$ENV{PATH}") __LIST_FILTER( __new_path "cygwin" ) set(ENV{PATH} "${__new_path}") @@ -352,7 +356,7 @@ if( ANDROID_FORBID_SYGWIN ) endif() endif() -#detect current host platform +# detect current host platform set( TOOL_OS_SUFFIX "" ) if( CMAKE_HOST_APPLE ) set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86" ) @@ -365,10 +369,10 @@ else() message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) endif() -#see if we have path to Android NDK +# see if we have path to Android NDK __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK ) if( NOT ANDROID_NDK ) - #see if we have path to Android standalone toolchain + # see if we have path to Android standalone toolchain __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN OBSOLETE_ANDROID_NDK_TOOLCHAIN_ROOT OBSOLETE_ENV_ANDROID_NDK_TOOLCHAIN_ROOT ) if( NOT ANDROID_STANDALONE_TOOLCHAIN ) @@ -397,10 +401,10 @@ if( NOT ANDROID_NDK ) endif( NOT ANDROID_STANDALONE_TOOLCHAIN ) endif( NOT ANDROID_NDK ) -#remember found paths +# remember found paths if( ANDROID_NDK ) get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE ) - #try to detect change + # try to detect change if( CMAKE_AR ) string( LENGTH "${ANDROID_NDK}" __length ) string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) @@ -414,7 +418,7 @@ if( ANDROID_NDK ) set( BUILD_WITH_ANDROID_NDK True ) elseif( ANDROID_STANDALONE_TOOLCHAIN ) get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE ) - #try to detect change + # try to detect change if( CMAKE_AR ) string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length ) string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath ) @@ -438,7 +442,7 @@ else() sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" ) endif() -#get all the details about standalone toolchain +# get all the details about standalone toolchain if( BUILD_WITH_STANDALONE_TOOLCHAIN ) __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" ) set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) @@ -455,7 +459,7 @@ if( BUILD_WITH_STANDALONE_TOOLCHAIN ) set( __availableToolchainArchs "mipsel" ) endif() if( ANDROID_COMPILER_VERSION ) - #do not run gcc every time because it is relatevely expencive + # do not run gcc every time because it is relatevely expencive set( __availableToolchainCompilerVersions "${ANDROID_COMPILER_VERSION}" ) else() execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" --version @@ -464,7 +468,7 @@ if( BUILD_WITH_STANDALONE_TOOLCHAIN ) endif() endif() -#get all the details about NDK +# get all the details about NDK if( BUILD_WITH_ANDROID_NDK ) file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" ) string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" ) @@ -490,7 +494,7 @@ if( BUILD_WITH_ANDROID_NDK ) endif() endif() -#build list of available ABIs +# build list of available ABIs if( NOT ANDROID_SUPPORTED_ABIS ) set( ANDROID_SUPPORTED_ABIS "" ) set( __uniqToolchainArchNames ${__availableToolchainArchs} ) @@ -505,9 +509,9 @@ if( NOT ANDROID_SUPPORTED_ABIS ) endif() endif() -#choose target ABI +# choose target ABI __INIT_VARIABLE( ANDROID_ABI OBSOLETE_ARM_TARGET OBSOLETE_ARM_TARGETS VALUES ${ANDROID_SUPPORTED_ABIS} ) -#verify that target ABI is supported +# verify that target ABI is supported list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx ) if( __androidAbiIdx EQUAL -1 ) string( REPLACE ";" "\", \"", PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" ) @@ -517,10 +521,10 @@ if( __androidAbiIdx EQUAL -1 ) endif() unset( __androidAbiIdx ) -#remember target ABI +# remember target ABI set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE ) -#set target ABI options +# set target ABI options if( ANDROID_ABI STREQUAL "x86" ) set( X86 true ) set( ANDROID_NDK_ABI_NAME "x86" ) @@ -545,7 +549,7 @@ elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_ARCH_FULLNAME "arm" ) set( CMAKE_SYSTEM_PROCESSOR "armv6" ) - #need always fallback to older platform + # need always fallback to older platform set( ARMEABI true ) elseif( ANDROID_ABI STREQUAL "armeabi-v7a") set( ARMEABI_V7A true ) @@ -573,8 +577,8 @@ else() endif() if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" ) - #really dirty hack - #it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run... + # really dirty hack + # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run... file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" ) endif() @@ -592,7 +596,7 @@ else() unset( ANDROID_FORCE_ARM_BUILD CACHE ) endif() -#choose toolchain +# choose toolchain if( ANDROID_TOOLCHAIN_NAME ) list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx ) if( __toolchainIdx EQUAL -1 ) @@ -637,10 +641,10 @@ unset( __availableToolchainMachines ) unset( __availableToolchainArchs ) unset( __availableToolchainCompilerVersions ) -#choose native API level +# choose native API level __INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL ) string( REGEX MATCH "[0-9]+" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" ) -#validate +# validate list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx ) if( __levelIdx EQUAL -1 ) message( SEND_ERROR "Specified Android native API level (${ANDROID_NATIVE_API_LEVEL}) is not supported by your NDK/toolchain." ) @@ -659,7 +663,7 @@ if( CMAKE_VERSION VERSION_GREATER "2.8" ) set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) endif() -#setup paths +# setup paths if( BUILD_WITH_STANDALONE_TOOLCHAIN ) set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) @@ -689,7 +693,7 @@ set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHI if( CMAKE_VERSION VERSION_LESS 2.8.5 ) set( CMAKE_ASM_COMPILER_ARG1 "-c" ) endif() -#there may be a way to make cmake deduce these TODO deduce the rest of the tools +# there may be a way to make cmake deduce these TODO deduce the rest of the tools set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" ) set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" ) @@ -705,11 +709,12 @@ if( APPLE ) endif() mark_as_advanced( CMAKE_INSTALL_NAME_TOOL ) endif() -#export directories + +# export directories set( ANDROID_SYSTEM_INCLUDE_DIRS "" ) set( ANDROID_SYSTEM_LIB_DIRS "" ) -#setup output directories +# setup output directories set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library output, set this to change where android libs are installed to" ) set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) @@ -722,13 +727,13 @@ if(NOT _CMAKE_IN_TRY_COMPILE) set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" ) endif() -#includes +# includes list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${ANDROID_SYSROOT}/usr/include" ) if( __stlIncludePath AND EXISTS "${__stlIncludePath}" ) list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${__stlIncludePath}" ) endif() -#STL bits includes +# c++ bits includes if( __stlLibPath AND EXISTS "${__stlLibPath}/include" ) list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${__stlLibPath}/include" ) endif() @@ -742,7 +747,7 @@ elseif( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/incl list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" ) endif() -#flags and definitions +# flags and definitions if(ANDROID_SYSROOT MATCHES "[ ;\"]") set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) # quotes will break try_compile and compiler identification @@ -766,7 +771,7 @@ set( CMAKE_CXX_PLATFORM_ID Linux ) set( CMAKE_CXX_SIZEOF_DATA_PTR 4 ) set( CMAKE_CXX_HAS_ISYSROOT 1 ) set( CMAKE_CXX_COMPILER_ABI ELF ) -#force ASM compiler (required for CMake < 2.8.5) +# force ASM compiler (required for CMake < 2.8.5) set( CMAKE_ASM_COMPILER_ID_RUN TRUE ) set( CMAKE_ASM_COMPILER_ID GNU ) set( CMAKE_ASM_COMPILER_WORKS TRUE ) @@ -796,17 +801,17 @@ endif() if( ANDROID_USE_STLPORT ) set( _CMAKE_CXX_FLAGS "${_CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions" ) - set( _CMAKE_C_FLAGS "${_CMAKE_C_FLAGS} -fno-rtti -fno-exceptions" ) + set( _CMAKE_C_FLAGS "${_CMAKE_C_FLAGS} -fno-exceptions" ) else() set( _CMAKE_CXX_FLAGS "${_CMAKE_CXX_FLAGS} -frtti -fexceptions" ) set( _CMAKE_C_FLAGS "${_CMAKE_C_FLAGS} -fexceptions" ) endif() -#release and debug flags +# release and debug flags if( ARMEABI OR ARMEABI_V7A ) if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 ) - #It is recommended to use the -mthumb compiler flag to force the generation - #of 16-bit Thumb-1 instructions (the default being 32-bit ARM ones). + # It is recommended to use the -mthumb compiler flag to force the generation + # of 16-bit Thumb-1 instructions (the default being 32-bit ARM ones). # O3 instead of O2/Os in release mode - like cmake sets for desktop gcc set( _CMAKE_CXX_FLAGS_RELEASE "-mthumb -O3" ) set( _CMAKE_C_FLAGS_RELEASE "-mthumb -O3" ) @@ -836,7 +841,7 @@ set( _CMAKE_C_FLAGS_RELEASE "${_CMAKE_C_FLAGS_RELEASE} -fomit-frame-pointer set( _CMAKE_CXX_FLAGS_DEBUG "${_CMAKE_CXX_FLAGS_DEBUG} -fno-strict-aliasing -fno-omit-frame-pointer -DDEBUG -D_DEBUG" ) set( _CMAKE_C_FLAGS_DEBUG "${_CMAKE_C_FLAGS_DEBUG} -fno-strict-aliasing -fno-omit-frame-pointer -DDEBUG -D_DEBUG" ) -#ABI-specific flags +# ABI-specific flags if( ARMEABI_V7A ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" ) if( NEON ) @@ -854,19 +859,18 @@ elseif( X86 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" )#sse? endif() -#linker flags +# linker flags if( NOT DEFINED __ndklibspath ) set( __ndklibspath "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/ndklibs/${ANDROID_NDK_ABI_NAME}" ) endif() -list( APPEND ANDROID_SYSTEM_LIB_DIRS "${__ndklibspath}" "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ) +list( APPEND ANDROID_SYSTEM_LIB_DIRS "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ) set( ANDROID_LINKER_FLAGS "" ) -#STL + +# STL if( ANDROID_USE_STLPORT ) if( EXISTS "${__stlLibPath}/libstlport_static.a" ) - __COPY_IF_DIFFERENT( "${__stlLibPath}/libstlport_static.a" "${__ndklibspath}/libstlport_static.a" ) - endif() - if( EXISTS "${__ndklibspath}/libstlport_static.a" ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--start-group -lstlport_static" ) + set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o \"${__stlLibPath}/libstlport_static.a\"") + set( CMAKE_CXX_CREATE_SHARED_MODULE " -o \"${__stlLibPath}/libstlport_static.a\"") endif() else( ANDROID_USE_STLPORT ) if( EXISTS "${__stlLibPath}/libgnustl_static.a" ) @@ -880,11 +884,6 @@ else( ANDROID_USE_STLPORT ) elseif( EXISTS "${__stlLibPath}/libstdc++.a" ) __COPY_IF_DIFFERENT( "${__stlLibPath}/libstdc++.a" "${__ndklibspath}/libstdc++.a" ) endif() - if( EXISTS "${__ndklibspath}/libstdc++.a" ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -lstdc++" ) - endif() - - #gcc exception & rtti support if( EXISTS "${__stlLibPath}/libsupc++.a" ) __COPY_IF_DIFFERENT( "${__stlLibPath}/libsupc++.a" "${__ndklibspath}/libsupc++.a" ) elseif( ANDROID_ARCH_NAME STREQUAL "arm" AND EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" ) @@ -896,16 +895,14 @@ else( ANDROID_USE_STLPORT ) elseif( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" ) __COPY_IF_DIFFERENT( "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" "${__ndklibspath}/libsupc++.a" ) endif() - if( EXISTS "${__ndklibspath}/libsupc++.a" ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -lsupc++" ) - endif() + list( APPEND ANDROID_SYSTEM_LIB_DIRS "${__ndklibspath}" ) endif( ANDROID_USE_STLPORT ) -#cleanup for STL search +# cleanup for STL search unset( __stlIncludePath ) unset( __stlLibPath ) -#other linker flags +# other linker flags __INIT_VARIABLE( ANDROID_NO_UNDEFINED OBSOLETE_NO_UNDEFINED VALUES ON ) set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" FORCE ) mark_as_advanced( ANDROID_NO_UNDEFINED ) @@ -914,7 +911,7 @@ if( ANDROID_NO_UNDEFINED ) endif() if (ANDROID_NDK MATCHES "-r[56].?$") - #libGLESv2.so in NDK's prior to r7 refers to exteranal symbols. So this flag option is required for all projects using OpenGL from native. + # libGLESv2.so in NDK's prior to r7 refers to exteranal symbols. So this flag option is required for all projects using OpenGL from native. __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES ON ) else() __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF ) @@ -940,7 +937,7 @@ if( ARMEABI_V7A ) set( ANDROID_LINKER_FLAGS "-Wl,--fix-cortex-a8 ${ANDROID_LINKER_FLAGS}" ) endif() -#cache flags +# cache flags set( CMAKE_CXX_FLAGS "${_CMAKE_CXX_FLAGS}" CACHE STRING "c++ flags" ) set( CMAKE_C_FLAGS "${_CMAKE_C_FLAGS}" CACHE STRING "c flags" ) set( CMAKE_CXX_FLAGS_RELEASE "${_CMAKE_CXX_FLAGS_RELEASE}" CACHE STRING "c++ Release flags" ) @@ -954,7 +951,7 @@ set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "linker flags" ) include_directories( SYSTEM ${ANDROID_SYSTEM_INCLUDE_DIRS} ) link_directories( ${ANDROID_SYSTEM_LIB_DIRS} ) -#finish flags +# finish flags set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Extra Android compiler flags") set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Extra Android linker flags") set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) @@ -969,7 +966,7 @@ else() set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" ) endif() -#set these global flags for cmake client scripts to change behavior +# set these global flags for cmake client scripts to change behavior set( ANDROID True ) set( BUILD_ANDROID True ) @@ -982,7 +979,7 @@ set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) -#macro to find packages on the host OS +# macro to find packages on the host OS macro( find_host_package ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) @@ -1004,7 +1001,7 @@ macro( find_host_package ) endmacro() -#macro to find programs on the host OS +# macro to find programs on the host OS macro( find_host_program ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) @@ -1044,7 +1041,11 @@ if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" ) set( __toolchain_config "") foreach( __var ANDROID_ABI ANDROID_FORCE_ARM_BUILD ANDROID_NATIVE_API_LEVEL ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_SET_OBSOLETE_VARIABLES LIBRARY_OUTPUT_PATH_ROOT ANDROID_USE_STLPORT ANDROID_FORBID_SYGWIN ANDROID_NDK ANDROID_STANDALONE_TOOLCHAIN ANDROID_FUNCTION_LEVEL_LINKING __ndklibspath ) if( DEFINED ${__var} ) - set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" )\n" ) + if( "${__var}" MATCHES " ") + set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" ) + else() + set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" ) + endif() endif() endforeach() file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" ) From 41b6d25bdd78ae684d8630fdb20a8752d6d7dee6 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Fri, 17 Aug 2012 17:32:06 +0400 Subject: [PATCH 009/163] added cross-platform Mutex implementation; enable platform-native (GDC/Concurrency) parallel_for_ implementation when TBB is not installed. --- modules/core/include/opencv2/core/core.hpp | 28 ++++++ modules/core/src/parallel.cpp | 10 +++ modules/core/src/system.cpp | 100 +++++++++++++++++++++ 3 files changed, 138 insertions(+) diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index 8cf7b7e277..fbaf13721f 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -4620,6 +4620,34 @@ public: CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body); +/////////////////////////// Synchronization Primitives /////////////////////////////// + +class CV_EXPORTS Mutex +{ +public: + Mutex(); + ~Mutex(); + Mutex(const Mutex& m); + Mutex& operator = (const Mutex& m); + + void lock(); + bool trylock(); + void unlock(); + + struct Impl; +protected: + Impl* impl; +}; + +class CV_EXPORTS AutoLock +{ +public: + AutoLock(Mutex& m) : mutex(&m) { mutex->lock(); } + ~AutoLock() { mutex->unlock(); } +protected: + Mutex* mutex; +}; + } #endif // __cplusplus diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp index 4274caf340..3e21417f74 100644 --- a/modules/core/src/parallel.cpp +++ b/modules/core/src/parallel.cpp @@ -42,6 +42,16 @@ #include "precomp.hpp" +#if !defined HAVE_TBB && !defined HAVE_OPENMP && !defined HAVE_GCD && !defined HAVE_CONCURRENCY + +#ifdef __APPLE__ +#define HAVE_GCD +#elif defined __MSC_VER && __MSC_VER >= 1600 +#define HAVE_CONCURRENCY +#endif + +#endif + #ifdef HAVE_CONCURRENCY # include #elif defined HAVE_OPENMP diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index 42bf6593db..e1d57ef8cb 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -930,4 +930,104 @@ BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID ) } #endif +namespace cv +{ + +#if defined WIN32 || defined _WIN32 || defined WINCE + +struct Mutex::Impl +{ + Impl() { InitializeCriticalSection(&cs); refcount = 1; } + ~Impl() { DeleteCriticalSection(&cs); } + + void lock() { EnterCriticalSection(&cs); } + bool trylock() { return TryEnterCriticalSection(&cs) != 0; } + void unlock() { LeaveCriticalSection(&cs); } + + CRITICAL_SECTION cs; + int refcount; +}; + +#elif defined __APPLE__ + +#include + +struct Mutex::Impl +{ + Impl() { sl = OS_SPINLOCK_INIT; refcount = 1; } + ~Impl() {} + + void lock() { OSSpinLockLock(&sl); } + bool trylock() { return OSSpinLockTry(&sl); } + void unlock() { OSSpinLockUnlock(&sl); } + + OSSpinLock sl; + int refcount; +}; + +#elif defined __linux__ + +struct Mutex::Impl +{ + Impl() { pthread_spin_init(&sl, 0); refcount = 1; } + ~Impl() { pthread_spin_destroy(&sl); } + + void lock() { pthread_spin_lock(&sl); } + bool trylock() { return pthread_spin_trylock(&sl) == 0; } + void unlock() { pthread_spin_unlock(&sl); } + + pthread_spinlock_t sl; + int refcount; +}; + +#else + +struct Mutex::Impl +{ + Impl() { pthread_mutex_init(&sl, 0); refcount = 1; } + ~Impl() { pthread_mutex_destroy(&sl); } + + void lock() { pthread_mutex_lock(&sl); } + bool trylock() { return pthread_mutex_trylock(&sl) == 0; } + void unlock() { pthread_mutex_unlock(&sl); } + + pthread_mutex_t sl; + int refcount; +}; + +#endif + +Mutex::Mutex() +{ + impl = new Mutex::Impl; +} + +Mutex::~Mutex() +{ + if( CV_XADD(&impl->refcount, -1) == 1 ) + delete impl; + impl = 0; +} + +Mutex::Mutex(const Mutex& m) +{ + impl = m.impl; + CV_XADD(&impl->refcount, 1); +} + +Mutex& Mutex::operator = (const Mutex& m) +{ + CV_XADD(&m.impl->refcount, 1); + if( CV_XADD(&impl->refcount, -1) == 1 ) + delete impl; + impl = m.impl; + return *this; +} + +void Mutex::lock() { impl->lock(); } +void Mutex::unlock() { impl->unlock(); } +bool Mutex::trylock() { return impl->trylock(); } + +} + /* End of file. */ \ No newline at end of file From ec8f926686457d4b5f4c7c8d9d78b975ac846812 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Fri, 17 Aug 2012 17:34:51 +0400 Subject: [PATCH 010/163] small correction for the previous patch in parallel.cpp --- modules/core/src/parallel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp index 3e21417f74..c238f992b0 100644 --- a/modules/core/src/parallel.cpp +++ b/modules/core/src/parallel.cpp @@ -46,7 +46,7 @@ #ifdef __APPLE__ #define HAVE_GCD -#elif defined __MSC_VER && __MSC_VER >= 1600 +#elif defined _MSC_VER && _MSC_VER >= 1600 #define HAVE_CONCURRENCY #endif From a507d564a4aaa33cb1fa8bac144a3dacbddbf103 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Fri, 17 Aug 2012 17:34:58 +0400 Subject: [PATCH 011/163] merged gpu_perf_cpu into gpu_perf --- modules/gpu/perf/perf_calib3d.cpp | 258 +++- modules/gpu/perf/perf_core.cpp | 1652 +++++++++++++++------ modules/gpu/perf/perf_features2d.cpp | 209 ++- modules/gpu/perf/perf_filters.cpp | 266 +++- modules/gpu/perf/perf_imgproc.cpp | 994 +++++++++---- modules/gpu/perf/perf_labeling.cpp | 134 +- modules/gpu/perf/perf_matop.cpp | 102 +- modules/gpu/perf/perf_objdetect.cpp | 103 +- modules/gpu/perf/perf_video.cpp | 792 ++++++---- modules/gpu/perf_cpu/perf_calib3d.cpp | 136 -- modules/gpu/perf_cpu/perf_core.cpp | 1388 ----------------- modules/gpu/perf_cpu/perf_cpu_precomp.cpp | 1 - modules/gpu/perf_cpu/perf_cpu_precomp.hpp | 32 - modules/gpu/perf_cpu/perf_features2d.cpp | 187 --- modules/gpu/perf_cpu/perf_filters.cpp | 283 ---- modules/gpu/perf_cpu/perf_imgproc.cpp | 771 ---------- modules/gpu/perf_cpu/perf_labeling.cpp | 158 -- modules/gpu/perf_cpu/perf_main.cpp | 20 - modules/gpu/perf_cpu/perf_matop.cpp | 124 -- modules/gpu/perf_cpu/perf_objdetect.cpp | 74 - modules/gpu/perf_cpu/perf_utility.cpp | 220 --- modules/gpu/perf_cpu/perf_utility.hpp | 77 - modules/gpu/perf_cpu/perf_video.cpp | 466 ------ 23 files changed, 3270 insertions(+), 5177 deletions(-) delete mode 100644 modules/gpu/perf_cpu/perf_calib3d.cpp delete mode 100644 modules/gpu/perf_cpu/perf_core.cpp delete mode 100644 modules/gpu/perf_cpu/perf_cpu_precomp.cpp delete mode 100644 modules/gpu/perf_cpu/perf_cpu_precomp.hpp delete mode 100644 modules/gpu/perf_cpu/perf_features2d.cpp delete mode 100644 modules/gpu/perf_cpu/perf_filters.cpp delete mode 100644 modules/gpu/perf_cpu/perf_imgproc.cpp delete mode 100644 modules/gpu/perf_cpu/perf_labeling.cpp delete mode 100644 modules/gpu/perf_cpu/perf_main.cpp delete mode 100644 modules/gpu/perf_cpu/perf_matop.cpp delete mode 100644 modules/gpu/perf_cpu/perf_objdetect.cpp delete mode 100644 modules/gpu/perf_cpu/perf_utility.cpp delete mode 100644 modules/gpu/perf_cpu/perf_utility.hpp delete mode 100644 modules/gpu/perf_cpu/perf_video.cpp diff --git a/modules/gpu/perf/perf_calib3d.cpp b/modules/gpu/perf/perf_calib3d.cpp index 343a4e9fad..f62185e007 100644 --- a/modules/gpu/perf/perf_calib3d.cpp +++ b/modules/gpu/perf/perf_calib3d.cpp @@ -15,22 +15,42 @@ PERF_TEST_P(ImagePair, Calib3D_StereoBM, Values(make_pair("gpu/p { declare.time(5.0); - cv::Mat imgLeft = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + const cv::Mat imgLeft = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(imgLeft.empty()); - cv::Mat imgRight = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + const cv::Mat imgRight = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(imgRight.empty()); - cv::gpu::StereoBM_GPU d_bm(0, 256); - cv::gpu::GpuMat d_imgLeft(imgLeft); - cv::gpu::GpuMat d_imgRight(imgRight); - cv::gpu::GpuMat d_dst; + const int preset = 0; + const int ndisp = 256; - d_bm(d_imgLeft, d_imgRight, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::StereoBM_GPU d_bm(preset, ndisp); + + cv::gpu::GpuMat d_imgLeft(imgLeft); + cv::gpu::GpuMat d_imgRight(imgRight); + cv::gpu::GpuMat d_dst; + d_bm(d_imgLeft, d_imgRight, d_dst); + + TEST_CYCLE() + { + d_bm(d_imgLeft, d_imgRight, d_dst); + } + } + else + { + cv::StereoBM bm(preset, ndisp); + + cv::Mat dst; + + bm(imgLeft, imgRight, dst); + + TEST_CYCLE() + { + bm(imgLeft, imgRight, dst); + } } } @@ -41,22 +61,32 @@ PERF_TEST_P(ImagePair, Calib3D_StereoBeliefPropagation, Values(make_pair("gpu/stereobm/aloe-L.png", "gpu/stereobm/aloe-disp.png"))) { - cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + const cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); - cv::Mat disp = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + const cv::Mat disp = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(disp.empty()); - cv::gpu::DisparityBilateralFilter d_filter(128); - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_disp(disp); - cv::gpu::GpuMat d_dst; + const int ndisp = 128; - d_filter(d_disp, d_img, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::DisparityBilateralFilter d_filter(ndisp); + + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_disp(disp); + cv::gpu::GpuMat d_dst; + d_filter(d_disp, d_img, d_dst); + + TEST_CYCLE() + { + d_filter(d_disp, d_img, d_dst); + } + } + else + { + FAIL(); } } @@ -117,22 +167,29 @@ DEF_PARAM_TEST_1(Count, int); PERF_TEST_P(Count, Calib3D_TransformPoints, Values(5000, 10000, 20000)) { - int count = GetParam(); + const int count = GetParam(); cv::Mat src(1, count, CV_32FC3); fillRandom(src, -100, 100); - cv::Mat rvec = cv::Mat::ones(1, 3, CV_32FC1); - cv::Mat tvec = cv::Mat::ones(1, 3, CV_32FC1); + const cv::Mat rvec = cv::Mat::ones(1, 3, CV_32FC1); + const cv::Mat tvec = cv::Mat::ones(1, 3, CV_32FC1); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::transformPoints(d_src, rvec, tvec, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::transformPoints(d_src, rvec, tvec, d_dst); + + TEST_CYCLE() + { + cv::gpu::transformPoints(d_src, rvec, tvec, d_dst); + } + } + else + { + FAIL(); } } @@ -141,23 +198,37 @@ PERF_TEST_P(Count, Calib3D_TransformPoints, Values(5000, 10000, 20000)) PERF_TEST_P(Count, Calib3D_ProjectPoints, Values(5000, 10000, 20000)) { - int count = GetParam(); + const int count = GetParam(); cv::Mat src(1, count, CV_32FC3); fillRandom(src, -100, 100); - cv::Mat rvec = cv::Mat::ones(1, 3, CV_32FC1); - cv::Mat tvec = cv::Mat::ones(1, 3, CV_32FC1); - cv::Mat camera_mat = cv::Mat::ones(3, 3, CV_32FC1); + const cv::Mat rvec = cv::Mat::ones(1, 3, CV_32FC1); + const cv::Mat tvec = cv::Mat::ones(1, 3, CV_32FC1); + const cv::Mat camera_mat = cv::Mat::ones(3, 3, CV_32FC1); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::projectPoints(d_src, rvec, tvec, camera_mat, cv::Mat(), d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::projectPoints(d_src, rvec, tvec, camera_mat, cv::Mat(), d_dst); + + TEST_CYCLE() + { + cv::gpu::projectPoints(d_src, rvec, tvec, camera_mat, cv::Mat(), d_dst); + } + } + else + { + cv::Mat dst; + + cv::projectPoints(src, rvec, tvec, camera_mat, cv::noArray(), dst); + + TEST_CYCLE() + { + cv::projectPoints(src, rvec, tvec, camera_mat, cv::noArray(), dst); + } } } @@ -166,9 +237,9 @@ PERF_TEST_P(Count, Calib3D_ProjectPoints, Values(5000, 10000, 20000)) PERF_TEST_P(Count, Calib3D_SolvePnPRansac, Values(5000, 10000, 20000)) { - declare.time(3.0); + declare.time(10.0); - int count = GetParam(); + const int count = GetParam(); cv::Mat object(1, count, CV_32FC3); fillRandom(object, -100, 100); @@ -180,7 +251,7 @@ PERF_TEST_P(Count, Calib3D_SolvePnPRansac, Values(5000, 10000, 20000)) camera_mat.at(2, 0) = 0.f; camera_mat.at(2, 1) = 0.f; - cv::Mat dist_coef(1, 8, CV_32F, cv::Scalar::all(0)); + const cv::Mat dist_coef(1, 8, CV_32F, cv::Scalar::all(0)); std::vector image_vec; cv::Mat rvec_gold(1, 3, CV_32FC1); @@ -194,11 +265,23 @@ PERF_TEST_P(Count, Calib3D_SolvePnPRansac, Values(5000, 10000, 20000)) cv::Mat rvec; cv::Mat tvec; - cv::gpu::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); - - TEST_CYCLE() + if (runOnGpu) { cv::gpu::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); + + TEST_CYCLE() + { + cv::gpu::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); + } + } + else + { + cv::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); + + TEST_CYCLE() + { + cv::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); + } } } @@ -207,8 +290,8 @@ PERF_TEST_P(Count, Calib3D_SolvePnPRansac, Values(5000, 10000, 20000)) PERF_TEST_P(Sz_Depth, Calib3D_ReprojectImageTo3D, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src, 5.0, 30.0); @@ -216,14 +299,28 @@ PERF_TEST_P(Sz_Depth, Calib3D_ReprojectImageTo3D, Combine(GPU_TYPICAL_MAT_SIZES, cv::Mat Q(4, 4, CV_32FC1); fillRandom(Q, 0.1, 1.0); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::reprojectImageTo3D(d_src, d_dst, Q); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::reprojectImageTo3D(d_src, d_dst, Q); + + TEST_CYCLE() + { + cv::gpu::reprojectImageTo3D(d_src, d_dst, Q); + } + } + else + { + cv::Mat dst; + + cv::reprojectImageTo3D(src, dst, Q); + + TEST_CYCLE() + { + cv::reprojectImageTo3D(src, dst, Q); + } } } @@ -232,20 +329,27 @@ PERF_TEST_P(Sz_Depth, Calib3D_ReprojectImageTo3D, Combine(GPU_TYPICAL_MAT_SIZES, PERF_TEST_P(Sz_Depth, Calib3D_DrawColorDisp, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S))) { - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); cv::Mat src(size, type); fillRandom(src, 0, 255); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::drawColorDisp(d_src, d_dst, 255); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::drawColorDisp(d_src, d_dst, 255); + + TEST_CYCLE() + { + cv::gpu::drawColorDisp(d_src, d_dst, 255); + } + } + else + { + FAIL(); } } diff --git a/modules/gpu/perf/perf_core.cpp b/modules/gpu/perf/perf_core.cpp index b56713a70e..90d0d831c9 100644 --- a/modules/gpu/perf/perf_core.cpp +++ b/modules/gpu/perf/perf_core.cpp @@ -12,21 +12,39 @@ namespace { PERF_TEST_P(Sz_Depth_Cn, Core_Merge, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, Values(2, 3, 4))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - std::vector d_src(channels); + std::vector src(channels); for (int i = 0; i < channels; ++i) - d_src[i] = cv::gpu::GpuMat(size, depth, cv::Scalar::all(i)); + src[i] = cv::Mat(size, depth, cv::Scalar::all(i)); - cv::gpu::GpuMat d_dst; - - cv::gpu::merge(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + std::vector d_src(channels); + for (int i = 0; i < channels; ++i) + d_src[i].upload(src[i]); + + cv::gpu::GpuMat d_dst; + cv::gpu::merge(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::merge(d_src, d_dst); + } + } + else + { + cv::Mat dst; + + cv::merge(src, dst); + + TEST_CYCLE() + { + cv::merge(src, dst); + } } } @@ -35,19 +53,35 @@ PERF_TEST_P(Sz_Depth_Cn, Core_Merge, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_D PERF_TEST_P(Sz_Depth_Cn, Core_Split, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, Values(2, 3, 4))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - cv::gpu::GpuMat d_src(size, CV_MAKE_TYPE(depth, channels), cv::Scalar(1, 2, 3, 4)); + cv::Mat src(size, CV_MAKE_TYPE(depth, channels), cv::Scalar(1, 2, 3, 4)); - std::vector d_dst; - - cv::gpu::split(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + + std::vector d_dst; + cv::gpu::split(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::split(d_src, d_dst); + } + } + else + { + std::vector dst; + + cv::split(src, dst); + + TEST_CYCLE() + { + cv::split(src, dst); + } } } @@ -56,8 +90,8 @@ PERF_TEST_P(Sz_Depth_Cn, Core_Split, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_D PERF_TEST_P(Sz_Depth, Core_AddMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src1(size, depth); fillRandom(src1); @@ -65,15 +99,29 @@ PERF_TEST_P(Sz_Depth, Core_AddMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEP cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::add(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::add(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::add(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::add(src1, src2, dst); + + TEST_CYCLE() + { + cv::add(src1, src2, dst); + } } } @@ -82,22 +130,36 @@ PERF_TEST_P(Sz_Depth, Core_AddMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEP PERF_TEST_P(Sz_Depth, Core_AddScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); cv::Scalar s(1, 2, 3, 4); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::add(d_src, s, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::add(d_src, s, d_dst); + + TEST_CYCLE() + { + cv::gpu::add(d_src, s, d_dst); + } + } + else + { + cv::Mat dst; + + cv::add(src, s, dst); + + TEST_CYCLE() + { + cv::add(src, s, dst); + } } } @@ -106,8 +168,8 @@ PERF_TEST_P(Sz_Depth, Core_AddScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_ PERF_TEST_P(Sz_Depth, Core_SubtractMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src1(size, depth); fillRandom(src1); @@ -115,15 +177,29 @@ PERF_TEST_P(Sz_Depth, Core_SubtractMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MA cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::subtract(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::subtract(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::subtract(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::subtract(src1, src2, dst); + + TEST_CYCLE() + { + cv::subtract(src1, src2, dst); + } } } @@ -132,22 +208,36 @@ PERF_TEST_P(Sz_Depth, Core_SubtractMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MA PERF_TEST_P(Sz_Depth, Core_SubtractScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); cv::Scalar s(1, 2, 3, 4); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::subtract(d_src, s, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::subtract(d_src, s, d_dst); + + TEST_CYCLE() + { + cv::gpu::subtract(d_src, s, d_dst); + } + } + else + { + cv::Mat dst; + + cv::subtract(src, s, dst); + + TEST_CYCLE() + { + cv::subtract(src, s, dst); + } } } @@ -156,8 +246,8 @@ PERF_TEST_P(Sz_Depth, Core_SubtractScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM PERF_TEST_P(Sz_Depth, Core_MultiplyMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src1(size, depth); fillRandom(src1); @@ -165,15 +255,29 @@ PERF_TEST_P(Sz_Depth, Core_MultiplyMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MA cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::multiply(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::multiply(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::multiply(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::multiply(src1, src2, dst); + + TEST_CYCLE() + { + cv::multiply(src1, src2, dst); + } } } @@ -182,22 +286,36 @@ PERF_TEST_P(Sz_Depth, Core_MultiplyMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MA PERF_TEST_P(Sz_Depth, Core_MultiplyScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); cv::Scalar s(1, 2, 3, 4); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::multiply(d_src, s, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::multiply(d_src, s, d_dst); + + TEST_CYCLE() + { + cv::gpu::multiply(d_src, s, d_dst); + } + } + else + { + cv::Mat dst; + + cv::multiply(src, s, dst); + + TEST_CYCLE() + { + cv::multiply(src, s, dst); + } } } @@ -206,8 +324,8 @@ PERF_TEST_P(Sz_Depth, Core_MultiplyScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM PERF_TEST_P(Sz_Depth, Core_DivideMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src1(size, depth); fillRandom(src1); @@ -215,15 +333,29 @@ PERF_TEST_P(Sz_Depth, Core_DivideMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_ cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::divide(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::divide(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::divide(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::divide(src1, src2, dst); + + TEST_CYCLE() + { + cv::divide(src1, src2, dst); + } } } @@ -232,22 +364,36 @@ PERF_TEST_P(Sz_Depth, Core_DivideMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_ PERF_TEST_P(Sz_Depth, Core_DivideScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); cv::Scalar s(1, 2, 3, 4); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::divide(d_src, s, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::divide(d_src, s, d_dst); + + TEST_CYCLE() + { + cv::gpu::divide(d_src, s, d_dst); + } + } + else + { + cv::Mat dst; + + cv::divide(src, s, dst); + + TEST_CYCLE() + { + cv::divide(src, s, dst); + } } } @@ -256,22 +402,36 @@ PERF_TEST_P(Sz_Depth, Core_DivideScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_M PERF_TEST_P(Sz_Depth, Core_DivideScalarInv, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); double s = 100.0; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::divide(s, d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::divide(s, d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::divide(s, d_src, d_dst); + } + } + else + { + cv::Mat dst; + + cv::divide(s, src, dst); + + TEST_CYCLE() + { + cv::divide(s, src, dst); + } } } @@ -280,8 +440,8 @@ PERF_TEST_P(Sz_Depth, Core_DivideScalarInv, Combine(GPU_TYPICAL_MAT_SIZES, ARITH PERF_TEST_P(Sz_Depth, Core_AbsDiffMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src1(size, depth); fillRandom(src1); @@ -289,15 +449,29 @@ PERF_TEST_P(Sz_Depth, Core_AbsDiffMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::absdiff(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::absdiff(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::absdiff(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::absdiff(src1, src2, dst); + + TEST_CYCLE() + { + cv::absdiff(src1, src2, dst); + } } } @@ -306,22 +480,36 @@ PERF_TEST_P(Sz_Depth, Core_AbsDiffMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT PERF_TEST_P(Sz_Depth, Core_AbsDiffScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); cv::Scalar s(1, 2, 3, 4); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::absdiff(d_src, s, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::absdiff(d_src, s, d_dst); + + TEST_CYCLE() + { + cv::gpu::absdiff(d_src, s, d_dst); + } + } + else + { + cv::Mat dst; + + cv::absdiff(src, s, dst); + + TEST_CYCLE() + { + cv::absdiff(src, s, dst); + } } } @@ -330,20 +518,27 @@ PERF_TEST_P(Sz_Depth, Core_AbsDiffScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_ PERF_TEST_P(Sz_Depth, Core_Abs, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_16S, CV_32F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::abs(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::abs(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::abs(d_src, d_dst); + } + } + else + { + FAIL(); } } @@ -352,20 +547,27 @@ PERF_TEST_P(Sz_Depth, Core_Abs, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_16S, CV PERF_TEST_P(Sz_Depth, Core_Sqr, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::sqr(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::sqr(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::sqr(d_src, d_dst); + } + } + else + { + FAIL(); } } @@ -374,20 +576,34 @@ PERF_TEST_P(Sz_Depth, Core_Sqr, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_ PERF_TEST_P(Sz_Depth, Core_Sqrt, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::sqrt(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::sqrt(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::sqrt(d_src, d_dst); + } + } + else + { + cv::Mat dst; + + cv::sqrt(src, dst); + + TEST_CYCLE() + { + cv::sqrt(src, dst); + } } } @@ -396,20 +612,34 @@ PERF_TEST_P(Sz_Depth, Core_Sqrt, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV PERF_TEST_P(Sz_Depth, Core_Log, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src, 1.0, 255.0); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::log(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::log(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::log(d_src, d_dst); + } + } + else + { + cv::Mat dst; + + cv::log(src, dst); + + TEST_CYCLE() + { + cv::log(src, dst); + } } } @@ -418,20 +648,34 @@ PERF_TEST_P(Sz_Depth, Core_Log, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_ PERF_TEST_P(Sz_Depth, Core_Exp, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src, 1.0, 10.0); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::exp(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::exp(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::exp(d_src, d_dst); + } + } + else + { + cv::Mat dst; + + cv::exp(src, dst); + + TEST_CYCLE() + { + cv::exp(src, dst); + } } } @@ -442,21 +686,35 @@ DEF_PARAM_TEST(Sz_Depth_Power, cv::Size, MatDepth, double); PERF_TEST_P(Sz_Depth_Power, Core_Pow, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F), Values(0.3, 2.0, 2.4))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - double power = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const double power = GET_PARAM(2); cv::Mat src(size, depth); fillRandom(src, 1.0, 10.0); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::pow(d_src, power, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::pow(d_src, power, d_dst); + + TEST_CYCLE() + { + cv::gpu::pow(d_src, power, d_dst); + } + } + else + { + cv::Mat dst; + + cv::pow(src, power, dst); + + TEST_CYCLE() + { + cv::pow(src, power, dst); + } } } @@ -470,9 +728,9 @@ DEF_PARAM_TEST(Sz_Depth_Code, cv::Size, MatDepth, CmpCode); PERF_TEST_P(Sz_Depth_Code, Core_CompareMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, ALL_CMP_CODES)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int cmp_code = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int cmp_code = GET_PARAM(2); cv::Mat src1(size, depth); fillRandom(src1); @@ -480,15 +738,29 @@ PERF_TEST_P(Sz_Depth_Code, Core_CompareMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITH cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::compare(d_src1, d_src2, d_dst, cmp_code); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::compare(d_src1, d_src2, d_dst, cmp_code); + + TEST_CYCLE() + { + cv::gpu::compare(d_src1, d_src2, d_dst, cmp_code); + } + } + else + { + cv::Mat dst; + + cv::compare(src1, src2, dst, cmp_code); + + TEST_CYCLE() + { + cv::compare(src1, src2, dst, cmp_code); + } } } @@ -497,23 +769,37 @@ PERF_TEST_P(Sz_Depth_Code, Core_CompareMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITH PERF_TEST_P(Sz_Depth_Code, Core_CompareScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, ALL_CMP_CODES)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int cmp_code = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int cmp_code = GET_PARAM(2); cv::Mat src(size, depth); fillRandom(src); cv::Scalar s = cv::Scalar::all(100); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::compare(d_src, s, d_dst, cmp_code); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::compare(d_src, s, d_dst, cmp_code); + + TEST_CYCLE() + { + cv::gpu::compare(d_src, s, d_dst, cmp_code); + } + } + else + { + cv::Mat dst; + + cv::compare(src, s, dst, cmp_code); + + TEST_CYCLE() + { + cv::compare(src, s, dst, cmp_code); + } } } @@ -522,20 +808,34 @@ PERF_TEST_P(Sz_Depth_Code, Core_CompareScalar, Combine(GPU_TYPICAL_MAT_SIZES, AR PERF_TEST_P(Sz_Depth, Core_BitwiseNot, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::bitwise_not(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::bitwise_not(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::bitwise_not(d_src, d_dst); + } + } + else + { + cv::Mat dst; + + cv::bitwise_not(src, dst); + + TEST_CYCLE() + { + cv::bitwise_not(src, dst); + } } } @@ -544,8 +844,8 @@ PERF_TEST_P(Sz_Depth, Core_BitwiseNot, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_ PERF_TEST_P(Sz_Depth, Core_BitwiseAndMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src1(size, depth); fillRandom(src1); @@ -553,15 +853,29 @@ PERF_TEST_P(Sz_Depth, Core_BitwiseAndMat, Combine(GPU_TYPICAL_MAT_SIZES, Values( cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::bitwise_and(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::bitwise_and(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::bitwise_and(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::bitwise_and(src1, src2, dst); + + TEST_CYCLE() + { + cv::bitwise_and(src1, src2, dst); + } } } @@ -570,25 +884,39 @@ PERF_TEST_P(Sz_Depth, Core_BitwiseAndMat, Combine(GPU_TYPICAL_MAT_SIZES, Values( PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseAndScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), Values(1, 3, 4))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); fillRandom(src); cv::Scalar s = cv::Scalar::all(100); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::bitwise_and(d_src, s, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::bitwise_and(d_src, s, d_dst); + + TEST_CYCLE() + { + cv::gpu::bitwise_and(d_src, s, d_dst); + } + } + else + { + cv::Mat dst; + + cv::bitwise_and(src, s, dst); + + TEST_CYCLE() + { + cv::bitwise_and(src, s, dst); + } } } @@ -597,8 +925,8 @@ PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseAndScalar, Combine(GPU_TYPICAL_MAT_SIZES, V PERF_TEST_P(Sz_Depth, Core_BitwiseOrMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src1(size, depth); fillRandom(src1); @@ -606,15 +934,29 @@ PERF_TEST_P(Sz_Depth, Core_BitwiseOrMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(C cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::bitwise_or(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::bitwise_or(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::bitwise_or(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::bitwise_or(src1, src2, dst); + + TEST_CYCLE() + { + cv::bitwise_or(src1, src2, dst); + } } } @@ -623,25 +965,39 @@ PERF_TEST_P(Sz_Depth, Core_BitwiseOrMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(C PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseOrScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), Values(1, 3, 4))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); fillRandom(src); cv::Scalar s = cv::Scalar::all(100); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::bitwise_or(d_src, s, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::bitwise_or(d_src, s, d_dst); + + TEST_CYCLE() + { + cv::gpu::bitwise_or(d_src, s, d_dst); + } + } + else + { + cv::Mat dst; + + cv::bitwise_or(src, s, dst); + + TEST_CYCLE() + { + cv::bitwise_or(src, s, dst); + } } } @@ -650,8 +1006,8 @@ PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseOrScalar, Combine(GPU_TYPICAL_MAT_SIZES, Va PERF_TEST_P(Sz_Depth, Core_BitwiseXorMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src1(size, depth); fillRandom(src1); @@ -659,15 +1015,29 @@ PERF_TEST_P(Sz_Depth, Core_BitwiseXorMat, Combine(GPU_TYPICAL_MAT_SIZES, Values( cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::bitwise_xor(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::bitwise_xor(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::bitwise_xor(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::bitwise_xor(src1, src2, dst); + + TEST_CYCLE() + { + cv::bitwise_xor(src1, src2, dst); + } } } @@ -676,25 +1046,39 @@ PERF_TEST_P(Sz_Depth, Core_BitwiseXorMat, Combine(GPU_TYPICAL_MAT_SIZES, Values( PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseXorScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), Values(1, 3, 4))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); fillRandom(src); cv::Scalar s = cv::Scalar::all(100); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::bitwise_xor(d_src, s, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::bitwise_xor(d_src, s, d_dst); + + TEST_CYCLE() + { + cv::gpu::bitwise_xor(d_src, s, d_dst); + } + } + else + { + cv::Mat dst; + + cv::bitwise_xor(src, s, dst); + + TEST_CYCLE() + { + cv::bitwise_xor(src, s, dst); + } } } @@ -703,25 +1087,32 @@ PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseXorScalar, Combine(GPU_TYPICAL_MAT_SIZES, V PERF_TEST_P(Sz_Depth_Cn, Core_RShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), Values(1, 3, 4))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); fillRandom(src); - cv::Scalar_ val = cv::Scalar_::all(4); + const cv::Scalar_ val = cv::Scalar_::all(4); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::rshift(d_src, val, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::rshift(d_src, val, d_dst); + + TEST_CYCLE() + { + cv::gpu::rshift(d_src, val, d_dst); + } + } + else + { + FAIL(); } } @@ -730,25 +1121,32 @@ PERF_TEST_P(Sz_Depth_Cn, Core_RShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8 PERF_TEST_P(Sz_Depth_Cn, Core_LShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), Values(1, 3, 4))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); fillRandom(src); - cv::Scalar_ val = cv::Scalar_::all(4); + const cv::Scalar_ val = cv::Scalar_::all(4); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::lshift(d_src, val, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::lshift(d_src, val, d_dst); + + TEST_CYCLE() + { + cv::gpu::lshift(d_src, val, d_dst); + } + } + else + { + FAIL(); } } @@ -757,8 +1155,8 @@ PERF_TEST_P(Sz_Depth_Cn, Core_LShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8 PERF_TEST_P(Sz_Depth, Core_MinMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src1(size, depth); fillRandom(src1); @@ -766,15 +1164,29 @@ PERF_TEST_P(Sz_Depth, Core_MinMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::min(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::min(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::min(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::min(src1, src2, dst); + + TEST_CYCLE() + { + cv::min(src1, src2, dst); + } } } @@ -783,22 +1195,36 @@ PERF_TEST_P(Sz_Depth, Core_MinMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, PERF_TEST_P(Sz_Depth, Core_MinScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); - double val = 50.0; + const double val = 50.0; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::min(d_src, val, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::min(d_src, val, d_dst); + + TEST_CYCLE() + { + cv::gpu::min(d_src, val, d_dst); + } + } + else + { + cv::Mat dst; + + cv::min(src, val, dst); + + TEST_CYCLE() + { + cv::min(src, val, dst); + } } } @@ -807,8 +1233,8 @@ PERF_TEST_P(Sz_Depth, Core_MinScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8 PERF_TEST_P(Sz_Depth, Core_MaxMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src1(size, depth); fillRandom(src1); @@ -816,15 +1242,29 @@ PERF_TEST_P(Sz_Depth, Core_MaxMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, cv::Mat src2(size, depth); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::max(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::max(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::max(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::max(src1, src2, dst); + + TEST_CYCLE() + { + cv::max(src1, src2, dst); + } } } @@ -833,22 +1273,36 @@ PERF_TEST_P(Sz_Depth, Core_MaxMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, PERF_TEST_P(Sz_Depth, Core_MaxScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); fillRandom(src); - double val = 50.0; + const double val = 50.0; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::max(d_src, val, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::max(d_src, val, d_dst); + + TEST_CYCLE() + { + cv::gpu::max(d_src, val, d_dst); + } + } + else + { + cv::Mat dst; + + cv::max(src, val, dst); + + TEST_CYCLE() + { + cv::max(src, val, dst); + } } } @@ -863,10 +1317,10 @@ PERF_TEST_P(Sz_3Depth, Core_AddWeighted, Combine( Values(CV_8U, CV_16U, CV_32F, CV_64F), Values(CV_8U, CV_16U, CV_32F, CV_64F))) { - cv::Size size = GET_PARAM(0); - int depth1 = GET_PARAM(1); - int depth2 = GET_PARAM(2); - int dst_depth = GET_PARAM(3); + const cv::Size size = GET_PARAM(0); + const int depth1 = GET_PARAM(1); + const int depth2 = GET_PARAM(2); + const int dst_depth = GET_PARAM(3); cv::Mat src1(size, depth1); fillRandom(src1); @@ -874,15 +1328,29 @@ PERF_TEST_P(Sz_3Depth, Core_AddWeighted, Combine( cv::Mat src2(size, depth2); fillRandom(src2); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::addWeighted(d_src1, 0.5, d_src2, 0.5, 10.0, d_dst, dst_depth); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::addWeighted(d_src1, 0.5, d_src2, 0.5, 10.0, d_dst, dst_depth); + + TEST_CYCLE() + { + cv::gpu::addWeighted(d_src1, 0.5, d_src2, 0.5, 10.0, d_dst, dst_depth); + } + } + else + { + cv::Mat dst; + + cv::addWeighted(src1, 0.5, src2, 0.5, 10.0, dst, dst_depth); + + TEST_CYCLE() + { + cv::addWeighted(src1, 0.5, src2, 0.5, 10.0, dst, dst_depth); + } } } @@ -901,9 +1369,9 @@ PERF_TEST_P(Sz_Type_Flags, Core_GEMM, Combine( { declare.time(5.0); - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); - int flags = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); + const int flags = GET_PARAM(2); cv::Mat src1(size, type); fillRandom(src1); @@ -914,16 +1382,32 @@ PERF_TEST_P(Sz_Type_Flags, Core_GEMM, Combine( cv::Mat src3(size, type); fillRandom(src3); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_src3(src3); - cv::gpu::GpuMat d_dst; - - cv::gpu::gemm(d_src1, d_src2, 1.0, d_src3, 1.0, d_dst, flags); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_src3(src3); + cv::gpu::GpuMat d_dst; + cv::gpu::gemm(d_src1, d_src2, 1.0, d_src3, 1.0, d_dst, flags); + + TEST_CYCLE() + { + cv::gpu::gemm(d_src1, d_src2, 1.0, d_src3, 1.0, d_dst, flags); + } + } + else + { + cv::Mat dst; + + cv::gemm(src1, src2, 1.0, src3, 1.0, dst, flags); + + declare.time(50.0); + + TEST_CYCLE() + { + cv::gemm(src1, src2, 1.0, src3, 1.0, dst, flags); + } } } @@ -940,14 +1424,28 @@ PERF_TEST_P(Sz_Type, Core_Transpose, Combine( cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::transpose(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::transpose(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::transpose(d_src, d_dst); + } + } + else + { + cv::Mat dst; + + cv::transpose(src, dst); + + TEST_CYCLE() + { + cv::transpose(src, dst); + } } } @@ -976,14 +1474,28 @@ PERF_TEST_P(Sz_Depth_Cn_Code, Core_Flip, Combine( cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::flip(d_src, d_dst, flipCode); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::flip(d_src, d_dst, flipCode); + + TEST_CYCLE() + { + cv::gpu::flip(d_src, d_dst, flipCode); + } + } + else + { + cv::Mat dst; + + cv::flip(src, dst, flipCode); + + TEST_CYCLE() + { + cv::flip(src, dst, flipCode); + } } } @@ -1003,14 +1515,28 @@ PERF_TEST_P(Sz_Type, Core_LutOneChannel, Combine( cv::Mat lut(1, 256, CV_8UC1); fillRandom(lut); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::LUT(d_src, lut, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::LUT(d_src, lut, d_dst); + + TEST_CYCLE() + { + cv::gpu::LUT(d_src, lut, d_dst); + } + } + else + { + cv::Mat dst; + + cv::LUT(src, lut, dst); + + TEST_CYCLE() + { + cv::LUT(src, lut, dst); + } } } @@ -1030,14 +1556,28 @@ PERF_TEST_P(Sz_Type, Core_LutMultiChannel, Combine( cv::Mat lut(1, 256, CV_MAKE_TYPE(CV_8U, src.channels())); fillRandom(lut); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::LUT(d_src, lut, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::LUT(d_src, lut, d_dst); + + TEST_CYCLE() + { + cv::gpu::LUT(d_src, lut, d_dst); + } + } + else + { + cv::Mat dst; + + cv::LUT(src, lut, dst); + + TEST_CYCLE() + { + cv::LUT(src, lut, dst); + } } } @@ -1051,14 +1591,31 @@ PERF_TEST_P(Sz, Core_MagnitudeComplex, GPU_TYPICAL_MAT_SIZES) cv::Mat src(size, CV_32FC2); fillRandom(src, -100.0, 100.0); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::magnitude(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::magnitude(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::magnitude(d_src, d_dst); + } + } + else + { + cv::Mat xy[2]; + cv::split(src, xy); + + cv::Mat dst; + + cv::magnitude(xy[0], xy[1], dst); + + TEST_CYCLE() + { + cv::magnitude(xy[0], xy[1], dst); + } } } @@ -1072,14 +1629,21 @@ PERF_TEST_P(Sz, Core_MagnitudeSqrComplex, GPU_TYPICAL_MAT_SIZES) cv::Mat src(size, CV_32FC2); fillRandom(src, -100.0, 100.0); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::magnitudeSqr(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::magnitudeSqr(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::magnitudeSqr(d_src, d_dst); + } + } + else + { + FAIL(); } } @@ -1096,15 +1660,29 @@ PERF_TEST_P(Sz, Core_Magnitude, GPU_TYPICAL_MAT_SIZES) cv::Mat src2(size, CV_32FC1); fillRandom(src2, -100.0, 100.0); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::magnitude(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::magnitude(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::magnitude(d_src1, d_src2, d_dst); + } + } + else + { + cv::Mat dst; + + cv::magnitude(src1, src2, dst); + + TEST_CYCLE() + { + cv::magnitude(src1, src2, dst); + } } } @@ -1121,15 +1699,22 @@ PERF_TEST_P(Sz, Core_MagnitudeSqr, GPU_TYPICAL_MAT_SIZES) cv::Mat src2(size, CV_32FC1); fillRandom(src2, -100.0, 100.0); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::magnitudeSqr(d_src1, d_src2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::magnitudeSqr(d_src1, d_src2, d_dst); + + TEST_CYCLE() + { + cv::gpu::magnitudeSqr(d_src1, d_src2, d_dst); + } + } + else + { + FAIL(); } } @@ -1149,15 +1734,29 @@ PERF_TEST_P(Sz_AngleInDegrees, Core_Phase, Combine(GPU_TYPICAL_MAT_SIZES, Bool() cv::Mat src2(size, CV_32FC1); fillRandom(src2, -100.0, 100.0); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::phase(d_src1, d_src2, d_dst, angleInDegrees); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::phase(d_src1, d_src2, d_dst, angleInDegrees); + + TEST_CYCLE() + { + cv::gpu::phase(d_src1, d_src2, d_dst, angleInDegrees); + } + } + else + { + cv::Mat dst; + + cv::phase(src1, src2, dst, angleInDegrees); + + TEST_CYCLE() + { + cv::phase(src1, src2, dst, angleInDegrees); + } } } @@ -1175,16 +1774,31 @@ PERF_TEST_P(Sz_AngleInDegrees, Core_CartToPolar, Combine(GPU_TYPICAL_MAT_SIZES, cv::Mat src2(size, CV_32FC1); fillRandom(src2, -100.0, 100.0); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_magnitude; - cv::gpu::GpuMat d_angle; - - cv::gpu::cartToPolar(d_src1, d_src2, d_magnitude, d_angle, angleInDegrees); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_magnitude; + cv::gpu::GpuMat d_angle; + cv::gpu::cartToPolar(d_src1, d_src2, d_magnitude, d_angle, angleInDegrees); + + TEST_CYCLE() + { + cv::gpu::cartToPolar(d_src1, d_src2, d_magnitude, d_angle, angleInDegrees); + } + } + else + { + cv::Mat magnitude; + cv::Mat angle; + + cv::cartToPolar(src1, src2, magnitude, angle, angleInDegrees); + + TEST_CYCLE() + { + cv::cartToPolar(src1, src2, magnitude, angle, angleInDegrees); + } } } @@ -1202,16 +1816,31 @@ PERF_TEST_P(Sz_AngleInDegrees, Core_PolarToCart, Combine(GPU_TYPICAL_MAT_SIZES, cv::Mat angle(size, CV_32FC1); fillRandom(angle, 0.0, angleInDegrees ? 360.0 : 2 * CV_PI); - cv::gpu::GpuMat d_magnitude(magnitude); - cv::gpu::GpuMat d_angle(angle); - cv::gpu::GpuMat d_x; - cv::gpu::GpuMat d_y; - - cv::gpu::polarToCart(d_magnitude, d_angle, d_x, d_y, angleInDegrees); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_magnitude(magnitude); + cv::gpu::GpuMat d_angle(angle); + cv::gpu::GpuMat d_x; + cv::gpu::GpuMat d_y; + cv::gpu::polarToCart(d_magnitude, d_angle, d_x, d_y, angleInDegrees); + + TEST_CYCLE() + { + cv::gpu::polarToCart(d_magnitude, d_angle, d_x, d_y, angleInDegrees); + } + } + else + { + cv::Mat x; + cv::Mat y; + + cv::polarToCart(magnitude, angle, x, y, angleInDegrees); + + TEST_CYCLE() + { + cv::polarToCart(magnitude, angle, x, y, angleInDegrees); + } } } @@ -1228,14 +1857,26 @@ PERF_TEST_P(Sz, Core_MeanStdDev, GPU_TYPICAL_MAT_SIZES) cv::Scalar mean; cv::Scalar stddev; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_buf; - - cv::gpu::meanStdDev(d_src, mean, stddev, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + cv::gpu::meanStdDev(d_src, mean, stddev, d_buf); + + TEST_CYCLE() + { + cv::gpu::meanStdDev(d_src, mean, stddev, d_buf); + } + } + else + { + cv::meanStdDev(src, mean, stddev); + + TEST_CYCLE() + { + cv::meanStdDev(src, mean, stddev); + } } } @@ -1258,14 +1899,26 @@ PERF_TEST_P(Sz_Depth_Norm, Core_Norm, Combine( double dst; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_buf; - - dst = cv::gpu::norm(d_src, normType, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + dst = cv::gpu::norm(d_src, normType, d_buf); + + TEST_CYCLE() + { + dst = cv::gpu::norm(d_src, normType, d_buf); + } + } + else + { + dst = cv::norm(src, normType); + + TEST_CYCLE() + { + dst = cv::norm(src, normType); + } } } @@ -1289,14 +1942,26 @@ PERF_TEST_P(Sz_Norm, Core_NormDiff, Combine( double dst; - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - - dst = cv::gpu::norm(d_src1, d_src2, normType); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + dst = cv::gpu::norm(d_src1, d_src2, normType); + + TEST_CYCLE() + { + dst = cv::gpu::norm(d_src1, d_src2, normType); + } + } + else + { + dst = cv::norm(src1, src2, normType); + + TEST_CYCLE() + { + dst = cv::norm(src1, src2, normType); + } } } @@ -1319,14 +1984,26 @@ PERF_TEST_P(Sz_Depth_Cn, Core_Sum, Combine( cv::Scalar dst; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_buf; - - dst = cv::gpu::sum(d_src, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + dst = cv::gpu::sum(d_src, d_buf); + + TEST_CYCLE() + { + dst = cv::gpu::sum(d_src, d_buf); + } + } + else + { + dst = cv::sum(src); + + TEST_CYCLE() + { + dst = cv::sum(src); + } } } @@ -1349,14 +2026,21 @@ PERF_TEST_P(Sz_Depth_Cn, Core_SumAbs, Combine( cv::Scalar dst; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_buf; - - dst = cv::gpu::absSum(d_src, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + dst = cv::gpu::absSum(d_src, d_buf); + + TEST_CYCLE() + { + dst = cv::gpu::absSum(d_src, d_buf); + } + } + else + { + FAIL(); } } @@ -1379,14 +2063,21 @@ PERF_TEST_P(Sz_Depth_Cn, Core_SumSqr, Combine( cv::Scalar dst; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_buf; - - dst = cv::gpu::sqrSum(d_src, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + dst = cv::gpu::sqrSum(d_src, d_buf); + + TEST_CYCLE() + { + dst = cv::gpu::sqrSum(d_src, d_buf); + } + } + else + { + FAIL(); } } @@ -1405,14 +2096,21 @@ PERF_TEST_P(Sz_Depth, Core_MinMax, Combine( double minVal, maxVal; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_buf; - - cv::gpu::minMax(d_src, &minVal, &maxVal, cv::gpu::GpuMat(), d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + cv::gpu::minMax(d_src, &minVal, &maxVal, cv::gpu::GpuMat(), d_buf); + + TEST_CYCLE() + { + cv::gpu::minMax(d_src, &minVal, &maxVal, cv::gpu::GpuMat(), d_buf); + } + } + else + { + FAIL(); } } @@ -1432,14 +2130,26 @@ PERF_TEST_P(Sz_Depth, Core_MinMaxLoc, Combine( double minVal, maxVal; cv::Point minLoc, maxLoc; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_valbuf, d_locbuf; - - cv::gpu::minMaxLoc(d_src, &minVal, &maxVal, &minLoc, &maxLoc, cv::gpu::GpuMat(), d_valbuf, d_locbuf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_valbuf, d_locbuf; + cv::gpu::minMaxLoc(d_src, &minVal, &maxVal, &minLoc, &maxLoc, cv::gpu::GpuMat(), d_valbuf, d_locbuf); + + TEST_CYCLE() + { + cv::gpu::minMaxLoc(d_src, &minVal, &maxVal, &minLoc, &maxLoc, cv::gpu::GpuMat(), d_valbuf, d_locbuf); + } + } + else + { + cv::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc); + + TEST_CYCLE() + { + cv::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc); + } } } @@ -1458,14 +2168,26 @@ PERF_TEST_P(Sz_Depth, Core_CountNonZero, Combine( int dst; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_buf; - - dst = cv::gpu::countNonZero(d_src, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_buf; + dst = cv::gpu::countNonZero(d_src, d_buf); + + TEST_CYCLE() + { + dst = cv::gpu::countNonZero(d_src, d_buf); + } + } + else + { + dst = cv::countNonZero(src); + + TEST_CYCLE() + { + dst = cv::countNonZero(src); + } } } @@ -1499,14 +2221,28 @@ PERF_TEST_P(Sz_Depth_Cn_Code_Dim, Core_Reduce, Combine( cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::reduce(d_src, d_dst, dim, reduceOp); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::reduce(d_src, d_dst, dim, reduceOp); + + TEST_CYCLE() + { + cv::gpu::reduce(d_src, d_dst, dim, reduceOp); + } + } + else + { + cv::Mat dst; + + cv::reduce(src, dst, dim, reduceOp); + + TEST_CYCLE() + { + cv::reduce(src, dst, dim, reduceOp); + } } } diff --git a/modules/gpu/perf/perf_features2d.cpp b/modules/gpu/perf/perf_features2d.cpp index ef9612b549..53b98d4628 100644 --- a/modules/gpu/perf/perf_features2d.cpp +++ b/modules/gpu/perf/perf_features2d.cpp @@ -12,21 +12,39 @@ DEF_PARAM_TEST_1(Image, string); PERF_TEST_P(Image, Features2D_SURF, Values("gpu/perf/aloe.jpg")) { - declare.time(2.0); + declare.time(50.0); cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); - cv::gpu::SURF_GPU d_surf; - - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_keypoints, d_descriptors; - - d_surf(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::SURF_GPU d_surf; + + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_keypoints, d_descriptors; + d_surf(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); + + TEST_CYCLE() + { + d_surf(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); + } + } + else + { + cv::SURF surf; + + std::vector keypoints; + cv::Mat descriptors; + + surf(img, cv::noArray(), keypoints, descriptors); + + TEST_CYCLE() + { + keypoints.clear(); + surf(img, cv::noArray(), keypoints, descriptors); + } } } @@ -38,16 +56,31 @@ PERF_TEST_P(Image, Features2D_FAST, Values("gpu/perf/aloe.jpg")) cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); - cv::gpu::FAST_GPU d_fast(20); - - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_keypoints; - - d_fast(d_img, cv::gpu::GpuMat(), d_keypoints); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::FAST_GPU d_fast(20); + + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_keypoints; + d_fast(d_img, cv::gpu::GpuMat(), d_keypoints); + + TEST_CYCLE() + { + d_fast(d_img, cv::gpu::GpuMat(), d_keypoints); + } + } + else + { + std::vector keypoints; + + cv::FAST(img, keypoints, 20); + + TEST_CYCLE() + { + keypoints.clear(); + cv::FAST(img, keypoints, 20); + } } } @@ -59,16 +92,34 @@ PERF_TEST_P(Image, Features2D_ORB, Values("gpu/perf/aloe.jpg")) cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); - cv::gpu::ORB_GPU d_orb(4000); - - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_keypoints, d_descriptors; - - d_orb(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::ORB_GPU d_orb(4000); + + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_keypoints, d_descriptors; + d_orb(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); + + TEST_CYCLE() + { + d_orb(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); + } + } + else + { + cv::ORB orb(4000); + + std::vector keypoints; + cv::Mat descriptors; + + orb(img, cv::noArray(), keypoints, descriptors); + + TEST_CYCLE() + { + keypoints.clear(); + orb(img, cv::noArray(), keypoints, descriptors); + } } } @@ -79,7 +130,7 @@ DEF_PARAM_TEST(DescSize_Norm, int, NormType); PERF_TEST_P(DescSize_Norm, Features2D_BFMatch, Combine(Values(64, 128, 256), Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))) { - declare.time(3.0); + declare.time(20.0); int desc_size = GET_PARAM(0); int normType = GET_PARAM(1); @@ -92,17 +143,33 @@ PERF_TEST_P(DescSize_Norm, Features2D_BFMatch, Combine(Values(64, 128, 256), Val cv::Mat train(3000, desc_size, type); fillRandom(train); - cv::gpu::BFMatcher_GPU d_matcher(normType); - - cv::gpu::GpuMat d_query(query); - cv::gpu::GpuMat d_train(train); - cv::gpu::GpuMat d_trainIdx, d_distance; - - d_matcher.matchSingle(d_query, d_train, d_trainIdx, d_distance); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::BFMatcher_GPU d_matcher(normType); + + cv::gpu::GpuMat d_query(query); + cv::gpu::GpuMat d_train(train); + cv::gpu::GpuMat d_trainIdx, d_distance; + d_matcher.matchSingle(d_query, d_train, d_trainIdx, d_distance); + + TEST_CYCLE() + { + d_matcher.matchSingle(d_query, d_train, d_trainIdx, d_distance); + } + } + else + { + cv::BFMatcher matcher(normType); + + std::vector matches; + + matcher.match(query, train, matches); + + TEST_CYCLE() + { + matcher.match(query, train, matches); + } } } @@ -116,7 +183,7 @@ PERF_TEST_P(DescSize_K_Norm, Features2D_BFKnnMatch, Combine( Values(2, 3), Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))) { - declare.time(3.0); + declare.time(30.0); int desc_size = GET_PARAM(0); int k = GET_PARAM(1); @@ -130,17 +197,33 @@ PERF_TEST_P(DescSize_K_Norm, Features2D_BFKnnMatch, Combine( cv::Mat train(3000, desc_size, type); fillRandom(train); - cv::gpu::BFMatcher_GPU d_matcher(normType); - - cv::gpu::GpuMat d_query(query); - cv::gpu::GpuMat d_train(train); - cv::gpu::GpuMat d_trainIdx, d_distance, d_allDist; - - d_matcher.knnMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_allDist, k); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::BFMatcher_GPU d_matcher(normType); + + cv::gpu::GpuMat d_query(query); + cv::gpu::GpuMat d_train(train); + cv::gpu::GpuMat d_trainIdx, d_distance, d_allDist; + d_matcher.knnMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_allDist, k); + + TEST_CYCLE() + { + d_matcher.knnMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_allDist, k); + } + } + else + { + cv::BFMatcher matcher(normType); + + std::vector< std::vector > matches; + + matcher.knnMatch(query, train, matches, k); + + TEST_CYCLE() + { + matcher.knnMatch(query, train, matches, k); + } } } @@ -149,7 +232,7 @@ PERF_TEST_P(DescSize_K_Norm, Features2D_BFKnnMatch, Combine( PERF_TEST_P(DescSize_Norm, Features2D_BFRadiusMatch, Combine(Values(64, 128, 256), Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))) { - declare.time(3.0); + declare.time(30.0); int desc_size = GET_PARAM(0); int normType = GET_PARAM(1); @@ -162,17 +245,33 @@ PERF_TEST_P(DescSize_Norm, Features2D_BFRadiusMatch, Combine(Values(64, 128, 256 cv::Mat train(3000, desc_size, type); fillRandom(train, 0.0, 1.0); - cv::gpu::BFMatcher_GPU d_matcher(normType); - - cv::gpu::GpuMat d_query(query); - cv::gpu::GpuMat d_train(train); - cv::gpu::GpuMat d_trainIdx, d_nMatches, d_distance; - - d_matcher.radiusMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_nMatches, 2.0); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::BFMatcher_GPU d_matcher(normType); + + cv::gpu::GpuMat d_query(query); + cv::gpu::GpuMat d_train(train); + cv::gpu::GpuMat d_trainIdx, d_nMatches, d_distance; + d_matcher.radiusMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_nMatches, 2.0); + + TEST_CYCLE() + { + d_matcher.radiusMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_nMatches, 2.0); + } + } + else + { + cv::BFMatcher matcher(normType); + + std::vector< std::vector > matches; + + matcher.radiusMatch(query, train, matches, 2.0); + + TEST_CYCLE() + { + matcher.radiusMatch(query, train, matches, 2.0); + } } } diff --git a/modules/gpu/perf/perf_filters.cpp b/modules/gpu/perf/perf_filters.cpp index 71dcd49e2b..64ab829f8e 100644 --- a/modules/gpu/perf/perf_filters.cpp +++ b/modules/gpu/perf/perf_filters.cpp @@ -12,6 +12,8 @@ DEF_PARAM_TEST(Sz_Type_KernelSz, cv::Size, MatType, int); PERF_TEST_P(Sz_Type_KernelSz, Filters_Blur, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4), Values(3, 5, 7))) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int type = GET_PARAM(1); int ksize = GET_PARAM(2); @@ -19,14 +21,28 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_Blur, Combine(GPU_TYPICAL_MAT_SIZES, Value cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::blur(d_src, d_dst, cv::Size(ksize, ksize)); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::blur(d_src, d_dst, cv::Size(ksize, ksize)); + + TEST_CYCLE() + { + cv::gpu::blur(d_src, d_dst, cv::Size(ksize, ksize)); + } + } + else + { + cv::Mat dst; + + cv::blur(src, dst, cv::Size(ksize, ksize)); + + TEST_CYCLE() + { + cv::blur(src, dst, cv::Size(ksize, ksize)); + } } } @@ -35,6 +51,8 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_Blur, Combine(GPU_TYPICAL_MAT_SIZES, Value PERF_TEST_P(Sz_Type_KernelSz, Filters_Sobel, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4, CV_32FC1), Values(3, 5, 7, 9, 11, 13, 15))) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int type = GET_PARAM(1); int ksize = GET_PARAM(2); @@ -42,15 +60,29 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_Sobel, Combine(GPU_TYPICAL_MAT_SIZES, Valu cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat d_buf; - - cv::gpu::Sobel(d_src, d_dst, -1, 1, 1, d_buf, ksize); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; + cv::gpu::Sobel(d_src, d_dst, -1, 1, 1, d_buf, ksize); + + TEST_CYCLE() + { + cv::gpu::Sobel(d_src, d_dst, -1, 1, 1, d_buf, ksize); + } + } + else + { + cv::Mat dst; + + cv::Sobel(src, dst, -1, 1, 1, ksize); + + TEST_CYCLE() + { + cv::Sobel(src, dst, -1, 1, 1, ksize); + } } } @@ -59,21 +91,37 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_Sobel, Combine(GPU_TYPICAL_MAT_SIZES, Valu PERF_TEST_P(Sz_Type, Filters_Scharr, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4, CV_32FC1))) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int type = GET_PARAM(1); cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat d_buf; - - cv::gpu::Scharr(d_src, d_dst, -1, 1, 0, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; + cv::gpu::Scharr(d_src, d_dst, -1, 1, 0, d_buf); + + TEST_CYCLE() + { + cv::gpu::Scharr(d_src, d_dst, -1, 1, 0, d_buf); + } + } + else + { + cv::Mat dst; + + cv::Scharr(src, dst, -1, 1, 0); + + TEST_CYCLE() + { + cv::Scharr(src, dst, -1, 1, 0); + } } } @@ -82,6 +130,8 @@ PERF_TEST_P(Sz_Type, Filters_Scharr, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U PERF_TEST_P(Sz_Type_KernelSz, Filters_GaussianBlur, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4, CV_32FC1), Values(3, 5, 7, 9, 11, 13, 15))) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int type = GET_PARAM(1); int ksize = GET_PARAM(2); @@ -89,15 +139,29 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_GaussianBlur, Combine(GPU_TYPICAL_MAT_SIZE cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat d_buf; - - cv::gpu::GaussianBlur(d_src, d_dst, cv::Size(ksize, ksize), d_buf, 0.5); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; + cv::gpu::GaussianBlur(d_src, d_dst, cv::Size(ksize, ksize), d_buf, 0.5); + + TEST_CYCLE() + { + cv::gpu::GaussianBlur(d_src, d_dst, cv::Size(ksize, ksize), d_buf, 0.5); + } + } + else + { + cv::Mat dst; + + cv::GaussianBlur(src, dst, cv::Size(ksize, ksize), 0.5); + + TEST_CYCLE() + { + cv::GaussianBlur(src, dst, cv::Size(ksize, ksize), 0.5); + } } } @@ -106,6 +170,8 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_GaussianBlur, Combine(GPU_TYPICAL_MAT_SIZE PERF_TEST_P(Sz_Type_KernelSz, Filters_Laplacian, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4), Values(1, 3))) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int type = GET_PARAM(1); int ksize = GET_PARAM(2); @@ -113,14 +179,28 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_Laplacian, Combine(GPU_TYPICAL_MAT_SIZES, cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::Laplacian(d_src, d_dst, -1, ksize); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::Laplacian(d_src, d_dst, -1, ksize); + + TEST_CYCLE() + { + cv::gpu::Laplacian(d_src, d_dst, -1, ksize); + } + } + else + { + cv::Mat dst; + + cv::Laplacian(src, dst, -1, ksize); + + TEST_CYCLE() + { + cv::Laplacian(src, dst, -1, ksize); + } } } @@ -129,6 +209,8 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_Laplacian, Combine(GPU_TYPICAL_MAT_SIZES, PERF_TEST_P(Sz_Type, Filters_Erode, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4))) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int type = GET_PARAM(1); @@ -137,15 +219,29 @@ PERF_TEST_P(Sz_Type, Filters_Erode, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat d_buf; - - cv::gpu::erode(d_src, d_dst, ker, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; + cv::gpu::erode(d_src, d_dst, ker, d_buf); + + TEST_CYCLE() + { + cv::gpu::erode(d_src, d_dst, ker, d_buf); + } + } + else + { + cv::Mat dst; + + cv::erode(src, dst, ker); + + TEST_CYCLE() + { + cv::erode(src, dst, ker); + } } } @@ -154,6 +250,8 @@ PERF_TEST_P(Sz_Type, Filters_Erode, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC PERF_TEST_P(Sz_Type, Filters_Dilate, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4))) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int type = GET_PARAM(1); @@ -162,15 +260,29 @@ PERF_TEST_P(Sz_Type, Filters_Dilate, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat d_buf; - - cv::gpu::dilate(d_src, d_dst, ker, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; + cv::gpu::dilate(d_src, d_dst, ker, d_buf); + + TEST_CYCLE() + { + cv::gpu::dilate(d_src, d_dst, ker, d_buf); + } + } + else + { + cv::Mat dst; + + cv::dilate(src, dst, ker); + + TEST_CYCLE() + { + cv::dilate(src, dst, ker); + } } } @@ -184,6 +296,8 @@ DEF_PARAM_TEST(Sz_Type_Op, cv::Size, MatType, MorphOp); PERF_TEST_P(Sz_Type_Op, Filters_MorphologyEx, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4), ALL_MORPH_OPS)) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int type = GET_PARAM(1); int morphOp = GET_PARAM(2); @@ -193,16 +307,30 @@ PERF_TEST_P(Sz_Type_Op, Filters_MorphologyEx, Combine(GPU_TYPICAL_MAT_SIZES, Val cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat d_buf1; - cv::gpu::GpuMat d_buf2; - - cv::gpu::morphologyEx(d_src, d_dst, morphOp, ker, d_buf1, d_buf2); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf1; + cv::gpu::GpuMat d_buf2; + cv::gpu::morphologyEx(d_src, d_dst, morphOp, ker, d_buf1, d_buf2); + + TEST_CYCLE() + { + cv::gpu::morphologyEx(d_src, d_dst, morphOp, ker, d_buf1, d_buf2); + } + } + else + { + cv::Mat dst; + + cv::morphologyEx(src, dst, morphOp, ker); + + TEST_CYCLE() + { + cv::morphologyEx(src, dst, morphOp, ker); + } } } @@ -211,6 +339,8 @@ PERF_TEST_P(Sz_Type_Op, Filters_MorphologyEx, Combine(GPU_TYPICAL_MAT_SIZES, Val PERF_TEST_P(Sz_Type_KernelSz, Filters_Filter2D, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4), Values(3, 5, 7, 9, 11, 13, 15))) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int type = GET_PARAM(1); int ksize = GET_PARAM(2); @@ -221,14 +351,28 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_Filter2D, Combine(GPU_TYPICAL_MAT_SIZES, V cv::Mat kernel(ksize, ksize, CV_32FC1); fillRandom(kernel, 0.0, 1.0); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::filter2D(d_src, d_dst, -1, kernel); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::filter2D(d_src, d_dst, -1, kernel); + + TEST_CYCLE() + { + cv::gpu::filter2D(d_src, d_dst, -1, kernel); + } + } + else + { + cv::Mat dst; + + cv::filter2D(src, dst, -1, kernel); + + TEST_CYCLE() + { + cv::filter2D(src, dst, -1, kernel); + } } } diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index a1614a79f3..9104892db4 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -59,7 +59,7 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Border_Mode, ImgProc_Remap, Combine( ALL_BORDER_MODES, ALL_REMAP_MODES)) { - declare.time(3.0); + declare.time(20.0); cv::Size size = GET_PARAM(0); int depth = GET_PARAM(1); @@ -78,16 +78,30 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Border_Mode, ImgProc_Remap, Combine( generateMap(xmap, ymap, remapMode); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_xmap(xmap); - cv::gpu::GpuMat d_ymap(ymap); - cv::gpu::GpuMat d_dst; - - cv::gpu::remap(d_src, d_dst, d_xmap, d_ymap, interpolation, borderMode); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_xmap(xmap); + cv::gpu::GpuMat d_ymap(ymap); + cv::gpu::GpuMat d_dst; + cv::gpu::remap(d_src, d_dst, d_xmap, d_ymap, interpolation, borderMode); + + TEST_CYCLE() + { + cv::gpu::remap(d_src, d_dst, d_xmap, d_ymap, interpolation, borderMode); + } + } + else + { + cv::Mat dst; + + cv::remap(src, dst, xmap, ymap, interpolation, borderMode); + + TEST_CYCLE() + { + cv::remap(src, dst, xmap, ymap, interpolation, borderMode); + } } } @@ -103,7 +117,7 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Scale, ImgProc_Resize, Combine( ALL_INTERPOLATIONS, Values(0.5, 0.3, 2.0))) { - declare.time(1.0); + declare.time(20.0); cv::Size size = GET_PARAM(0); int depth = GET_PARAM(1); @@ -116,14 +130,28 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Scale, ImgProc_Resize, Combine( cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); + + TEST_CYCLE() + { + cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); + } + } + else + { + cv::Mat dst; + + cv::resize(src, dst, cv::Size(), f, f, interpolation); + + TEST_CYCLE() + { + cv::resize(src, dst, cv::Size(), f, f, interpolation); + } } } @@ -151,14 +179,28 @@ PERF_TEST_P(Sz_Depth_Cn_Scale, ImgProc_ResizeArea, Combine( cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); + + TEST_CYCLE() + { + cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); + } + } + else + { + cv::Mat dst; + + cv::resize(src, dst, cv::Size(), f, f, interpolation); + + TEST_CYCLE() + { + cv::resize(src, dst, cv::Size(), f, f, interpolation); + } } } @@ -174,6 +216,8 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpAffine, Combine( Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), ALL_BORDER_MODES)) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int depth = GET_PARAM(1); int channels = GET_PARAM(2); @@ -190,14 +234,28 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpAffine, Combine( {std::sin(aplha), std::cos(aplha), 0}}; cv::Mat M(2, 3, CV_64F, (void*) mat); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::warpAffine(d_src, d_dst, M, size, interpolation, borderMode); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::warpAffine(d_src, d_dst, M, size, interpolation, borderMode); + + TEST_CYCLE() + { + cv::gpu::warpAffine(d_src, d_dst, M, size, interpolation, borderMode); + } + } + else + { + cv::Mat dst; + + cv::warpAffine(src, dst, M, size, interpolation, borderMode); + + TEST_CYCLE() + { + cv::warpAffine(src, dst, M, size, interpolation, borderMode); + } } } @@ -211,6 +269,8 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpPerspective, Combine( Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), ALL_BORDER_MODES)) { + declare.time(20.0); + cv::Size size = GET_PARAM(0); int depth = GET_PARAM(1); int channels = GET_PARAM(2); @@ -228,14 +288,28 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpPerspective, Combine( {0.0, 0.0, 1.0}}; cv::Mat M(3, 3, CV_64F, (void*) mat); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::warpPerspective(d_src, d_dst, M, size, interpolation, borderMode); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::warpPerspective(d_src, d_dst, M, size, interpolation, borderMode); + + TEST_CYCLE() + { + cv::gpu::warpPerspective(d_src, d_dst, M, size, interpolation, borderMode); + } + } + else + { + cv::Mat dst; + + cv::warpPerspective(src, dst, M, size, interpolation, borderMode); + + TEST_CYCLE() + { + cv::warpPerspective(src, dst, M, size, interpolation, borderMode); + } } } @@ -260,14 +334,28 @@ PERF_TEST_P(Sz_Depth_Cn_Border, ImgProc_CopyMakeBorder, Combine( cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::copyMakeBorder(d_src, d_dst, 5, 5, 5, 5, borderMode); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::copyMakeBorder(d_src, d_dst, 5, 5, 5, 5, borderMode); + + TEST_CYCLE() + { + cv::gpu::copyMakeBorder(d_src, d_dst, 5, 5, 5, 5, borderMode); + } + } + else + { + cv::Mat dst; + + cv::copyMakeBorder(src, dst, 5, 5, 5, 5, borderMode); + + TEST_CYCLE() + { + cv::copyMakeBorder(src, dst, 5, 5, 5, 5, borderMode); + } } } @@ -291,14 +379,28 @@ PERF_TEST_P(Sz_Depth_Op, ImgProc_Threshold, Combine( cv::Mat src(size, depth); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::threshold(d_src, d_dst, 100.0, 255.0, threshOp); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::threshold(d_src, d_dst, 100.0, 255.0, threshOp); + + TEST_CYCLE() + { + cv::gpu::threshold(d_src, d_dst, 100.0, 255.0, threshOp); + } + } + else + { + cv::Mat dst; + + cv::threshold(src, dst, 100.0, 255.0, threshOp); + + TEST_CYCLE() + { + cv::threshold(src, dst, 100.0, 255.0, threshOp); + } } } @@ -312,15 +414,29 @@ PERF_TEST_P(Sz, ImgProc_Integral, GPU_TYPICAL_MAT_SIZES) cv::Mat src(size, CV_8UC1); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat d_buf; - - cv::gpu::integralBuffered(d_src, d_dst, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_buf; + cv::gpu::integralBuffered(d_src, d_dst, d_buf); + + TEST_CYCLE() + { + cv::gpu::integralBuffered(d_src, d_dst, d_buf); + } + } + else + { + cv::Mat dst; + + cv::integral(src, dst); + + TEST_CYCLE() + { + cv::integral(src, dst); + } } } @@ -334,14 +450,21 @@ PERF_TEST_P(Sz, ImgProc_IntegralSqr, GPU_TYPICAL_MAT_SIZES) cv::Mat src(size, CV_8UC1); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::sqrIntegral(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::sqrIntegral(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::sqrIntegral(d_src, d_dst); + } + } + else + { + FAIL(); } } @@ -356,15 +479,35 @@ PERF_TEST_P(Sz_Depth, ImgProc_HistEvenC1, Combine(GPU_TYPICAL_MAT_SIZES, Values( cv::Mat src(size, depth); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_hist; - cv::gpu::GpuMat d_buf; - - cv::gpu::histEven(d_src, d_hist, d_buf, 30, 0, 180); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_hist; + cv::gpu::GpuMat d_buf; + cv::gpu::histEven(d_src, d_hist, d_buf, 30, 0, 180); + + TEST_CYCLE() + { + cv::gpu::histEven(d_src, d_hist, d_buf, 30, 0, 180); + } + } + else + { + int hbins = 30; + float hranges[] = {0.0f, 180.0f}; + int histSize[] = {hbins}; + const float* ranges[] = {hranges}; + int channels[] = {0}; + + cv::Mat hist; + + cv::calcHist(&src, 1, channels, cv::Mat(), hist, 1, histSize, ranges); + + TEST_CYCLE() + { + cv::calcHist(&src, 1, channels, cv::Mat(), hist, 1, histSize, ranges); + } } } @@ -383,15 +526,22 @@ PERF_TEST_P(Sz_Depth, ImgProc_HistEvenC4, Combine(GPU_TYPICAL_MAT_SIZES, Values( int lowerLevel[] = {0, 0, 0, 0}; int upperLevel[] = {180, 180, 180, 180}; - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_hist[4]; - cv::gpu::GpuMat d_buf; - - cv::gpu::histEven(d_src, d_hist, d_buf, histSize, lowerLevel, upperLevel); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_hist[4]; + cv::gpu::GpuMat d_buf; + cv::gpu::histEven(d_src, d_hist, d_buf, histSize, lowerLevel, upperLevel); + + TEST_CYCLE() + { + cv::gpu::histEven(d_src, d_hist, d_buf, histSize, lowerLevel, upperLevel); + } + } + else + { + FAIL(); } } @@ -405,15 +555,22 @@ PERF_TEST_P(Sz, ImgProc_CalcHist, GPU_TYPICAL_MAT_SIZES) cv::Mat src(size, CV_8UC1); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_hist; - cv::gpu::GpuMat d_buf; - - cv::gpu::calcHist(d_src, d_hist, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_hist; + cv::gpu::GpuMat d_buf; + cv::gpu::calcHist(d_src, d_hist, d_buf); + + TEST_CYCLE() + { + cv::gpu::calcHist(d_src, d_hist, d_buf); + } + } + else + { + FAIL(); } } @@ -427,16 +584,30 @@ PERF_TEST_P(Sz, ImgProc_EqualizeHist, GPU_TYPICAL_MAT_SIZES) cv::Mat src(size, CV_8UC1); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat d_hist; - cv::gpu::GpuMat d_buf; - - cv::gpu::equalizeHist(d_src, d_dst, d_hist, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_hist; + cv::gpu::GpuMat d_buf; + cv::gpu::equalizeHist(d_src, d_dst, d_hist, d_buf); + + TEST_CYCLE() + { + cv::gpu::equalizeHist(d_src, d_dst, d_hist, d_buf); + } + } + else + { + cv::Mat dst; + + cv::equalizeHist(src, dst); + + TEST_CYCLE() + { + cv::equalizeHist(src, dst); + } } } @@ -450,14 +621,21 @@ PERF_TEST_P(Sz, ImgProc_ColumnSum, GPU_TYPICAL_MAT_SIZES) cv::Mat src(size, CV_32FC1); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::columnSum(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::columnSum(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::columnSum(d_src, d_dst); + } + } + else + { + FAIL(); } } @@ -478,15 +656,29 @@ PERF_TEST_P(Image_AppertureSz_L2gradient, ImgProc_Canny, Combine( cv::Mat image = readImage(fileName, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(image.empty()); - cv::gpu::GpuMat d_image(image); - cv::gpu::GpuMat d_dst; - cv::gpu::CannyBuf d_buf; - - cv::gpu::Canny(d_image, d_buf, d_dst, 50.0, 100.0, apperture_size, useL2gradient); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_image(image); + cv::gpu::GpuMat d_dst; + cv::gpu::CannyBuf d_buf; + cv::gpu::Canny(d_image, d_buf, d_dst, 50.0, 100.0, apperture_size, useL2gradient); + + TEST_CYCLE() + { + cv::gpu::Canny(d_image, d_buf, d_dst, 50.0, 100.0, apperture_size, useL2gradient); + } + } + else + { + cv::Mat dst; + + cv::Canny(image, dst, 50.0, 100.0, apperture_size, useL2gradient); + + TEST_CYCLE() + { + cv::Canny(image, dst, 50.0, 100.0, apperture_size, useL2gradient); + } } } @@ -497,7 +689,7 @@ DEF_PARAM_TEST_1(Image, string); PERF_TEST_P(Image, ImgProc_MeanShiftFiltering, Values("gpu/meanshift/cones.png")) { - declare.time(5.0); + declare.time(15.0); cv::Mat img = readImage(GetParam()); ASSERT_FALSE(img.empty()); @@ -505,14 +697,28 @@ PERF_TEST_P(Image, ImgProc_MeanShiftFiltering, Values("gpu/meanshift/con cv::Mat rgba; cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA); - cv::gpu::GpuMat d_src(rgba); - cv::gpu::GpuMat d_dst; - - cv::gpu::meanShiftFiltering(d_src, d_dst, 50, 50); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(rgba); + cv::gpu::GpuMat d_dst; + cv::gpu::meanShiftFiltering(d_src, d_dst, 50, 50); + + TEST_CYCLE() + { + cv::gpu::meanShiftFiltering(d_src, d_dst, 50, 50); + } + } + else + { + cv::Mat dst; + + cv::pyrMeanShiftFiltering(img, dst, 50, 50); + + TEST_CYCLE() + { + cv::pyrMeanShiftFiltering(img, dst, 50, 50); + } } } @@ -529,15 +735,22 @@ PERF_TEST_P(Image, ImgProc_MeanShiftProc, Values("gpu/meanshift/cones.pn cv::Mat rgba; cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA); - cv::gpu::GpuMat d_src(rgba); - cv::gpu::GpuMat d_dstr; - cv::gpu::GpuMat d_dstsp; - - cv::gpu::meanShiftProc(d_src, d_dstr, d_dstsp, 50, 50); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(rgba); + cv::gpu::GpuMat d_dstr; + cv::gpu::GpuMat d_dstsp; + cv::gpu::meanShiftProc(d_src, d_dstr, d_dstsp, 50, 50); + + TEST_CYCLE() + { + cv::gpu::meanShiftProc(d_src, d_dstr, d_dstsp, 50, 50); + } + } + else + { + FAIL(); } } @@ -556,13 +769,20 @@ PERF_TEST_P(Image, ImgProc_MeanShiftSegmentation, Values("gpu/meanshift/ cv::Mat dst; - cv::gpu::GpuMat d_src(rgba); - - cv::gpu::meanShiftSegmentation(d_src, dst, 10, 10, 20); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(rgba); + cv::gpu::meanShiftSegmentation(d_src, dst, 10, 10, 20); + + TEST_CYCLE() + { + cv::gpu::meanShiftSegmentation(d_src, dst, 10, 10, 20); + } + } + else + { + FAIL(); } } @@ -583,17 +803,24 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_BlendLinear, Combine(GPU_TYPICAL_MAT_SIZES, Val cv::Mat img2(size, type); fillRandom(img2); - cv::gpu::GpuMat d_img1(img1); - cv::gpu::GpuMat d_img2(img2); - cv::gpu::GpuMat d_weights1(size, CV_32FC1, cv::Scalar::all(0.5)); - cv::gpu::GpuMat d_weights2(size, CV_32FC1, cv::Scalar::all(0.5)); - cv::gpu::GpuMat d_dst; - - cv::gpu::blendLinear(d_img1, d_img2, d_weights1, d_weights2, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_img1(img1); + cv::gpu::GpuMat d_img2(img2); + cv::gpu::GpuMat d_weights1(size, CV_32FC1, cv::Scalar::all(0.5)); + cv::gpu::GpuMat d_weights2(size, CV_32FC1, cv::Scalar::all(0.5)); + cv::gpu::GpuMat d_dst; + cv::gpu::blendLinear(d_img1, d_img2, d_weights1, d_weights2, d_dst); + + TEST_CYCLE() + { + cv::gpu::blendLinear(d_img1, d_img2, d_weights1, d_weights2, d_dst); + } + } + else + { + FAIL(); } } @@ -604,26 +831,48 @@ DEF_PARAM_TEST(Sz_KernelSz_Ccorr, cv::Size, int, bool); PERF_TEST_P(Sz_KernelSz_Ccorr, ImgProc_Convolve, Combine(GPU_TYPICAL_MAT_SIZES, Values(17, 27, 32, 64), Bool())) { - declare.time(2.0); + declare.time(10.0); cv::Size size = GET_PARAM(0); int templ_size = GET_PARAM(1); bool ccorr = GET_PARAM(2); - cv::gpu::GpuMat d_image = cv::gpu::createContinuous(size, CV_32FC1); - d_image.setTo(cv::Scalar(1.0)); + cv::Mat image(size, CV_32FC1); + image.setTo(1.0); - cv::gpu::GpuMat d_templ = cv::gpu::createContinuous(templ_size, templ_size, CV_32FC1); - d_templ.setTo(cv::Scalar(1.0)); + cv::Mat templ(templ_size, templ_size, CV_32FC1); + templ.setTo(1.0); - cv::gpu::GpuMat d_dst; - cv::gpu::ConvolveBuf d_buf; - - cv::gpu::convolve(d_image, d_templ, d_dst, ccorr, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_image = cv::gpu::createContinuous(size, CV_32FC1); + d_image.upload(image); + + cv::gpu::GpuMat d_templ = cv::gpu::createContinuous(templ_size, templ_size, CV_32FC1); + d_templ.upload(templ); + + cv::gpu::GpuMat d_dst; + cv::gpu::ConvolveBuf d_buf; + cv::gpu::convolve(d_image, d_templ, d_dst, ccorr, d_buf); + + TEST_CYCLE() + { + cv::gpu::convolve(d_image, d_templ, d_dst, ccorr, d_buf); + } + } + else + { + ASSERT_FALSE(ccorr); + + cv::Mat dst; + + cv::filter2D(image, dst, image.depth(), templ); + + TEST_CYCLE() + { + cv::filter2D(image, dst, image.depth(), templ); + } } } @@ -652,15 +901,29 @@ PERF_TEST_P(Sz_TemplateSz_Cn_Method, ImgProc_MatchTemplate8U, Combine( cv::Mat templ(templ_size, CV_MAKE_TYPE(CV_8U, cn)); fillRandom(templ); - cv::gpu::GpuMat d_image(image); - cv::gpu::GpuMat d_templ(templ); - cv::gpu::GpuMat d_dst; - - cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_image(image); + cv::gpu::GpuMat d_templ(templ); + cv::gpu::GpuMat d_dst; + cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); + + TEST_CYCLE() + { + cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); + } + } + else + { + cv::Mat dst; + + cv::matchTemplate(image, templ, dst, method); + + TEST_CYCLE() + { + cv::matchTemplate(image, templ, dst, method); + } } }; @@ -684,15 +947,29 @@ PERF_TEST_P(Sz_TemplateSz_Cn_Method, ImgProc_MatchTemplate32F, Combine( cv::Mat templ(templ_size, CV_MAKE_TYPE(CV_32F, cn)); fillRandom(templ); - cv::gpu::GpuMat d_image(image); - cv::gpu::GpuMat d_templ(templ); - cv::gpu::GpuMat d_dst; - - cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_image(image); + cv::gpu::GpuMat d_templ(templ); + cv::gpu::GpuMat d_dst; + cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); + + TEST_CYCLE() + { + cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); + } + } + else + { + cv::Mat dst; + + cv::matchTemplate(image, templ, dst, method); + + TEST_CYCLE() + { + cv::matchTemplate(image, templ, dst, method); + } } }; @@ -716,15 +993,29 @@ PERF_TEST_P(Sz_Flags, ImgProc_MulSpectrums, Combine( cv::Mat b(size, CV_32FC2); fillRandom(b, 0, 100); - cv::gpu::GpuMat d_a(a); - cv::gpu::GpuMat d_b(b); - cv::gpu::GpuMat d_dst; - - cv::gpu::mulSpectrums(d_a, d_b, d_dst, flag); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_a(a); + cv::gpu::GpuMat d_b(b); + cv::gpu::GpuMat d_dst; + cv::gpu::mulSpectrums(d_a, d_b, d_dst, flag); + + TEST_CYCLE() + { + cv::gpu::mulSpectrums(d_a, d_b, d_dst, flag); + } + } + else + { + cv::Mat dst; + + cv::mulSpectrums(a, b, dst, flag); + + TEST_CYCLE() + { + cv::mulSpectrums(a, b, dst, flag); + } } } @@ -743,15 +1034,22 @@ PERF_TEST_P(Sz, ImgProc_MulAndScaleSpectrums, GPU_TYPICAL_MAT_SIZES) cv::Mat src2(size, CV_32FC2); fillRandom(src2, 0, 100); - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; - - cv::gpu::mulAndScaleSpectrums(d_src1, d_src2, d_dst, cv::DFT_ROWS, scale, false); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src1(src1); + cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat d_dst; + cv::gpu::mulAndScaleSpectrums(d_src1, d_src2, d_dst, cv::DFT_ROWS, scale, false); + + TEST_CYCLE() + { + cv::gpu::mulAndScaleSpectrums(d_src1, d_src2, d_dst, cv::DFT_ROWS, scale, false); + } + } + else + { + FAIL(); } } @@ -762,7 +1060,7 @@ PERF_TEST_P(Sz_Flags, ImgProc_Dft, Combine( GPU_TYPICAL_MAT_SIZES, Values(0, DftFlags(cv::DFT_ROWS), DftFlags(cv::DFT_INVERSE)))) { - declare.time(2.0); + declare.time(10.0); cv::Size size = GET_PARAM(0); int flag = GET_PARAM(1); @@ -770,14 +1068,28 @@ PERF_TEST_P(Sz_Flags, ImgProc_Dft, Combine( cv::Mat src(size, CV_32FC2); fillRandom(src, 0, 100); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::dft(d_src, d_dst, size, flag); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::dft(d_src, d_dst, size, flag); + + TEST_CYCLE() + { + cv::gpu::dft(d_src, d_dst, size, flag); + } + } + else + { + cv::Mat dst; + + cv::dft(src, dst, flag); + + TEST_CYCLE() + { + cv::dft(src, dst, flag); + } } } @@ -793,8 +1105,6 @@ PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerHarris, Combine( Values(3, 5, 7), Values(0, 3, 5, 7))) { - double k = 0.5; - string fileName = GET_PARAM(0); int type = GET_PARAM(1); int borderMode = GET_PARAM(2); @@ -803,20 +1113,35 @@ PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerHarris, Combine( cv::Mat img = readImage(fileName, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); - img.convertTo(img, type, type == CV_32F ? 1.0 / 255.0 : 1.0); - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat d_Dx; - cv::gpu::GpuMat d_Dy; - cv::gpu::GpuMat d_buf; + double k = 0.5; - cv::gpu::cornerHarris(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, k, borderMode); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_Dx; + cv::gpu::GpuMat d_Dy; + cv::gpu::GpuMat d_buf; + cv::gpu::cornerHarris(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, k, borderMode); + + TEST_CYCLE() + { + cv::gpu::cornerHarris(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, k, borderMode); + } + } + else + { + cv::Mat dst; + + cv::cornerHarris(img, dst, blockSize, apertureSize, k, borderMode); + + TEST_CYCLE() + { + cv::cornerHarris(img, dst, blockSize, apertureSize, k, borderMode); + } } } @@ -841,17 +1166,31 @@ PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerMinEigenVal, Com img.convertTo(img, type, type == CV_32F ? 1.0 / 255.0 : 1.0); - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_dst; - cv::gpu::GpuMat d_Dx; - cv::gpu::GpuMat d_Dy; - cv::gpu::GpuMat d_buf; - - cv::gpu::cornerMinEigenVal(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, borderMode); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat d_Dx; + cv::gpu::GpuMat d_Dy; + cv::gpu::GpuMat d_buf; + cv::gpu::cornerMinEigenVal(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, borderMode); + + TEST_CYCLE() + { + cv::gpu::cornerMinEigenVal(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, borderMode); + } + } + else + { + cv::Mat dst; + + cv::cornerMinEigenVal(img, dst, blockSize, apertureSize, borderMode); + + TEST_CYCLE() + { + cv::cornerMinEigenVal(img, dst, blockSize, apertureSize, borderMode); + } } } @@ -866,14 +1205,21 @@ PERF_TEST_P(Sz, ImgProc_BuildWarpPlaneMaps, GPU_TYPICAL_MAT_SIZES) cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); cv::Mat T = cv::Mat::zeros(1, 3, CV_32F); - cv::gpu::GpuMat d_map_x; - cv::gpu::GpuMat d_map_y; - - cv::gpu::buildWarpPlaneMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, T, 1.0, d_map_x, d_map_y); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_map_x; + cv::gpu::GpuMat d_map_y; + cv::gpu::buildWarpPlaneMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, T, 1.0, d_map_x, d_map_y); + + TEST_CYCLE() + { + cv::gpu::buildWarpPlaneMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, T, 1.0, d_map_x, d_map_y); + } + } + else + { + FAIL(); } } @@ -887,14 +1233,21 @@ PERF_TEST_P(Sz, ImgProc_BuildWarpCylindricalMaps, GPU_TYPICAL_MAT_SIZES) cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); - cv::gpu::GpuMat d_map_x; - cv::gpu::GpuMat d_map_y; - - cv::gpu::buildWarpCylindricalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_map_x; + cv::gpu::GpuMat d_map_y; + cv::gpu::buildWarpCylindricalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); + + TEST_CYCLE() + { + cv::gpu::buildWarpCylindricalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); + } + } + else + { + FAIL(); } } @@ -908,14 +1261,21 @@ PERF_TEST_P(Sz, ImgProc_BuildWarpSphericalMaps, GPU_TYPICAL_MAT_SIZES) cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); - cv::gpu::GpuMat d_map_x; - cv::gpu::GpuMat d_map_y; - - cv::gpu::buildWarpSphericalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_map_x; + cv::gpu::GpuMat d_map_y; + cv::gpu::buildWarpSphericalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); + + TEST_CYCLE() + { + cv::gpu::buildWarpSphericalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); + } + } + else + { + FAIL(); } } @@ -940,14 +1300,21 @@ PERF_TEST_P(Sz_Depth_Cn_Inter, ImgProc_Rotate, Combine( cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::rotate(d_src, d_dst, size, 30.0, 0, 0, interpolation); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::rotate(d_src, d_dst, size, 30.0, 0, 0, interpolation); + + TEST_CYCLE() + { + cv::gpu::rotate(d_src, d_dst, size, 30.0, 0, 0, interpolation); + } + } + else + { + FAIL(); } } @@ -968,14 +1335,28 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_PyrDown, Combine( cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::pyrDown(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::pyrDown(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::pyrDown(d_src, d_dst); + } + } + else + { + cv::Mat dst; + + cv::pyrDown(src, dst); + + TEST_CYCLE() + { + cv::pyrDown(src, dst); + } } } @@ -996,14 +1377,28 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_PyrUp, Combine( cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::pyrUp(d_src, d_dst); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::pyrUp(d_src, d_dst); + + TEST_CYCLE() + { + cv::gpu::pyrUp(d_src, d_dst); + } + } + else + { + cv::Mat dst; + + cv::pyrUp(src, dst); + + TEST_CYCLE() + { + cv::pyrUp(src, dst); + } } } @@ -1049,14 +1444,28 @@ PERF_TEST_P(Sz_Depth_Code, ImgProc_CvtColor, Combine( cv::Mat src(size, CV_MAKETYPE(depth, info.scn)); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::cvtColor(d_src, d_dst, info.code, info.dcn); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + cv::gpu::cvtColor(d_src, d_dst, info.code, info.dcn); + + TEST_CYCLE() + { + cv::gpu::cvtColor(d_src, d_dst, info.code, info.dcn); + } + } + else + { + cv::Mat dst; + + cv::cvtColor(src, dst, info.code, info.dcn); + + TEST_CYCLE() + { + cv::cvtColor(src, dst, info.code, info.dcn); + } } } @@ -1072,13 +1481,20 @@ PERF_TEST_P(Sz, ImgProc_SwapChannels, GPU_TYPICAL_MAT_SIZES) const int dstOrder[] = {2, 1, 0, 3}; - cv::gpu::GpuMat d_src(src); - - cv::gpu::swapChannels(d_src, dstOrder); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::swapChannels(d_src, dstOrder); + + TEST_CYCLE() + { + cv::gpu::swapChannels(d_src, dstOrder); + } + } + else + { + FAIL(); } } @@ -1102,15 +1518,22 @@ PERF_TEST_P(Sz_Type_Op, ImgProc_AlphaComp, Combine(GPU_TYPICAL_MAT_SIZES, Values cv::Mat img2(size, type); fillRandom(img2); - cv::gpu::GpuMat d_img1(img1); - cv::gpu::GpuMat d_img2(img2); - cv::gpu::GpuMat d_dst; - - cv::gpu::alphaComp(d_img1, d_img2, d_dst, alpha_op); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_img1(img1); + cv::gpu::GpuMat d_img2(img2); + cv::gpu::GpuMat d_dst; + cv::gpu::alphaComp(d_img1, d_img2, d_dst, alpha_op); + + TEST_CYCLE() + { + cv::gpu::alphaComp(d_img1, d_img2, d_dst, alpha_op); + } + } + else + { + FAIL(); } } @@ -1128,15 +1551,22 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_ImagePyramidBuild, Combine(GPU_TYPICAL_MAT_SIZE cv::Mat src(size, type); fillRandom(src); - cv::gpu::GpuMat d_src(src); - - cv::gpu::ImagePyramid d_pyr; - - d_pyr.build(d_src, 5); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + + cv::gpu::ImagePyramid d_pyr; + d_pyr.build(d_src, 5); + + TEST_CYCLE() + { + d_pyr.build(d_src, 5); + } + } + else + { + FAIL(); } } @@ -1156,16 +1586,23 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_ImagePyramidGetLayer, Combine(GPU_TYPICAL_MAT_S cv::Size dstSize(size.width / 2 + 10, size.height / 2 + 10); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - cv::gpu::ImagePyramid d_pyr(d_src, 3); - - d_pyr.getLayer(d_dst, dstSize); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + + cv::gpu::ImagePyramid d_pyr(d_src, 3); + d_pyr.getLayer(d_dst, dstSize); + + TEST_CYCLE() + { + d_pyr.getLayer(d_dst, dstSize); + } + } + else + { + FAIL(); } } @@ -1197,16 +1634,29 @@ PERF_TEST_P(Sz_DoSort, ImgProc_HoughLines, Combine(GPU_TYPICAL_MAT_SIZES, Bool() cv::line(src, p1, p2, cv::Scalar::all(255), 2); } - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_lines; - cv::gpu::GpuMat d_accum; - cv::gpu::GpuMat d_buf; - - cv::gpu::HoughLines(d_src, d_lines, d_accum, d_buf, rho, theta, threshold, doSort); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_lines; + cv::gpu::GpuMat d_accum; + cv::gpu::GpuMat d_buf; + cv::gpu::HoughLines(d_src, d_lines, d_accum, d_buf, rho, theta, threshold, doSort); + + TEST_CYCLE() + { + cv::gpu::HoughLines(d_src, d_lines, d_accum, d_buf, rho, theta, threshold, doSort); + } + } + else + { + std::vector lines; + cv::HoughLines(src, lines, rho, theta, threshold); + + TEST_CYCLE() + { + cv::HoughLines(src, lines, rho, theta, threshold); + } } } diff --git a/modules/gpu/perf/perf_labeling.cpp b/modules/gpu/perf/perf_labeling.cpp index bd1bcf144d..f17dd7d0af 100644 --- a/modules/gpu/perf/perf_labeling.cpp +++ b/modules/gpu/perf/perf_labeling.cpp @@ -7,27 +7,129 @@ namespace { DEF_PARAM_TEST_1(Image, string); +struct GreedyLabeling +{ + struct dot + { + int x; + int y; + + static dot make(int i, int j) + { + dot d; d.x = i; d.y = j; + return d; + } + }; + + struct InInterval + { + InInterval(const int& _lo, const int& _hi) : lo(-_lo), hi(_hi) {}; + const int lo, hi; + + bool operator() (const unsigned char a, const unsigned char b) const + { + int d = a - b; + return lo <= d && d <= hi; + } + }; + + GreedyLabeling(cv::Mat img) + : image(img), _labels(image.size(), CV_32SC1, cv::Scalar::all(-1)) {stack = new dot[image.cols * image.rows];} + + ~GreedyLabeling(){delete[] stack;} + + void operator() (cv::Mat labels) const + { + labels.setTo(cv::Scalar::all(-1)); + InInterval inInt(0, 2); + int cc = -1; + + int* dist_labels = (int*)labels.data; + int pitch = labels.step1(); + + unsigned char* source = (unsigned char*)image.data; + int width = image.cols; + int height = image.rows; + + for (int j = 0; j < image.rows; ++j) + for (int i = 0; i < image.cols; ++i) + { + if (dist_labels[j * pitch + i] != -1) continue; + + dot* top = stack; + dot p = dot::make(i, j); + cc++; + + dist_labels[j * pitch + i] = cc; + + while (top >= stack) + { + int* dl = &dist_labels[p.y * pitch + p.x]; + unsigned char* sp = &source[p.y * image.step1() + p.x]; + + dl[0] = cc; + + //right + if( p.x < (width - 1) && dl[ +1] == -1 && inInt(sp[0], sp[+1])) + *top++ = dot::make(p.x + 1, p.y); + + //left + if( p.x > 0 && dl[-1] == -1 && inInt(sp[0], sp[-1])) + *top++ = dot::make(p.x - 1, p.y); + + //bottom + if( p.y < (height - 1) && dl[+pitch] == -1 && inInt(sp[0], sp[+image.step1()])) + *top++ = dot::make(p.x, p.y + 1); + + //top + if( p.y > 0 && dl[-pitch] == -1 && inInt(sp[0], sp[-image.step1()])) + *top++ = dot::make(p.x, p.y - 1); + + p = *--top; + } + } + } + + cv::Mat image; + cv::Mat _labels; + dot* stack; +}; + PERF_TEST_P(Image, Labeling_ConnectedComponents, Values("gpu/labeling/aloe-disp.png")) { - cv::Mat image = readImage(GetParam(), cv::IMREAD_GRAYSCALE); - - // cv::threshold(image, image, 150, 255, CV_THRESH_BINARY); - - cv::gpu::GpuMat mask; - mask.create(image.rows, image.cols, CV_8UC1); - - cv::gpu::GpuMat components; - components.create(image.rows, image.cols, CV_32SC1); - - cv::gpu::connectivityMask(cv::gpu::GpuMat(image), mask, cv::Scalar::all(0), cv::Scalar::all(2)); - - ASSERT_NO_THROW(cv::gpu::labelComponents(mask, components)); - declare.time(1.0); - TEST_CYCLE() + cv::Mat image = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + + if (runOnGpu) { - cv::gpu::labelComponents(mask, components); + cv::gpu::GpuMat mask; + mask.create(image.rows, image.cols, CV_8UC1); + + cv::gpu::GpuMat components; + components.create(image.rows, image.cols, CV_32SC1); + + cv::gpu::connectivityMask(cv::gpu::GpuMat(image), mask, cv::Scalar::all(0), cv::Scalar::all(2)); + + ASSERT_NO_THROW(cv::gpu::labelComponents(mask, components)); + + TEST_CYCLE() + { + cv::gpu::labelComponents(mask, components); + } + } + else + { + GreedyLabeling host(image); + + host(host._labels); + + declare.time(1.0); + + TEST_CYCLE() + { + host(host._labels); + } } } diff --git a/modules/gpu/perf/perf_matop.cpp b/modules/gpu/perf/perf_matop.cpp index c014b19da8..cdae962f23 100644 --- a/modules/gpu/perf/perf_matop.cpp +++ b/modules/gpu/perf/perf_matop.cpp @@ -18,13 +18,27 @@ PERF_TEST_P(Sz_Depth_Cn, MatOp_SetTo, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8 cv::Scalar val(1, 2, 3, 4); - cv::gpu::GpuMat d_src(size, type); - - d_src.setTo(val); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(size, type); + d_src.setTo(val); + + TEST_CYCLE() + { + d_src.setTo(val); + } + } + else + { + cv::Mat src(size, type); + + src.setTo(val); + + TEST_CYCLE() + { + src.setTo(val); + } } } @@ -47,14 +61,26 @@ PERF_TEST_P(Sz_Depth_Cn, MatOp_SetToMasked, Combine(GPU_TYPICAL_MAT_SIZES, Value cv::Scalar val(1, 2, 3, 4); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_mask(mask); - - d_src.setTo(val, d_mask); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_mask(mask); + d_src.setTo(val, d_mask); + + TEST_CYCLE() + { + d_src.setTo(val, d_mask); + } + } + else + { + src.setTo(val, mask); + + TEST_CYCLE() + { + src.setTo(val, mask); + } } } @@ -75,15 +101,29 @@ PERF_TEST_P(Sz_Depth_Cn, MatOp_CopyToMasked, Combine(GPU_TYPICAL_MAT_SIZES, Valu cv::Mat mask(size, CV_8UC1); fillRandom(mask, 0, 2); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_mask(mask); - cv::gpu::GpuMat d_dst; - - d_src.copyTo(d_dst, d_mask); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_mask(mask); + cv::gpu::GpuMat d_dst; + d_src.copyTo(d_dst, d_mask); + + TEST_CYCLE() + { + d_src.copyTo(d_dst, d_mask); + } + } + else + { + cv::Mat dst; + + src.copyTo(dst, mask); + + TEST_CYCLE() + { + src.copyTo(dst, mask); + } } } @@ -101,14 +141,28 @@ PERF_TEST_P(Sz_2Depth, MatOp_ConvertTo, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV cv::Mat src(size, depth1); fillRandom(src); - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; - - d_src.convertTo(d_dst, depth2, 0.5, 1.0); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_dst; + d_src.convertTo(d_dst, depth2, 0.5, 1.0); + + TEST_CYCLE() + { + d_src.convertTo(d_dst, depth2, 0.5, 1.0); + } + } + else + { + cv::Mat dst; + + src.convertTo(dst, depth2, 0.5, 1.0); + + TEST_CYCLE() + { + src.convertTo(dst, depth2, 0.5, 1.0); + } } } diff --git a/modules/gpu/perf/perf_objdetect.cpp b/modules/gpu/perf/perf_objdetect.cpp index 9c1f7919f9..0c4cd5e4c0 100644 --- a/modules/gpu/perf/perf_objdetect.cpp +++ b/modules/gpu/perf/perf_objdetect.cpp @@ -17,16 +17,31 @@ PERF_TEST_P(Image, ObjDetect_HOG, Values("gpu/hog/road.png")) std::vector found_locations; - cv::gpu::GpuMat d_img(img); - - cv::gpu::HOGDescriptor d_hog; - d_hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector()); - - d_hog.detectMultiScale(d_img, found_locations); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_img(img); + + cv::gpu::HOGDescriptor d_hog; + d_hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector()); + d_hog.detectMultiScale(d_img, found_locations); + + TEST_CYCLE() + { + d_hog.detectMultiScale(d_img, found_locations); + } + } + else + { + cv::HOGDescriptor hog; + hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector()); + + hog.detectMultiScale(img, found_locations); + + TEST_CYCLE() + { + hog.detectMultiScale(img, found_locations); + } } } @@ -42,18 +57,34 @@ PERF_TEST_P(ImageAndCascade, ObjDetect_HaarClassifier, cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); - cv::gpu::CascadeClassifier_GPU d_cascade; - - ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second))); - - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_objects_buffer; - - d_cascade.detectMultiScale(d_img, d_objects_buffer); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::CascadeClassifier_GPU d_cascade; + ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second))); + + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_objects_buffer; + d_cascade.detectMultiScale(d_img, d_objects_buffer); + + TEST_CYCLE() + { + d_cascade.detectMultiScale(d_img, d_objects_buffer); + } + } + else + { + cv::CascadeClassifier cascade; + ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/perf/haarcascade_frontalface_alt.xml"))); + + std::vector rects; + + cascade.detectMultiScale(img, rects); + + TEST_CYCLE() + { + cascade.detectMultiScale(img, rects); + } } } @@ -66,18 +97,34 @@ PERF_TEST_P(ImageAndCascade, ObjDetect_LBPClassifier, cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); - cv::gpu::CascadeClassifier_GPU d_cascade; - - ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second))); - - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_gpu_rects; - - d_cascade.detectMultiScale(d_img, d_gpu_rects); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::CascadeClassifier_GPU d_cascade; + ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second))); + + cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat d_gpu_rects; + d_cascade.detectMultiScale(d_img, d_gpu_rects); + + TEST_CYCLE() + { + d_cascade.detectMultiScale(d_img, d_gpu_rects); + } + } + else + { + cv::CascadeClassifier cascade; + ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/lbpcascade/lbpcascade_frontalface.xml"))); + + std::vector rects; + + cascade.detectMultiScale(img, rects); + + TEST_CYCLE() + { + cascade.detectMultiScale(img, rects); + } } } diff --git a/modules/gpu/perf/perf_video.cpp b/modules/gpu/perf/perf_video.cpp index a5a1e4da57..7faea0b880 100644 --- a/modules/gpu/perf/perf_video.cpp +++ b/modules/gpu/perf/perf_video.cpp @@ -3,6 +3,14 @@ using namespace std; using namespace testing; +namespace cv +{ + template<> void Ptr::delete_obj() + { + cvReleaseBGStatModel(&obj); + } +} + namespace { ////////////////////////////////////////////////////// @@ -25,19 +33,26 @@ PERF_TEST_P(ImagePair, Video_BroxOpticalFlow, Values(make_pair("gpu frame0.convertTo(frame0, CV_32FC1, 1.0 / 255.0); frame1.convertTo(frame1, CV_32FC1, 1.0 / 255.0); - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_u; - cv::gpu::GpuMat d_v; - - cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, - 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); - - d_flow(d_frame0, d_frame1, d_u, d_v); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_u; + cv::gpu::GpuMat d_v; + + cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, + 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); + d_flow(d_frame0, d_frame1, d_u, d_v); + + TEST_CYCLE() + { + d_flow(d_frame0, d_frame1, d_u, d_v); + } + } + else + { + FAIL(); } } @@ -55,25 +70,32 @@ PERF_TEST_P(ImagePair, Video_InterpolateFrames, Values(make_pair("g frame0.convertTo(frame0, CV_32FC1, 1.0 / 255.0); frame1.convertTo(frame1, CV_32FC1, 1.0 / 255.0); - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_fu, d_fv; - cv::gpu::GpuMat d_bu, d_bv; - - cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, - 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); - - d_flow(d_frame0, d_frame1, d_fu, d_fv); - d_flow(d_frame1, d_frame0, d_bu, d_bv); - - cv::gpu::GpuMat d_newFrame; - cv::gpu::GpuMat d_buf; - - cv::gpu::interpolateFrames(d_frame0, d_frame1, d_fu, d_fv, d_bu, d_bv, 0.5f, d_newFrame, d_buf); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_fu, d_fv; + cv::gpu::GpuMat d_bu, d_bv; + + cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, + 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); + + d_flow(d_frame0, d_frame1, d_fu, d_fv); + d_flow(d_frame1, d_frame0, d_bu, d_bv); + + cv::gpu::GpuMat d_newFrame; + cv::gpu::GpuMat d_buf; + cv::gpu::interpolateFrames(d_frame0, d_frame1, d_fu, d_fv, d_bu, d_bv, 0.5f, d_newFrame, d_buf); + + TEST_CYCLE() + { + cv::gpu::interpolateFrames(d_frame0, d_frame1, d_fu, d_fv, d_bu, d_bv, 0.5f, d_newFrame, d_buf); + } + } + else + { + FAIL(); } } @@ -91,23 +113,30 @@ PERF_TEST_P(ImagePair, Video_CreateOpticalFlowNeedleMap, Values(mak frame0.convertTo(frame0, CV_32FC1, 1.0 / 255.0); frame1.convertTo(frame1, CV_32FC1, 1.0 / 255.0); - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_u; - cv::gpu::GpuMat d_v; - - cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, - 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); - - d_flow(d_frame0, d_frame1, d_u, d_v); - - cv::gpu::GpuMat d_vertex, d_colors; - - cv::gpu::createOpticalFlowNeedleMap(d_u, d_v, d_vertex, d_colors); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_u; + cv::gpu::GpuMat d_v; + + cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, + 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); + + d_flow(d_frame0, d_frame1, d_u, d_v); + + cv::gpu::GpuMat d_vertex, d_colors; + cv::gpu::createOpticalFlowNeedleMap(d_u, d_v, d_vertex, d_colors); + + TEST_CYCLE() + { + cv::gpu::createOpticalFlowNeedleMap(d_u, d_v, d_vertex, d_colors); + } + } + else + { + FAIL(); } } @@ -124,16 +153,30 @@ PERF_TEST_P(Image_MinDistance, Video_GoodFeaturesToTrack, Combine(Values cv::Mat image = readImage(fileName, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(image.empty()); - cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(8000, 0.01, minDistance); - - cv::gpu::GpuMat d_image(image); - cv::gpu::GpuMat d_pts; - - d_detector(d_image, d_pts); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(8000, 0.01, minDistance); + + cv::gpu::GpuMat d_image(image); + cv::gpu::GpuMat d_pts; + d_detector(d_image, d_pts); + + TEST_CYCLE() + { + d_detector(d_image, d_pts); + } + } + else + { + cv::Mat pts; + + cv::goodFeaturesToTrack(image, pts, 8000, 0.01, minDistance); + + TEST_CYCLE() + { + cv::goodFeaturesToTrack(image, pts, 8000, 0.01, minDistance); + } } } @@ -150,6 +193,8 @@ PERF_TEST_P(ImagePair_Gray_NPts_WinSz_Levels_Iters, Video_PyrLKOpticalFlowSparse Values(1, 2, 3), Values(1, 10, 30))) { + declare.time(20.0); + pair_string imagePair = GET_PARAM(0); bool useGray = GET_PARAM(1); int points = GET_PARAM(2); @@ -169,26 +214,45 @@ PERF_TEST_P(ImagePair_Gray_NPts_WinSz_Levels_Iters, Video_PyrLKOpticalFlowSparse else cv::cvtColor(frame0, gray_frame, cv::COLOR_BGR2GRAY); - cv::gpu::GpuMat d_pts; + cv::Mat pts; + cv::goodFeaturesToTrack(gray_frame, pts, points, 0.01, 0.0); - cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(points, 0.01, 0.0); - d_detector(cv::gpu::GpuMat(gray_frame), d_pts); - - cv::gpu::PyrLKOpticalFlow d_pyrLK; - d_pyrLK.winSize = cv::Size(winSize, winSize); - d_pyrLK.maxLevel = levels - 1; - d_pyrLK.iters = iters; - - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_nextPts; - cv::gpu::GpuMat d_status; - - d_pyrLK.sparse(d_frame0, d_frame1, d_pts, d_nextPts, d_status); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_pts(pts); + + cv::gpu::PyrLKOpticalFlow d_pyrLK; + d_pyrLK.winSize = cv::Size(winSize, winSize); + d_pyrLK.maxLevel = levels - 1; + d_pyrLK.iters = iters; + + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_nextPts; + cv::gpu::GpuMat d_status; + d_pyrLK.sparse(d_frame0, d_frame1, d_pts, d_nextPts, d_status); + + TEST_CYCLE() + { + d_pyrLK.sparse(d_frame0, d_frame1, d_pts, d_nextPts, d_status); + } + } + else + { + cv::Mat nextPts; + cv::Mat status; + + cv::calcOpticalFlowPyrLK(frame0, frame1, pts, nextPts, status, cv::noArray(), + cv::Size(winSize, winSize), levels - 1, + cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, iters, 0.01)); + + TEST_CYCLE() + { + cv::calcOpticalFlowPyrLK(frame0, frame1, pts, nextPts, status, cv::noArray(), + cv::Size(winSize, winSize), levels - 1, + cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, iters, 0.01)); + } } } @@ -216,21 +280,28 @@ PERF_TEST_P(ImagePair_WinSz_Levels_Iters, Video_PyrLKOpticalFlowDense, Combine( cv::Mat frame1 = readImage(imagePair.second, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame1.empty()); - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_u; - cv::gpu::GpuMat d_v; - - cv::gpu::PyrLKOpticalFlow d_pyrLK; - d_pyrLK.winSize = cv::Size(winSize, winSize); - d_pyrLK.maxLevel = levels - 1; - d_pyrLK.iters = iters; - - d_pyrLK.dense(d_frame0, d_frame1, d_u, d_v); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_u; + cv::gpu::GpuMat d_v; + + cv::gpu::PyrLKOpticalFlow d_pyrLK; + d_pyrLK.winSize = cv::Size(winSize, winSize); + d_pyrLK.maxLevel = levels - 1; + d_pyrLK.iters = iters; + d_pyrLK.dense(d_frame0, d_frame1, d_u, d_v); + + TEST_CYCLE() + { + d_pyrLK.dense(d_frame0, d_frame1, d_u, d_v); + } + } + else + { + FAIL(); } } @@ -247,18 +318,47 @@ PERF_TEST_P(ImagePair, Video_FarnebackOpticalFlow, Values(make_pair cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame1.empty()); - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_u; - cv::gpu::GpuMat d_v; + int numLevels = 5; + double pyrScale = 0.5; + int winSize = 13; + int numIters = 10; + int polyN = 5; + double polySigma = 1.1; + int flags = 0; - cv::gpu::FarnebackOpticalFlow d_farneback; - - d_farneback(d_frame0, d_frame1, d_u, d_v); - - TEST_CYCLE() + if (runOnGpu) { + cv::gpu::GpuMat d_frame0(frame0); + cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_u; + cv::gpu::GpuMat d_v; + + cv::gpu::FarnebackOpticalFlow d_farneback; + d_farneback.numLevels = numLevels; + d_farneback.pyrScale = pyrScale; + d_farneback.winSize = winSize; + d_farneback.numIters = numIters; + d_farneback.polyN = polyN; + d_farneback.polySigma = polySigma; + d_farneback.flags = flags; + d_farneback(d_frame0, d_frame1, d_u, d_v); + + TEST_CYCLE() + { + d_farneback(d_frame0, d_frame1, d_u, d_v); + } + } + else + { + cv::Mat flow; + + cv::calcOpticalFlowFarneback(frame0, frame1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags); + + TEST_CYCLE() + { + cv::calcOpticalFlowFarneback(frame0, frame1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags); + } } } @@ -269,7 +369,7 @@ DEF_PARAM_TEST_1(Video, string); PERF_TEST_P(Video, Video_FGDStatModel, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) { - declare.time(10); + declare.time(60); string inputFile = perf::TestBase::getDataPath(GetParam()); @@ -280,20 +380,41 @@ PERF_TEST_P(Video, Video_FGDStatModel, Values("gpu/video/768x576.avi", "gpu/vide cap >> frame; ASSERT_FALSE(frame.empty()); - cv::gpu::GpuMat d_frame(frame); - cv::gpu::FGDStatModel d_model(4); - d_model.create(d_frame); - - for (int i = 0; i < 10; ++i) + if (runOnGpu) { - cap >> frame; - ASSERT_FALSE(frame.empty()); + cv::gpu::GpuMat d_frame(frame); - d_frame.upload(frame); + cv::gpu::FGDStatModel d_model(4); + d_model.create(d_frame); - startTimer(); next(); - d_model.update(d_frame); - stopTimer(); + for (int i = 0; i < 10; ++i) + { + cap >> frame; + ASSERT_FALSE(frame.empty()); + + d_frame.upload(frame); + + startTimer(); next(); + d_model.update(d_frame); + stopTimer(); + } + } + else + { + IplImage ipl_frame = frame; + cv::Ptr model(cvCreateFGDStatModel(&ipl_frame)); + + for (int i = 0; i < 10; ++i) + { + cap >> frame; + ASSERT_FALSE(frame.empty()); + + ipl_frame = frame; + + startTimer(); next(); + cvUpdateBGStatModel(&ipl_frame, model); + stopTimer(); + } } } @@ -313,10 +434,6 @@ PERF_TEST_P(Video_Cn_LearningRate, Video_MOG, Combine(Values("gpu/video/768x576. cv::Mat frame; - cv::gpu::GpuMat d_frame; - cv::gpu::MOG_GPU d_mog; - cv::gpu::GpuMat d_foreground; - cap >> frame; ASSERT_FALSE(frame.empty()); @@ -330,30 +447,62 @@ PERF_TEST_P(Video_Cn_LearningRate, Video_MOG, Combine(Values("gpu/video/768x576. cv::swap(temp, frame); } - d_frame.upload(frame); - - d_mog(d_frame, d_foreground, learningRate); - - for (int i = 0; i < 10; ++i) + if (runOnGpu) { - cap >> frame; - ASSERT_FALSE(frame.empty()); + cv::gpu::GpuMat d_frame(frame); + cv::gpu::MOG_GPU d_mog; + cv::gpu::GpuMat d_foreground; - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } - - d_frame.upload(frame); - - startTimer(); next(); d_mog(d_frame, d_foreground, learningRate); - stopTimer(); + + for (int i = 0; i < 10; ++i) + { + cap >> frame; + ASSERT_FALSE(frame.empty()); + + if (cn != 3) + { + cv::Mat temp; + if (cn == 1) + cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); + else + cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); + cv::swap(temp, frame); + } + + d_frame.upload(frame); + + startTimer(); next(); + d_mog(d_frame, d_foreground, learningRate); + stopTimer(); + } + } + else + { + cv::BackgroundSubtractorMOG mog; + cv::Mat foreground; + + mog(frame, foreground, learningRate); + + for (int i = 0; i < 10; ++i) + { + cap >> frame; + ASSERT_FALSE(frame.empty()); + + if (cn != 3) + { + cv::Mat temp; + if (cn == 1) + cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); + else + cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); + cv::swap(temp, frame); + } + + startTimer(); next(); + mog(frame, foreground, learningRate); + stopTimer(); + } } } @@ -372,10 +521,6 @@ PERF_TEST_P(Video_Cn, Video_MOG2, Combine(Values("gpu/video/768x576.avi", "gpu/v cv::Mat frame; - cv::gpu::GpuMat d_frame; - cv::gpu::MOG2_GPU d_mog2; - cv::gpu::GpuMat d_foreground; - cap >> frame; ASSERT_FALSE(frame.empty()); @@ -389,30 +534,62 @@ PERF_TEST_P(Video_Cn, Video_MOG2, Combine(Values("gpu/video/768x576.avi", "gpu/v cv::swap(temp, frame); } - d_frame.upload(frame); - - d_mog2(d_frame, d_foreground); - - for (int i = 0; i < 10; ++i) + if (runOnGpu) { - cap >> frame; - ASSERT_FALSE(frame.empty()); + cv::gpu::GpuMat d_frame(frame); + cv::gpu::MOG2_GPU d_mog2; + cv::gpu::GpuMat d_foreground; - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } - - d_frame.upload(frame); - - startTimer(); next(); d_mog2(d_frame, d_foreground); - stopTimer(); + + for (int i = 0; i < 10; ++i) + { + cap >> frame; + ASSERT_FALSE(frame.empty()); + + if (cn != 3) + { + cv::Mat temp; + if (cn == 1) + cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); + else + cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); + cv::swap(temp, frame); + } + + d_frame.upload(frame); + + startTimer(); next(); + d_mog2(d_frame, d_foreground); + stopTimer(); + } + } + else + { + cv::BackgroundSubtractorMOG2 mog2; + cv::Mat foreground; + + mog2(frame, foreground); + + for (int i = 0; i < 10; ++i) + { + cap >> frame; + ASSERT_FALSE(frame.empty()); + + if (cn != 3) + { + cv::Mat temp; + if (cn == 1) + cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); + else + cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); + cv::swap(temp, frame); + } + + startTimer(); next(); + mog2(frame, foreground); + stopTimer(); + } } } @@ -429,36 +606,70 @@ PERF_TEST_P(Video_Cn, Video_MOG2GetBackgroundImage, Combine(Values("gpu/video/76 cv::Mat frame; - cv::gpu::GpuMat d_frame; - cv::gpu::MOG2_GPU d_mog2; - cv::gpu::GpuMat d_foreground; - - for (int i = 0; i < 10; ++i) + if (runOnGpu) { - cap >> frame; - ASSERT_FALSE(frame.empty()); + cv::gpu::GpuMat d_frame; + cv::gpu::MOG2_GPU d_mog2; + cv::gpu::GpuMat d_foreground; - if (cn != 3) + for (int i = 0; i < 10; ++i) { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); + cap >> frame; + ASSERT_FALSE(frame.empty()); + + if (cn != 3) + { + cv::Mat temp; + if (cn == 1) + cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); + else + cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); + cv::swap(temp, frame); + } + + d_frame.upload(frame); + + d_mog2(d_frame, d_foreground); } - d_frame.upload(frame); - - d_mog2(d_frame, d_foreground); - } - - cv::gpu::GpuMat d_background; - d_mog2.getBackgroundImage(d_background); - - TEST_CYCLE() - { + cv::gpu::GpuMat d_background; d_mog2.getBackgroundImage(d_background); + + TEST_CYCLE() + { + d_mog2.getBackgroundImage(d_background); + } + } + else + { + cv::BackgroundSubtractorMOG2 mog2; + cv::Mat foreground; + + for (int i = 0; i < 10; ++i) + { + cap >> frame; + ASSERT_FALSE(frame.empty()); + + if (cn != 3) + { + cv::Mat temp; + if (cn == 1) + cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); + else + cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); + cv::swap(temp, frame); + } + + mog2(frame, foreground); + } + + cv::Mat background; + mog2.getBackgroundImage(background); + + TEST_CYCLE() + { + mog2.getBackgroundImage(background); + } } } @@ -487,32 +698,39 @@ PERF_TEST_P(Video_Cn, Video_VIBE, Combine(Values("gpu/video/768x576.avi", "gpu/v cv::swap(temp, frame); } - cv::gpu::GpuMat d_frame(frame); - cv::gpu::VIBE_GPU d_vibe; - cv::gpu::GpuMat d_foreground; - - d_vibe(d_frame, d_foreground); - - for (int i = 0; i < 10; ++i) + if (runOnGpu) { - cap >> frame; - ASSERT_FALSE(frame.empty()); + cv::gpu::GpuMat d_frame(frame); + cv::gpu::VIBE_GPU d_vibe; + cv::gpu::GpuMat d_foreground; - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } - - d_frame.upload(frame); - - startTimer(); next(); d_vibe(d_frame, d_foreground); - stopTimer(); + + for (int i = 0; i < 10; ++i) + { + cap >> frame; + ASSERT_FALSE(frame.empty()); + + if (cn != 3) + { + cv::Mat temp; + if (cn == 1) + cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); + else + cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); + cv::swap(temp, frame); + } + + d_frame.upload(frame); + + startTimer(); next(); + d_vibe(d_frame, d_foreground); + stopTimer(); + } + } + else + { + FAIL(); } } @@ -544,38 +762,76 @@ PERF_TEST_P(Video_Cn_MaxFeatures, Video_GMG, Combine(Values("gpu/video/768x576.a cv::swap(temp, frame); } - cv::gpu::GpuMat d_frame(frame); - cv::gpu::GpuMat d_fgmask; - - cv::gpu::GMG_GPU d_gmg; - d_gmg.maxFeatures = maxFeatures; - - d_gmg(d_frame, d_fgmask); - - for (int i = 0; i < 150; ++i) + if (runOnGpu) { - cap >> frame; - if (frame.empty()) - { - cap.open(inputFile); - cap >> frame; - } + cv::gpu::GpuMat d_frame(frame); + cv::gpu::GpuMat d_fgmask; - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } + cv::gpu::GMG_GPU d_gmg; + d_gmg.maxFeatures = maxFeatures; - d_frame.upload(frame); - - startTimer(); next(); d_gmg(d_frame, d_fgmask); - stopTimer(); + + for (int i = 0; i < 150; ++i) + { + cap >> frame; + if (frame.empty()) + { + cap.open(inputFile); + cap >> frame; + } + + if (cn != 3) + { + cv::Mat temp; + if (cn == 1) + cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); + else + cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); + cv::swap(temp, frame); + } + + d_frame.upload(frame); + + startTimer(); next(); + d_gmg(d_frame, d_fgmask); + stopTimer(); + } + } + else + { + cv::Mat fgmask; + cv::Mat zeros(frame.size(), CV_8UC1, cv::Scalar::all(0)); + + cv::BackgroundSubtractorGMG gmg; + gmg.set("maxFeatures", maxFeatures); + gmg.initialize(frame.size(), 0.0, 255.0); + + gmg(frame, fgmask); + + for (int i = 0; i < 150; ++i) + { + cap >> frame; + if (frame.empty()) + { + cap.open(inputFile); + cap >> frame; + } + + if (cn != 3) + { + cv::Mat temp; + if (cn == 1) + cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); + else + cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); + cv::swap(temp, frame); + } + + startTimer(); next(); + gmg(frame, fgmask); + stopTimer(); + } } } @@ -584,6 +840,8 @@ PERF_TEST_P(Video_Cn_MaxFeatures, Video_GMG, Combine(Values("gpu/video/768x576.a PERF_TEST_P(Video, Video_VideoWriter, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) { + declare.time(30); + string inputFile = perf::TestBase::getDataPath(GetParam()); string outputFile = cv::tempfile(".avi"); @@ -592,26 +850,45 @@ PERF_TEST_P(Video, Video_VideoWriter, Values("gpu/video/768x576.avi", "gpu/video cv::VideoCapture reader(inputFile); ASSERT_TRUE( reader.isOpened() ); - cv::gpu::VideoWriter_GPU d_writer; - cv::Mat frame; - cv::gpu::GpuMat d_frame; - declare.time(10); - - for (int i = 0; i < 10; ++i) + if (runOnGpu) { - reader >> frame; - ASSERT_FALSE(frame.empty()); + cv::gpu::VideoWriter_GPU d_writer; - d_frame.upload(frame); + cv::gpu::GpuMat d_frame; - if (!d_writer.isOpened()) - d_writer.open(outputFile, frame.size(), FPS); + for (int i = 0; i < 10; ++i) + { + reader >> frame; + ASSERT_FALSE(frame.empty()); - startTimer(); next(); - d_writer.write(d_frame); - stopTimer(); + d_frame.upload(frame); + + if (!d_writer.isOpened()) + d_writer.open(outputFile, frame.size(), FPS); + + startTimer(); next(); + d_writer.write(d_frame); + stopTimer(); + } + } + else + { + cv::VideoWriter writer; + + for (int i = 0; i < 10; ++i) + { + reader >> frame; + ASSERT_FALSE(frame.empty()); + + if (!writer.isOpened()) + writer.open(outputFile, CV_FOURCC('X', 'V', 'I', 'D'), FPS, frame.size()); + + startTimer(); next(); + writer.write(frame); + stopTimer(); + } } } @@ -624,16 +901,33 @@ PERF_TEST_P(Video, Video_VideoReader, Values("gpu/video/768x576.avi", "gpu/video string inputFile = perf::TestBase::getDataPath(GetParam()); - cv::gpu::VideoReader_GPU d_reader(inputFile); - ASSERT_TRUE( d_reader.isOpened() ); - - cv::gpu::GpuMat d_frame; - - d_reader.read(d_frame); - - TEST_CYCLE_N(10) + if (runOnGpu) { + cv::gpu::VideoReader_GPU d_reader(inputFile); + ASSERT_TRUE( d_reader.isOpened() ); + + cv::gpu::GpuMat d_frame; + d_reader.read(d_frame); + + TEST_CYCLE_N(10) + { + d_reader.read(d_frame); + } + } + else + { + cv::VideoCapture reader(inputFile); + ASSERT_TRUE( reader.isOpened() ); + + cv::Mat frame; + + reader >> frame; + + TEST_CYCLE_N(10) + { + reader >> frame; + } } } diff --git a/modules/gpu/perf_cpu/perf_calib3d.cpp b/modules/gpu/perf_cpu/perf_calib3d.cpp deleted file mode 100644 index 8124b808af..0000000000 --- a/modules/gpu/perf_cpu/perf_calib3d.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "perf_cpu_precomp.hpp" - -#ifdef HAVE_CUDA - -////////////////////////////////////////////////////////////////////// -// StereoBM - -GPU_PERF_TEST_1(StereoBM, cv::gpu::DeviceInfo) -{ - cv::Mat img_l = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_l.empty()); - - cv::Mat img_r = readImage("gpu/perf/aloeR.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img_r.empty()); - - cv::StereoBM bm(0, 256); - - cv::Mat dst; - - bm(img_l, img_r, dst); - - declare.time(5.0); - - TEST_CYCLE() - { - bm(img_l, img_r, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Calib3D, StereoBM, ALL_DEVICES); - -////////////////////////////////////////////////////////////////////// -// ProjectPoints - -IMPLEMENT_PARAM_CLASS(Count, int) - -GPU_PERF_TEST(ProjectPoints, cv::gpu::DeviceInfo, Count) -{ - int count = GET_PARAM(1); - - cv::Mat src(1, count, CV_32FC3); - fill(src, -100, 100); - - cv::Mat rvec = cv::Mat::ones(1, 3, CV_32FC1); - cv::Mat tvec = cv::Mat::ones(1, 3, CV_32FC1); - cv::Mat camera_mat = cv::Mat::ones(3, 3, CV_32FC1); - cv::Mat dst; - - cv::projectPoints(src, rvec, tvec, camera_mat, cv::noArray(), dst); - - TEST_CYCLE() - { - cv::projectPoints(src, rvec, tvec, camera_mat, cv::noArray(), dst); - } -} - -INSTANTIATE_TEST_CASE_P(Calib3D, ProjectPoints, testing::Combine( - ALL_DEVICES, - testing::Values(5000, 10000, 20000))); - -////////////////////////////////////////////////////////////////////// -// SolvePnPRansac - -GPU_PERF_TEST(SolvePnPRansac, cv::gpu::DeviceInfo, Count) -{ - int count = GET_PARAM(1); - - cv::Mat object(1, count, CV_32FC3); - fill(object, -100, 100); - - cv::Mat camera_mat(3, 3, CV_32FC1); - fill(camera_mat, 0.5, 1); - camera_mat.at(0, 1) = 0.f; - camera_mat.at(1, 0) = 0.f; - camera_mat.at(2, 0) = 0.f; - camera_mat.at(2, 1) = 0.f; - - cv::Mat dist_coef(1, 8, CV_32F, cv::Scalar::all(0)); - - std::vector image_vec; - cv::Mat rvec_gold(1, 3, CV_32FC1); - fill(rvec_gold, 0, 1); - cv::Mat tvec_gold(1, 3, CV_32FC1); - fill(tvec_gold, 0, 1); - cv::projectPoints(object, rvec_gold, tvec_gold, camera_mat, dist_coef, image_vec); - - cv::Mat image(1, count, CV_32FC2, &image_vec[0]); - - cv::Mat rvec; - cv::Mat tvec; - - cv::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); - - declare.time(10.0); - - TEST_CYCLE() - { - cv::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); - } -} - -INSTANTIATE_TEST_CASE_P(Calib3D, SolvePnPRansac, testing::Combine( - ALL_DEVICES, - testing::Values(5000, 10000, 20000))); - -////////////////////////////////////////////////////////////////////// -// ReprojectImageTo3D - -GPU_PERF_TEST(ReprojectImageTo3D, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 5.0, 30.0); - - cv::Mat Q(4, 4, CV_32FC1); - fill(Q, 0.1, 1.0); - - cv::Mat dst; - - cv::reprojectImageTo3D(src, dst, Q); - - TEST_CYCLE() - { - cv::reprojectImageTo3D(src, dst, Q); - } -} - -INSTANTIATE_TEST_CASE_P(Calib3D, ReprojectImageTo3D, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S))); - -#endif - diff --git a/modules/gpu/perf_cpu/perf_core.cpp b/modules/gpu/perf_cpu/perf_core.cpp deleted file mode 100644 index fb87009584..0000000000 --- a/modules/gpu/perf_cpu/perf_core.cpp +++ /dev/null @@ -1,1388 +0,0 @@ -#include "perf_cpu_precomp.hpp" - -#ifdef HAVE_CUDA - -////////////////////////////////////////////////////////////////////// -// Merge - -GPU_PERF_TEST(Merge, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); - - std::vector src(channels); - for (int i = 0; i < channels; ++i) - src[i] = cv::Mat(size, depth, cv::Scalar::all(i)); - - cv::Mat dst; - - cv::merge(src, dst); - - TEST_CYCLE() - { - cv::merge(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Merge, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - testing::Values(2, 3, 4))); - -////////////////////////////////////////////////////////////////////// -// Split - -GPU_PERF_TEST(Split, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); - - cv::Mat src(size, CV_MAKE_TYPE(depth, channels), cv::Scalar(1, 2, 3, 4)); - - std::vector dst; - - cv::split(src, dst); - - TEST_CYCLE() - { - cv::split(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Split, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - testing::Values(2, 3, 4))); - -////////////////////////////////////////////////////////////////////// -// Add_Mat - -GPU_PERF_TEST(Add_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src1(size, depth); - fill(src1, 0.0, 100.0); - - cv::Mat src2(size, depth); - fill(src2, 0.0, 100.0); - - cv::Mat dst; - - cv::add(src1, src2, dst); - - TEST_CYCLE() - { - cv::add(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Add_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// Add_Scalar - -GPU_PERF_TEST(Add_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0.0, 100.0); - - cv::Scalar s(1, 2, 3, 4); - cv::Mat dst; - - cv::add(src, s, dst); - - TEST_CYCLE() - { - cv::add(src, s, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Add_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// Subtract_Mat - -GPU_PERF_TEST(Subtract_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src1(size, depth); - fill(src1, 0.0, 100.0); - - cv::Mat src2(size, depth); - fill(src2, 0.0, 100.0); - - cv::Mat dst; - - cv::subtract(src1, src2, dst); - - TEST_CYCLE() - { - cv::subtract(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Subtract_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// Subtract_Scalar - -GPU_PERF_TEST(Subtract_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0.0, 100.0); - - cv::Scalar s(1, 2, 3, 4); - cv::Mat dst; - - cv::subtract(src, s, dst); - - TEST_CYCLE() - { - cv::subtract(src, s, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Subtract_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// Multiply_Mat - -GPU_PERF_TEST(Multiply_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src1(size, depth); - fill(src1, 0.0, 100.0); - - cv::Mat src2(size, depth); - fill(src2, 0.0, 100.0); - - cv::Mat dst; - - cv::multiply(src1, src2, dst); - - TEST_CYCLE() - { - cv::multiply(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Multiply_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// Multiply_Scalar - -GPU_PERF_TEST(Multiply_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0.0, 100.0); - - cv::Scalar s(1, 2, 3, 4); - cv::Mat dst; - - cv::multiply(src, s, dst); - - TEST_CYCLE() - { - cv::multiply(src, s, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Multiply_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// Divide_Mat - -GPU_PERF_TEST(Divide_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src1(size, depth); - fill(src1, 0.0, 100.0); - - cv::Mat src2(size, depth); - fill(src2, 0.0, 100.0); - - cv::Mat dst; - - cv::divide(src1, src2, dst); - - TEST_CYCLE() - { - cv::divide(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Divide_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// Divide_Scalar - -GPU_PERF_TEST(Divide_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0.0, 100.0); - - cv::Scalar s(1, 2, 3, 4); - cv::Mat dst; - - cv::divide(src, s, dst); - - TEST_CYCLE() - { - cv::divide(src, s, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Divide_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// Divide_Scalar_Inv - -GPU_PERF_TEST(Divide_Scalar_Inv, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0.0, 100.0); - - double scale = 100.0; - cv::Mat dst; - - cv::divide(scale, src, dst); - - TEST_CYCLE() - { - cv::divide(scale, src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Divide_Scalar_Inv, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// AbsDiff_Mat - -GPU_PERF_TEST(AbsDiff_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src1(size, depth); - fill(src1, 0.0, 100.0); - - cv::Mat src2(size, depth); - fill(src2, 0.0, 100.0); - - cv::Mat dst; - - cv::absdiff(src1, src2, dst); - - TEST_CYCLE() - { - cv::absdiff(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, AbsDiff_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// AbsDiff_Scalar - -GPU_PERF_TEST(AbsDiff_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0.0, 100.0); - - cv::Scalar s(1, 2, 3, 4); - cv::Mat dst; - - cv::absdiff(src, s, dst); - - TEST_CYCLE() - { - cv::absdiff(src, s, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, AbsDiff_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// Sqrt - -GPU_PERF_TEST(Sqrt, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0.0, 100.0); - - cv::Mat dst; - - cv::sqrt(src, dst); - - TEST_CYCLE() - { - cv::sqrt(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Sqrt, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S, CV_32F))); - -////////////////////////////////////////////////////////////////////// -// Log - -GPU_PERF_TEST(Log, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 1.0, 100.0); - - cv::Mat dst; - - cv::log(src, dst); - - TEST_CYCLE() - { - cv::log(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Log, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S, CV_32F))); - -////////////////////////////////////////////////////////////////////// -// Exp - -GPU_PERF_TEST(Exp, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 1.0, 10.0); - - cv::Mat dst; - - cv::exp(src, dst); - - TEST_CYCLE() - { - cv::exp(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Exp, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S, CV_32F))); - -////////////////////////////////////////////////////////////////////// -// Pow - -GPU_PERF_TEST(Pow, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 1.0, 10.0); - - cv::Mat dst; - - cv::pow(src, 2.3, dst); - - TEST_CYCLE() - { - cv::pow(src, 2.3, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Pow, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16S, CV_32F))); - -////////////////////////////////////////////////////////////////////// -// Compare_Mat - -CV_ENUM(CmpCode, cv::CMP_EQ, cv::CMP_GT, cv::CMP_GE, cv::CMP_LT, cv::CMP_LE, cv::CMP_NE) -#define ALL_CMP_CODES testing::Values(CmpCode(cv::CMP_EQ), CmpCode(cv::CMP_NE), CmpCode(cv::CMP_GT), CmpCode(cv::CMP_GE), CmpCode(cv::CMP_LT), CmpCode(cv::CMP_LE)) - -GPU_PERF_TEST(Compare_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth, CmpCode) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int cmp_code = GET_PARAM(3); - - cv::Mat src1(size, depth); - fill(src1, 0, 100.0); - - cv::Mat src2(size, depth); - fill(src2, 0, 100.0); - - cv::Mat dst; - - cv::compare(src1, src2, dst, cmp_code); - - TEST_CYCLE() - { - cv::compare(src1, src2, dst, cmp_code); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Compare_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - ALL_CMP_CODES)); - -////////////////////////////////////////////////////////////////////// -// Compare_Scalar - -GPU_PERF_TEST(Compare_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth, CmpCode) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int cmp_code = GET_PARAM(3); - - cv::Mat src(size, depth); - fill(src, 0, 100.0); - - cv::Scalar s = cv::Scalar::all(50); - cv::Mat dst; - - cv::compare(src, s, dst, cmp_code); - - TEST_CYCLE() - { - cv::compare(src, s, dst, cmp_code); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Compare_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - ALL_CMP_CODES)); - -////////////////////////////////////////////////////////////////////// -// Bitwise_Not - -GPU_PERF_TEST(Bitwise_Not, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0, 100.0); - - cv::Mat dst; - - cv::bitwise_not(src, dst); - - TEST_CYCLE() - { - cv::bitwise_not(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Bitwise_Not, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S))); - -////////////////////////////////////////////////////////////////////// -// Bitwise_And_Mat - -GPU_PERF_TEST(Bitwise_And_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src1(size, depth); - fill(src1, 0, 100.0); - - cv::Mat src2(size, depth); - fill(src2, 0, 100.0); - - cv::Mat dst; - - cv::bitwise_and(src1, src2, dst); - - TEST_CYCLE() - { - cv::bitwise_and(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Bitwise_And_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S))); - -////////////////////////////////////////////////////////////////////// -// Bitwise_And_Scalar - -GPU_PERF_TEST(Bitwise_And_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); - - int type = CV_MAKE_TYPE(depth, channels); - - cv::Mat src(size, type); - fill(src, 0, 100.0); - - cv::Scalar s = cv::Scalar(50, 50, 50, 50); - cv::Mat dst; - - cv::bitwise_and(src, s, dst); - - TEST_CYCLE() - { - cv::bitwise_and(src, s, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Bitwise_And_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S), - testing::Values(1, 3, 4))); - -////////////////////////////////////////////////////////////////////// -// Bitwise_Or_Mat - -GPU_PERF_TEST(Bitwise_Or_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src1(size, depth); - fill(src1, 0, 100.0); - - cv::Mat src2(size, depth); - fill(src2, 0, 100.0); - - cv::Mat dst; - - cv::bitwise_or(src1, src2, dst); - - TEST_CYCLE() - { - cv::bitwise_or(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Bitwise_Or_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S))); - -////////////////////////////////////////////////////////////////////// -// Bitwise_Or_Scalar - -GPU_PERF_TEST(Bitwise_Or_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); - - int type = CV_MAKE_TYPE(depth, channels); - - cv::Mat src(size, type); - fill(src, 0, 100.0); - - cv::Scalar s = cv::Scalar(50, 50, 50, 50); - cv::Mat dst; - - cv::bitwise_or(src, s, dst); - - TEST_CYCLE() - { - cv::bitwise_or(src, s, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Bitwise_Or_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S), - testing::Values(1, 3, 4))); - -////////////////////////////////////////////////////////////////////// -// Bitwise_Xor_Mat - -GPU_PERF_TEST(Bitwise_Xor_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src1(size, depth); - fill(src1, 0, 100.0); - - cv::Mat src2(size, depth); - fill(src2, 0, 100.0); - - cv::Mat dst; - - cv::bitwise_xor(src1, src2, dst); - - TEST_CYCLE() - { - cv::bitwise_xor(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Bitwise_Xor_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S))); - -////////////////////////////////////////////////////////////////////// -// Bitwise_Xor_Scalar - -GPU_PERF_TEST(Bitwise_Xor_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); - - int type = CV_MAKE_TYPE(depth, channels); - - cv::Mat src(size, type); - fill(src, 0, 100.0); - - cv::Scalar s = cv::Scalar(50, 50, 50, 50); - cv::Mat dst; - - cv::bitwise_xor(src, s, dst); - - TEST_CYCLE() - { - cv::bitwise_xor(src, s, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Bitwise_Xor_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S), - testing::Values(1, 3, 4))); - -////////////////////////////////////////////////////////////////////// -// Min_Mat - -GPU_PERF_TEST(Min_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src1(size, depth); - fill(src1, 0, 255.0); - - cv::Mat src2(size, depth); - fill(src2, 0, 255.0); - - cv::Mat dst; - - cv::min(src1, src2, dst); - - TEST_CYCLE() - { - cv::min(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Min_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F))); - -////////////////////////////////////////////////////////////////////// -// Min_Scalar - -GPU_PERF_TEST(Min_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0, 255.0); - - double val = 50.0; - cv::Mat dst; - - cv::min(src, val, dst); - - TEST_CYCLE() - { - cv::min(src, val, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Min_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F))); - -////////////////////////////////////////////////////////////////////// -// Max_Mat - -GPU_PERF_TEST(Max_Mat, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src1(size, depth); - fill(src1, 0, 255.0); - - cv::Mat src2(size, depth); - fill(src2, 0, 255.0); - - cv::Mat dst; - - cv::max(src1, src2, dst); - - TEST_CYCLE() - { - cv::max(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Max_Mat, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F))); - -////////////////////////////////////////////////////////////////////// -// Max_Scalar - -GPU_PERF_TEST(Max_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0, 255.0); - - double val = 50.0; - cv::Mat dst; - - cv::max(src, val, dst); - - TEST_CYCLE() - { - cv::max(src, val, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Max_Scalar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F))); - -////////////////////////////////////////////////////////////////////// -// AddWeighted - -GPU_PERF_TEST(AddWeighted, cv::gpu::DeviceInfo, cv::Size, MatDepth, MatDepth, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth1 = GET_PARAM(2); - int depth2 = GET_PARAM(3); - int dst_depth = GET_PARAM(4); - - cv::Mat src1(size, depth1); - fill(src1, 0, 100.0); - - cv::Mat src2(size, depth2); - fill(src2, 0, 100.0); - - cv::Mat dst; - - cv::addWeighted(src1, 0.5, src2, 0.5, 10.0, dst, dst_depth); - - TEST_CYCLE() - { - cv::addWeighted(src1, 0.5, src2, 0.5, 10.0, dst, dst_depth); - } -} - -INSTANTIATE_TEST_CASE_P(Core, AddWeighted, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F), - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// GEMM - -CV_FLAGS(GemmFlags, 0, cv::GEMM_1_T, cv::GEMM_2_T, cv::GEMM_3_T) -#define ALL_GEMM_FLAGS testing::Values(GemmFlags(0), GemmFlags(cv::GEMM_1_T), GemmFlags(cv::GEMM_2_T), GemmFlags(cv::GEMM_3_T), GemmFlags(cv::GEMM_1_T | cv::GEMM_2_T), GemmFlags(cv::GEMM_1_T | cv::GEMM_3_T), GemmFlags(cv::GEMM_1_T | cv::GEMM_2_T | cv::GEMM_3_T)) - -GPU_PERF_TEST(GEMM, cv::gpu::DeviceInfo, cv::Size, MatType, GemmFlags) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int flags = GET_PARAM(3); - - cv::Mat src1(size, type); - fill(src1, 0.0, 10.0); - - cv::Mat src2(size, type); - fill(src2, 0.0, 10.0); - - cv::Mat src3(size, type); - fill(src3, 0.0, 10.0); - - cv::Mat dst; - - cv::gemm(src1, src2, 1.0, src3, 1.0, dst, flags); - - declare.time(50.0); - - TEST_CYCLE() - { - cv::gemm(src1, src2, 1.0, src3, 1.0, dst, flags); - } -} - -INSTANTIATE_TEST_CASE_P(Core, GEMM, testing::Combine( - ALL_DEVICES, - testing::Values(cv::Size(512, 512), cv::Size(1024, 1024)), - testing::Values(CV_32FC1, CV_32FC2, CV_64FC1, CV_64FC2), - ALL_GEMM_FLAGS)); - -////////////////////////////////////////////////////////////////////// -// Transpose - -GPU_PERF_TEST(Transpose, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0.0, 100.0); - - cv::Mat dst; - - cv::transpose(src, dst); - - TEST_CYCLE() - { - cv::transpose(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Transpose, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC1, CV_8UC4, CV_16UC2, CV_16SC2, CV_32SC1, CV_32SC2, CV_64FC1))); - -////////////////////////////////////////////////////////////////////// -// Flip - -enum {FLIP_BOTH = 0, FLIP_X = 1, FLIP_Y = -1}; -CV_ENUM(FlipCode, FLIP_BOTH, FLIP_X, FLIP_Y) -#define ALL_FLIP_CODES testing::Values(FlipCode(FLIP_BOTH), FlipCode(FLIP_X), FlipCode(FLIP_Y)) - -GPU_PERF_TEST(Flip, cv::gpu::DeviceInfo, cv::Size, MatType, FlipCode) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int flipCode = GET_PARAM(3); - - cv::Mat src(size, type); - fill(src, 0.0, 100.0); - - cv::Mat dst; - - cv::flip(src, dst, flipCode); - - TEST_CYCLE() - { - cv::flip(src, dst, flipCode); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Flip, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16UC1, CV_16UC3, CV_16UC4, CV_32FC1, CV_32FC3, CV_32FC4), - ALL_FLIP_CODES)); - -////////////////////////////////////////////////////////////////////// -// LUT_OneChannel - -GPU_PERF_TEST(LUT_OneChannel, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0.0, 100.0); - - cv::Mat lut(1, 256, CV_8UC1); - fill(lut, 0.0, 100.0); - - cv::Mat dst; - - cv::LUT(src, lut, dst); - - TEST_CYCLE() - { - cv::LUT(src, lut, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, LUT_OneChannel, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC1, CV_8UC3))); - -////////////////////////////////////////////////////////////////////// -// LUT_MultiChannel - -GPU_PERF_TEST(LUT_MultiChannel, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0.0, 100.0); - - cv::Mat lut(1, 256, CV_MAKE_TYPE(CV_8U, src.channels())); - fill(lut, 0.0, 100.0); - - cv::Mat dst; - - cv::LUT(src, lut, dst); - - TEST_CYCLE() - { - cv::LUT(src, lut, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, LUT_MultiChannel, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC3))); - -////////////////////////////////////////////////////////////////////// -// Magnitude_Complex - -GPU_PERF_TEST(Magnitude_Complex, cv::gpu::DeviceInfo, cv::Size) -{ - cv::Size size = GET_PARAM(1); - - cv::Mat src(size, CV_32FC2); - fill(src, -100.0, 100.0); - - cv::Mat srcs[2]; - cv::split(src, srcs); - - cv::Mat dst; - - cv::magnitude(srcs[0], srcs[1], dst); - - TEST_CYCLE() - { - cv::magnitude(srcs[0], srcs[1], dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Magnitude_Complex, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - -////////////////////////////////////////////////////////////////////// -// Magnitude - -GPU_PERF_TEST(Magnitude, cv::gpu::DeviceInfo, cv::Size) -{ - cv::Size size = GET_PARAM(1); - - cv::Mat src1(size, CV_32FC1); - fill(src1, -100.0, 100.0); - - cv::Mat src2(size, CV_32FC1); - fill(src2, -100.0, 100.0); - - cv::Mat dst; - - cv::magnitude(src1, src2, dst); - - TEST_CYCLE() - { - cv::magnitude(src1, src2, dst); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Magnitude, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - -////////////////////////////////////////////////////////////////////// -// Phase - -IMPLEMENT_PARAM_CLASS(AngleInDegrees, bool) - -GPU_PERF_TEST(Phase, cv::gpu::DeviceInfo, cv::Size, AngleInDegrees) -{ - cv::Size size = GET_PARAM(1); - bool angleInDegrees = GET_PARAM(2); - - cv::Mat src1(size, CV_32FC1); - fill(src1, -100.0, 100.0); - - cv::Mat src2(size, CV_32FC1); - fill(src2, -100.0, 100.0); - - cv::Mat dst; - - cv::phase(src1, src2, dst, angleInDegrees); - - TEST_CYCLE() - { - cv::phase(src1, src2, dst, angleInDegrees); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Phase, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(false, true))); - -////////////////////////////////////////////////////////////////////// -// CartToPolar - -GPU_PERF_TEST(CartToPolar, cv::gpu::DeviceInfo, cv::Size, AngleInDegrees) -{ - cv::Size size = GET_PARAM(1); - bool angleInDegrees = GET_PARAM(2); - - cv::Mat src1(size, CV_32FC1); - fill(src1, -100.0, 100.0); - - cv::Mat src2(size, CV_32FC1); - fill(src2, -100.0, 100.0); - - cv::Mat magnitude; - cv::Mat angle; - - cv::cartToPolar(src1, src2, magnitude, angle, angleInDegrees); - - TEST_CYCLE() - { - cv::cartToPolar(src1, src2, magnitude, angle, angleInDegrees); - } -} - -INSTANTIATE_TEST_CASE_P(Core, CartToPolar, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(false, true))); - -////////////////////////////////////////////////////////////////////// -// PolarToCart - -GPU_PERF_TEST(PolarToCart, cv::gpu::DeviceInfo, cv::Size, AngleInDegrees) -{ - cv::Size size = GET_PARAM(1); - bool angleInDegrees = GET_PARAM(2); - - cv::Mat magnitude(size, CV_32FC1); - fill(magnitude, 0.0, 100.0); - - cv::Mat angle(size, CV_32FC1); - fill(angle, 0.0, angleInDegrees ? 360.0 : 2 * CV_PI); - - cv::Mat x; - cv::Mat y; - - cv::polarToCart(magnitude, angle, x, y, angleInDegrees); - - TEST_CYCLE() - { - cv::polarToCart(magnitude, angle, x, y, angleInDegrees); - } -} - -INSTANTIATE_TEST_CASE_P(Core, PolarToCart, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(false, true))); - -////////////////////////////////////////////////////////////////////// -// MeanStdDev - -GPU_PERF_TEST(MeanStdDev, cv::gpu::DeviceInfo, cv::Size) -{ - cv::Size size = GET_PARAM(1); - - cv::Mat src(size, CV_8UC1); - fill(src, 0.0, 255.0); - - cv::Scalar mean; - cv::Scalar stddev; - - cv::meanStdDev(src, mean, stddev); - - TEST_CYCLE() - { - cv::meanStdDev(src, mean, stddev); - } -} - -INSTANTIATE_TEST_CASE_P(Core, MeanStdDev, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - -////////////////////////////////////////////////////////////////////// -// Norm - -GPU_PERF_TEST(Norm, cv::gpu::DeviceInfo, cv::Size, MatDepth, NormType) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int normType = GET_PARAM(3); - - cv::Mat src(size, depth); - fill(src, 0.0, 255.0); - - double dst; - cv::Mat buf; - - dst = cv::norm(src, normType); - - TEST_CYCLE() - { - dst = cv::norm(src, normType); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Norm, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32S, CV_32F), - testing::Values(NormType(cv::NORM_INF), NormType(cv::NORM_L1), NormType(cv::NORM_L2)))); - -////////////////////////////////////////////////////////////////////// -// NormDiff - -GPU_PERF_TEST(NormDiff, cv::gpu::DeviceInfo, cv::Size, NormType) -{ - cv::Size size = GET_PARAM(1); - int normType = GET_PARAM(2); - - cv::Mat src1(size, CV_8UC1); - fill(src1, 0.0, 255.0); - - cv::Mat src2(size, CV_8UC1); - fill(src2, 0.0, 255.0); - - double dst; - - dst = cv::norm(src1, src2, normType); - - TEST_CYCLE() - { - dst = cv::norm(src1, src2, normType); - } -} - -INSTANTIATE_TEST_CASE_P(Core, NormDiff, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(NormType(cv::NORM_INF), NormType(cv::NORM_L1), NormType(cv::NORM_L2)))); - -////////////////////////////////////////////////////////////////////// -// Sum - -GPU_PERF_TEST(Sum, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0.0, 255.0); - - cv::Scalar dst; - - dst = cv::sum(src); - - TEST_CYCLE() - { - dst = cv::sum(src); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Sum, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_16UC1, CV_16UC3, CV_16UC4, CV_32FC1, CV_32FC3, CV_32FC4))); - -////////////////////////////////////////////////////////////////////// -// MinMaxLoc - -GPU_PERF_TEST(MinMaxLoc, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0.0, 255.0); - - double minVal, maxVal; - cv::Point minLoc, maxLoc; - - cv::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc); - - TEST_CYCLE() - { - cv::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc); - } -} - -INSTANTIATE_TEST_CASE_P(Core, MinMaxLoc, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// CountNonZero - -GPU_PERF_TEST(CountNonZero, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0.0, 1.5); - - int dst; - - dst = cv::countNonZero(src); - - TEST_CYCLE() - { - dst = cv::countNonZero(src); - } -} - -INSTANTIATE_TEST_CASE_P(Core, CountNonZero, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_32F, CV_64F))); - -////////////////////////////////////////////////////////////////////// -// Reduce - -CV_ENUM(ReduceCode, CV_REDUCE_SUM, CV_REDUCE_AVG, CV_REDUCE_MAX, CV_REDUCE_MIN) -#define ALL_REDUCE_CODES testing::Values(CV_REDUCE_SUM, CV_REDUCE_AVG, CV_REDUCE_MAX, CV_REDUCE_MIN) - -enum {Rows = 0, Cols = 1}; -CV_ENUM(ReduceDim, Rows, Cols) - -GPU_PERF_TEST(Reduce, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channels, ReduceCode, ReduceDim) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int channels = GET_PARAM(3); - int reduceOp = GET_PARAM(4); - int dim = GET_PARAM(5); - - int type = CV_MAKE_TYPE(depth, channels); - - cv::Mat src(size, type); - fill(src, 0.0, 10.0); - - cv::Mat dst; - - cv::reduce(src, dst, dim, reduceOp); - - TEST_CYCLE() - { - cv::reduce(src, dst, dim, reduceOp); - } -} - -INSTANTIATE_TEST_CASE_P(Core, Reduce, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(CV_8U, CV_16U, CV_16S, CV_32F), - testing::Values(1, 2, 3, 4), - ALL_REDUCE_CODES, - testing::Values(ReduceDim(Rows), ReduceDim(Cols)))); - -#endif diff --git a/modules/gpu/perf_cpu/perf_cpu_precomp.cpp b/modules/gpu/perf_cpu/perf_cpu_precomp.cpp deleted file mode 100644 index d947dd0258..0000000000 --- a/modules/gpu/perf_cpu/perf_cpu_precomp.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "perf_cpu_precomp.hpp" diff --git a/modules/gpu/perf_cpu/perf_cpu_precomp.hpp b/modules/gpu/perf_cpu/perf_cpu_precomp.hpp deleted file mode 100644 index 12680c7a02..0000000000 --- a/modules/gpu/perf_cpu/perf_cpu_precomp.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wmissing-declarations" -# pragma GCC diagnostic ignored "-Wmissing-prototypes" //OSX -#endif - -#ifndef __OPENCV_PERF_CPU_PRECOMP_HPP__ -#define __OPENCV_PERF_CPU_PRECOMP_HPP__ - -#include -#include - -#include "cvconfig.h" - -#include "opencv2/ts/ts.hpp" -#include "opencv2/ts/ts_perf.hpp" - -#include "opencv2/core/core.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/gpu/gpu.hpp" -#include "opencv2/imgproc/imgproc.hpp" -#include "opencv2/video/video.hpp" -#include "opencv2/calib3d/calib3d.hpp" -#include "opencv2/nonfree/nonfree.hpp" -#include "opencv2/legacy/legacy.hpp" - -#include "perf_utility.hpp" - -#ifdef GTEST_CREATE_SHARED_LIBRARY -#error no modules except ts should have GTEST_CREATE_SHARED_LIBRARY defined -#endif - -#endif diff --git a/modules/gpu/perf_cpu/perf_features2d.cpp b/modules/gpu/perf_cpu/perf_features2d.cpp deleted file mode 100644 index 74579a64a2..0000000000 --- a/modules/gpu/perf_cpu/perf_features2d.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "perf_cpu_precomp.hpp" - -#ifdef HAVE_CUDA - -////////////////////////////////////////////////////////////////////// -// SURF - -GPU_PERF_TEST_1(SURF, cv::gpu::DeviceInfo) -{ - cv::Mat img = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - cv::SURF surf; - - std::vector keypoints; - cv::Mat descriptors; - - surf(img, cv::noArray(), keypoints, descriptors); - - declare.time(50.0); - - TEST_CYCLE() - { - keypoints.clear(); - surf(img, cv::noArray(), keypoints, descriptors); - } -} - -INSTANTIATE_TEST_CASE_P(Features2D, SURF, ALL_DEVICES); - -////////////////////////////////////////////////////////////////////// -// FAST - -GPU_PERF_TEST_1(FAST, cv::gpu::DeviceInfo) -{ - cv::Mat img = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - std::vector keypoints; - - cv::FAST(img, keypoints, 20); - - TEST_CYCLE() - { - keypoints.clear(); - cv::FAST(img, keypoints, 20); - } -} - -INSTANTIATE_TEST_CASE_P(Features2D, FAST, ALL_DEVICES); - -////////////////////////////////////////////////////////////////////// -// ORB - -GPU_PERF_TEST_1(ORB, cv::gpu::DeviceInfo) -{ - cv::Mat img = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - cv::ORB orb(4000); - - std::vector keypoints; - cv::Mat descriptors; - - orb(img, cv::noArray(), keypoints, descriptors); - - TEST_CYCLE() - { - keypoints.clear(); - orb(img, cv::noArray(), keypoints, descriptors); - } -} - -INSTANTIATE_TEST_CASE_P(Features2D, ORB, ALL_DEVICES); - -////////////////////////////////////////////////////////////////////// -// BruteForceMatcher_match - -IMPLEMENT_PARAM_CLASS(DescriptorSize, int) - -GPU_PERF_TEST(BruteForceMatcher_match, cv::gpu::DeviceInfo, DescriptorSize, NormType) -{ - int desc_size = GET_PARAM(1); - int normType = GET_PARAM(2); - - int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; - - cv::Mat query(3000, desc_size, type); - fill(query, 0.0, 10.0); - - cv::Mat train(3000, desc_size, type); - fill(train, 0.0, 10.0); - - cv::BFMatcher matcher(normType); - - std::vector matches; - - matcher.match(query, train, matches); - - declare.time(20.0); - - TEST_CYCLE() - { - matcher.match(query, train, matches); - } -} - -INSTANTIATE_TEST_CASE_P(Features2D, BruteForceMatcher_match, testing::Combine( - ALL_DEVICES, - testing::Values(DescriptorSize(64), DescriptorSize(128), DescriptorSize(256)), - testing::Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))); - -////////////////////////////////////////////////////////////////////// -// BruteForceMatcher_knnMatch - -IMPLEMENT_PARAM_CLASS(K, int) - -GPU_PERF_TEST(BruteForceMatcher_knnMatch, cv::gpu::DeviceInfo, DescriptorSize, K, NormType) -{ - int desc_size = GET_PARAM(1); - int k = GET_PARAM(2); - int normType = GET_PARAM(3); - - int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; - - cv::Mat query(3000, desc_size, type); - fill(query, 0.0, 10.0); - - cv::Mat train(3000, desc_size, type); - fill(train, 0.0, 10.0); - - cv::BFMatcher matcher(normType); - - std::vector< std::vector > matches; - - matcher.knnMatch(query, train, matches, k); - - declare.time(30.0); - - TEST_CYCLE() - { - matcher.knnMatch(query, train, matches, k); - } -} - -INSTANTIATE_TEST_CASE_P(Features2D, BruteForceMatcher_knnMatch, testing::Combine( - ALL_DEVICES, - testing::Values(DescriptorSize(64), DescriptorSize(128), DescriptorSize(256)), - testing::Values(K(2), K(3)), - testing::Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))); - -////////////////////////////////////////////////////////////////////// -// BruteForceMatcher_radiusMatch - -GPU_PERF_TEST(BruteForceMatcher_radiusMatch, cv::gpu::DeviceInfo, DescriptorSize, NormType) -{ - int desc_size = GET_PARAM(1); - int normType = GET_PARAM(2); - - int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; - - cv::Mat query(3000, desc_size, type); - fill(query, 0.0, 1.0); - - cv::Mat train(3000, desc_size, type); - fill(train, 0.0, 1.0); - - cv::BFMatcher matcher(normType); - - std::vector< std::vector > matches; - - matcher.radiusMatch(query, train, matches, 2.0); - - declare.time(30.0); - - TEST_CYCLE() - { - matcher.radiusMatch(query, train, matches, 2.0); - } -} - -INSTANTIATE_TEST_CASE_P(Features2D, BruteForceMatcher_radiusMatch, testing::Combine( - ALL_DEVICES, - testing::Values(DescriptorSize(64), DescriptorSize(128), DescriptorSize(256)), - testing::Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))); - -#endif diff --git a/modules/gpu/perf_cpu/perf_filters.cpp b/modules/gpu/perf_cpu/perf_filters.cpp deleted file mode 100644 index ab0be3bad9..0000000000 --- a/modules/gpu/perf_cpu/perf_filters.cpp +++ /dev/null @@ -1,283 +0,0 @@ -#include "perf_cpu_precomp.hpp" - -#ifdef HAVE_CUDA - -IMPLEMENT_PARAM_CLASS(KernelSize, int) - -////////////////////////////////////////////////////////////////////// -// Blur - -GPU_PERF_TEST(Blur, cv::gpu::DeviceInfo, cv::Size, MatType, KernelSize) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int ksize = GET_PARAM(3); - - cv::Mat src(size, type); - fill(src, 0.0, 255.0); - - cv::Mat dst; - - cv::blur(src, dst, cv::Size(ksize, ksize)); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::blur(src, dst, cv::Size(ksize, ksize)); - } -} - -INSTANTIATE_TEST_CASE_P(Filters, Blur, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)), - testing::Values(KernelSize(3), KernelSize(5), KernelSize(7)))); - -////////////////////////////////////////////////////////////////////// -// Sobel - -GPU_PERF_TEST(Sobel, cv::gpu::DeviceInfo, cv::Size, MatType, KernelSize) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int ksize = GET_PARAM(3); - - cv::Mat src(size, type); - fill(src, 0.0, 255.0); - - cv::Mat dst; - - cv::Sobel(src, dst, -1, 1, 1, ksize); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::Sobel(src, dst, -1, 1, 1, ksize); - } -} - -INSTANTIATE_TEST_CASE_P(Filters, Sobel, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1)), - testing::Values(KernelSize(3), KernelSize(5), KernelSize(7), KernelSize(9), KernelSize(11), KernelSize(13), KernelSize(15)))); - -////////////////////////////////////////////////////////////////////// -// Scharr - -GPU_PERF_TEST(Scharr, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0.0, 255.0); - - cv::Mat dst; - - cv::Scharr(src, dst, -1, 1, 0); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::Scharr(src, dst, -1, 1, 0); - } -} - -INSTANTIATE_TEST_CASE_P(Filters, Scharr, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1)))); - -////////////////////////////////////////////////////////////////////// -// GaussianBlur - -GPU_PERF_TEST(GaussianBlur, cv::gpu::DeviceInfo, cv::Size, MatType, KernelSize) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int ksize = GET_PARAM(3); - - cv::Mat src(size, type); - fill(src, 0.0, 255.0); - - cv::Mat dst; - - cv::GaussianBlur(src, dst, cv::Size(ksize, ksize), 0.5); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::GaussianBlur(src, dst, cv::Size(ksize, ksize), 0.5); - } -} - -INSTANTIATE_TEST_CASE_P(Filters, GaussianBlur, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1)), - testing::Values(KernelSize(3), KernelSize(5), KernelSize(7), KernelSize(9), KernelSize(11), KernelSize(13), KernelSize(15)))); - -////////////////////////////////////////////////////////////////////// -// Laplacian - -GPU_PERF_TEST(Laplacian, cv::gpu::DeviceInfo, cv::Size, MatType, KernelSize) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int ksize = GET_PARAM(3); - - cv::Mat src(size, type); - fill(src, 0.0, 255.0); - - cv::Mat dst; - - cv::Laplacian(src, dst, -1, ksize); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::Laplacian(src, dst, -1, ksize); - } -} - -INSTANTIATE_TEST_CASE_P(Filters, Laplacian, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1), MatType(CV_32FC4)), - testing::Values(KernelSize(1), KernelSize(3)))); - -////////////////////////////////////////////////////////////////////// -// Erode - -GPU_PERF_TEST(Erode, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0.0, 255.0); - - cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - - cv::Mat dst; - - cv::erode(src, dst, ker); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::erode(src, dst, ker); - } -} - -INSTANTIATE_TEST_CASE_P(Filters, Erode, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)))); - -////////////////////////////////////////////////////////////////////// -// Dilate - -GPU_PERF_TEST(Dilate, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0.0, 255.0); - - cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - - cv::Mat dst; - - cv::dilate(src, dst, ker); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::dilate(src, dst, ker); - } -} - -INSTANTIATE_TEST_CASE_P(Filters, Dilate, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)))); - -////////////////////////////////////////////////////////////////////// -// MorphologyEx - -CV_ENUM(MorphOp, cv::MORPH_OPEN, cv::MORPH_CLOSE, cv::MORPH_GRADIENT, cv::MORPH_TOPHAT, cv::MORPH_BLACKHAT) -#define ALL_MORPH_OPS testing::Values(MorphOp(cv::MORPH_OPEN), MorphOp(cv::MORPH_CLOSE), MorphOp(cv::MORPH_GRADIENT), MorphOp(cv::MORPH_TOPHAT), MorphOp(cv::MORPH_BLACKHAT)) - -GPU_PERF_TEST(MorphologyEx, cv::gpu::DeviceInfo, cv::Size, MatType, MorphOp) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int morphOp = GET_PARAM(3); - - cv::Mat src(size, type); - fill(src, 0.0, 255.0); - - cv::Mat dst; - - cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - - cv::morphologyEx(src, dst, morphOp, ker); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::morphologyEx(src, dst, morphOp, ker); - } -} - -INSTANTIATE_TEST_CASE_P(Filters, MorphologyEx, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)), - ALL_MORPH_OPS)); - -////////////////////////////////////////////////////////////////////// -// Filter2D - -GPU_PERF_TEST(Filter2D, cv::gpu::DeviceInfo, cv::Size, MatType, KernelSize) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int ksize = GET_PARAM(3); - - cv::Mat src(size, type); - fill(src, 0.0, 255.0); - - cv::Mat kernel(ksize, ksize, CV_32FC1); - fill(kernel, 0.0, 1.0); - - cv::Mat dst; - - cv::filter2D(src, dst, -1, kernel); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::filter2D(src, dst, -1, kernel); - } -} - -INSTANTIATE_TEST_CASE_P(Filters, Filter2D, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1), MatType(CV_32FC4)), - testing::Values(KernelSize(3), KernelSize(5), KernelSize(7), KernelSize(9), KernelSize(11), KernelSize(13), KernelSize(15)))); - -#endif diff --git a/modules/gpu/perf_cpu/perf_imgproc.cpp b/modules/gpu/perf_cpu/perf_imgproc.cpp deleted file mode 100644 index 1b3c0951c6..0000000000 --- a/modules/gpu/perf_cpu/perf_imgproc.cpp +++ /dev/null @@ -1,771 +0,0 @@ -#include "perf_cpu_precomp.hpp" - -#ifdef HAVE_CUDA - -////////////////////////////////////////////////////////////////////// -// Remap - -GPU_PERF_TEST(Remap, cv::gpu::DeviceInfo, cv::Size, MatType, Interpolation, BorderMode) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int interpolation = GET_PARAM(3); - int borderMode = GET_PARAM(4); - - cv::Mat src(size, type); - fill(src, 0, 255); - - cv::Mat xmap(size, CV_32FC1); - fill(xmap, 0, size.width); - - cv::Mat ymap(size, CV_32FC1); - fill(ymap, 0, size.height); - - cv::Mat dst; - - cv::remap(src, dst, xmap, ymap, interpolation, borderMode); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::remap(src, dst, xmap, ymap, interpolation, borderMode); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, Remap, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_CONSTANT), BorderMode(cv::BORDER_REFLECT), BorderMode(cv::BORDER_WRAP)))); - - -////////////////////////////////////////////////////////////////////// -// Resize - -IMPLEMENT_PARAM_CLASS(Scale, double) - -GPU_PERF_TEST(Resize, cv::gpu::DeviceInfo, cv::Size, MatType, Interpolation, Scale) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int interpolation = GET_PARAM(3); - double f = GET_PARAM(4); - - cv::Mat src(size, type); - fill(src, 0, 255); - - cv::Mat dst; - - cv::resize(src, dst, cv::Size(), f, f, interpolation); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::resize(src, dst, cv::Size(), f, f, interpolation); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, Resize, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), - Interpolation(cv::INTER_CUBIC), Interpolation(cv::INTER_AREA)), - testing::Values(Scale(0.5), Scale(0.3), Scale(2.0)))); - -GPU_PERF_TEST(ResizeArea, cv::gpu::DeviceInfo, cv::Size, MatType, Scale) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int interpolation = cv::INTER_AREA; - double f = GET_PARAM(3); - - cv::Mat src_host(size, type); - fill(src_host, 0, 255); - - cv::Mat src(src_host); - cv::Mat dst; - - cv::resize(src, dst, cv::Size(), f, f, interpolation); - - declare.time(1.0); - - TEST_CYCLE() - { - cv::resize(src, dst, cv::Size(), f, f, interpolation); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, ResizeArea, testing::Combine( - ALL_DEVICES, - testing::Values(perf::sz1080p, cv::Size(4096, 2048)), - testing::Values(MatType(CV_8UC1)/*, MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)*/), - testing::Values(Scale(0.2),Scale(0.1),Scale(0.05)))); - -////////////////////////////////////////////////////////////////////// -// WarpAffine - -GPU_PERF_TEST(WarpAffine, cv::gpu::DeviceInfo, cv::Size, MatType, Interpolation, BorderMode) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int interpolation = GET_PARAM(3); - int borderMode = GET_PARAM(4); - - cv::Mat src(size, type); - fill(src, 0, 255); - - cv::Mat dst; - - const double aplha = CV_PI / 4; - double mat[2][3] = { {std::cos(aplha), -std::sin(aplha), src.cols / 2}, - {std::sin(aplha), std::cos(aplha), 0}}; - cv::Mat M(2, 3, CV_64F, (void*) mat); - - cv::warpAffine(src, dst, M, size, interpolation, borderMode); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::warpAffine(src, dst, M, size, interpolation, borderMode); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, WarpAffine, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_CONSTANT), BorderMode(cv::BORDER_REFLECT), BorderMode(cv::BORDER_WRAP)))); - -////////////////////////////////////////////////////////////////////// -// WarpPerspective - -GPU_PERF_TEST(WarpPerspective, cv::gpu::DeviceInfo, cv::Size, MatType, Interpolation, BorderMode) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int interpolation = GET_PARAM(3); - int borderMode = GET_PARAM(4); - - cv::Mat src(size, type); - fill(src, 0, 255); - - cv::Mat dst; - - const double aplha = CV_PI / 4; - double mat[3][3] = { {std::cos(aplha), -std::sin(aplha), src.cols / 2}, - {std::sin(aplha), std::cos(aplha), 0}, - {0.0, 0.0, 1.0}}; - cv::Mat M(3, 3, CV_64F, (void*) mat); - - cv::warpPerspective(src, dst, M, size, interpolation, borderMode); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::warpPerspective(src, dst, M, size, interpolation, borderMode); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, WarpPerspective, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_CONSTANT), BorderMode(cv::BORDER_REFLECT), BorderMode(cv::BORDER_WRAP)))); - -////////////////////////////////////////////////////////////////////// -// CopyMakeBorder - -GPU_PERF_TEST(CopyMakeBorder, cv::gpu::DeviceInfo, cv::Size, MatType, BorderMode) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - int borderType = GET_PARAM(3); - - cv::Mat src(size, type); - fill(src, 0, 255); - - cv::Mat dst; - - cv::copyMakeBorder(src, dst, 5, 5, 5, 5, borderType); - - TEST_CYCLE() - { - cv::copyMakeBorder(src, dst, 5, 5, 5, 5, borderType); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, CopyMakeBorder, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_CONSTANT), BorderMode(cv::BORDER_REFLECT), BorderMode(cv::BORDER_WRAP)))); - -////////////////////////////////////////////////////////////////////// -// Threshold - -CV_ENUM(ThreshOp, cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC, cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV) -#define ALL_THRESH_OPS testing::Values(ThreshOp(cv::THRESH_BINARY), ThreshOp(cv::THRESH_BINARY_INV), ThreshOp(cv::THRESH_TRUNC), ThreshOp(cv::THRESH_TOZERO), ThreshOp(cv::THRESH_TOZERO_INV)) - -GPU_PERF_TEST(Threshold, cv::gpu::DeviceInfo, cv::Size, MatDepth, ThreshOp) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - int threshOp = GET_PARAM(3); - - cv::Mat src(size, depth); - fill(src, 0, 255); - - cv::Mat dst; - - cv::threshold(src, dst, 100.0, 255.0, threshOp); - - TEST_CYCLE() - { - cv::threshold(src, dst, 100.0, 255.0, threshOp); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, Threshold, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_32F), MatDepth(CV_64F)), - ALL_THRESH_OPS)); - -////////////////////////////////////////////////////////////////////// -// Integral - -GPU_PERF_TEST(Integral, cv::gpu::DeviceInfo, cv::Size) -{ - cv::Size size = GET_PARAM(1); - - cv::Mat src(size, CV_8UC1); - fill(src, 0, 255); - - cv::Mat dst; - - cv::integral(src, dst); - - TEST_CYCLE() - { - cv::integral(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, Integral, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - -////////////////////////////////////////////////////////////////////// -// HistEven_OneChannel - -GPU_PERF_TEST(HistEven_OneChannel, cv::gpu::DeviceInfo, cv::Size, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - - cv::Mat src(size, depth); - fill(src, 0, 255); - - int hbins = 30; - float hranges[] = {0.0f, 180.0f}; - cv::Mat hist; - int histSize[] = {hbins}; - const float* ranges[] = {hranges}; - int channels[] = {0}; - - cv::calcHist(&src, 1, channels, cv::Mat(), hist, 1, histSize, ranges); - - TEST_CYCLE() - { - cv::calcHist(&src, 1, channels, cv::Mat(), hist, 1, histSize, ranges); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, HistEven_OneChannel, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_16S)))); - -////////////////////////////////////////////////////////////////////// -// EqualizeHist - -GPU_PERF_TEST(EqualizeHist, cv::gpu::DeviceInfo, cv::Size) -{ - cv::Size size = GET_PARAM(1); - - cv::Mat src(size, CV_8UC1); - fill(src, 0, 255); - - cv::Mat dst; - - cv::equalizeHist(src, dst); - - TEST_CYCLE() - { - cv::equalizeHist(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, EqualizeHist, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES)); - -////////////////////////////////////////////////////////////////////// -// Canny - -IMPLEMENT_PARAM_CLASS(AppertureSize, int) -IMPLEMENT_PARAM_CLASS(L2gradient, bool) - -GPU_PERF_TEST(Canny, cv::gpu::DeviceInfo, AppertureSize, L2gradient) -{ - int apperture_size = GET_PARAM(1); - bool useL2gradient = GET_PARAM(2); - - cv::Mat image = readImage("perf/1280x1024.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(image.empty()); - - cv::Mat dst; - - cv::Canny(image, dst, 50.0, 100.0, apperture_size, useL2gradient); - - TEST_CYCLE() - { - cv::Canny(image, dst, 50.0, 100.0, apperture_size, useL2gradient); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, Canny, testing::Combine( - ALL_DEVICES, - testing::Values(AppertureSize(3), AppertureSize(5)), - testing::Values(L2gradient(false), L2gradient(true)))); - -////////////////////////////////////////////////////////////////////// -// MeanShiftFiltering - -GPU_PERF_TEST_1(MeanShiftFiltering, cv::gpu::DeviceInfo) -{ - cv::Mat img = readImage("gpu/meanshift/cones.png"); - ASSERT_FALSE(img.empty()); - - cv::Mat dst; - - cv::pyrMeanShiftFiltering(img, dst, 50, 50); - - declare.time(15.0); - - TEST_CYCLE() - { - cv::pyrMeanShiftFiltering(img, dst, 50, 50); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, MeanShiftFiltering, ALL_DEVICES); - -////////////////////////////////////////////////////////////////////// -// Convolve - -IMPLEMENT_PARAM_CLASS(KSize, int) -IMPLEMENT_PARAM_CLASS(Ccorr, bool) - -GPU_PERF_TEST(Convolve, cv::gpu::DeviceInfo, cv::Size, KSize, Ccorr) -{ - cv::Size size = GET_PARAM(1); - int templ_size = GET_PARAM(2); - bool ccorr = GET_PARAM(3); - - ASSERT_FALSE(ccorr); - - cv::Mat image(size, CV_32FC1); - image.setTo(1.0); - - cv::Mat templ(templ_size, templ_size, CV_32FC1); - templ.setTo(1.0); - - cv::Mat dst; - - cv::filter2D(image, dst, image.depth(), templ); - - declare.time(10.0); - - TEST_CYCLE() - { - cv::filter2D(image, dst, image.depth(), templ); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, Convolve, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(KSize(3), KSize(9), KSize(17), KSize(27), KSize(32), KSize(64)), - testing::Values(Ccorr(false), Ccorr(true)))); - -//////////////////////////////////////////////////////////////////////////////// -// MatchTemplate_8U - -CV_ENUM(TemplateMethod, cv::TM_SQDIFF, cv::TM_SQDIFF_NORMED, cv::TM_CCORR, cv::TM_CCORR_NORMED, cv::TM_CCOEFF, cv::TM_CCOEFF_NORMED) -#define ALL_TEMPLATE_METHODS testing::Values(TemplateMethod(cv::TM_SQDIFF), TemplateMethod(cv::TM_SQDIFF_NORMED), TemplateMethod(cv::TM_CCORR), TemplateMethod(cv::TM_CCORR_NORMED), TemplateMethod(cv::TM_CCOEFF), TemplateMethod(cv::TM_CCOEFF_NORMED)) - -IMPLEMENT_PARAM_CLASS(TemplateSize, cv::Size) - -GPU_PERF_TEST(MatchTemplate_8U, cv::gpu::DeviceInfo, cv::Size, TemplateSize, Channels, TemplateMethod) -{ - cv::Size size = GET_PARAM(1); - cv::Size templ_size = GET_PARAM(2); - int cn = GET_PARAM(3); - int method = GET_PARAM(4); - - cv::Mat image(size, CV_MAKE_TYPE(CV_8U, cn)); - fill(image, 0, 255); - - cv::Mat templ(templ_size, CV_MAKE_TYPE(CV_8U, cn)); - fill(templ, 0, 255); - - cv::Mat dst; - - cv::matchTemplate(image, templ, dst, method); - - TEST_CYCLE() - { - cv::matchTemplate(image, templ, dst, method); - } -}; - -INSTANTIATE_TEST_CASE_P(ImgProc, MatchTemplate_8U, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(TemplateSize(cv::Size(5, 5)), TemplateSize(cv::Size(16, 16)), TemplateSize(cv::Size(30, 30))), - testing::Values(Channels(1), Channels(3), Channels(4)), - ALL_TEMPLATE_METHODS)); - -//////////////////////////////////////////////////////////////////////////////// -// MatchTemplate_32F - -GPU_PERF_TEST(MatchTemplate_32F, cv::gpu::DeviceInfo, cv::Size, TemplateSize, Channels, TemplateMethod) -{ - cv::Size size = GET_PARAM(1); - cv::Size templ_size = GET_PARAM(2); - int cn = GET_PARAM(3); - int method = GET_PARAM(4); - - cv::Mat image(size, CV_MAKE_TYPE(CV_32F, cn)); - fill(image, 0, 255); - - cv::Mat templ(templ_size, CV_MAKE_TYPE(CV_32F, cn)); - fill(templ, 0, 255); - - cv::Mat dst; - - cv::matchTemplate(image, templ, dst, method); - - TEST_CYCLE() - { - cv::matchTemplate(image, templ, dst, method); - } -}; - -INSTANTIATE_TEST_CASE_P(ImgProc, MatchTemplate_32F, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(TemplateSize(cv::Size(5, 5)), TemplateSize(cv::Size(16, 16)), TemplateSize(cv::Size(30, 30))), - testing::Values(Channels(1), Channels(3), Channels(4)), - testing::Values(TemplateMethod(cv::TM_SQDIFF), TemplateMethod(cv::TM_CCORR)))); - -////////////////////////////////////////////////////////////////////// -// MulSpectrums - -CV_FLAGS(DftFlags, 0, cv::DFT_INVERSE, cv::DFT_SCALE, cv::DFT_ROWS, cv::DFT_COMPLEX_OUTPUT, cv::DFT_REAL_OUTPUT) - -GPU_PERF_TEST(MulSpectrums, cv::gpu::DeviceInfo, cv::Size, DftFlags) -{ - cv::Size size = GET_PARAM(1); - int flag = GET_PARAM(2); - - cv::Mat a(size, CV_32FC2); - fill(a, 0, 100); - - cv::Mat b(size, CV_32FC2); - fill(b, 0, 100); - - cv::Mat dst; - - cv::mulSpectrums(a, b, dst, flag); - - TEST_CYCLE() - { - cv::mulSpectrums(a, b, dst, flag); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, MulSpectrums, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(DftFlags(0), DftFlags(cv::DFT_ROWS)))); - -////////////////////////////////////////////////////////////////////// -// Dft - -GPU_PERF_TEST(Dft, cv::gpu::DeviceInfo, cv::Size, DftFlags) -{ - cv::Size size = GET_PARAM(1); - int flag = GET_PARAM(2); - - cv::Mat src(size, CV_32FC2); - fill(src, 0, 100); - - cv::Mat dst; - - cv::dft(src, dst, flag); - - declare.time(10.0); - - TEST_CYCLE() - { - cv::dft(src, dst, flag); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, Dft, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(DftFlags(0), DftFlags(cv::DFT_ROWS), DftFlags(cv::DFT_INVERSE)))); - -////////////////////////////////////////////////////////////////////// -// CornerHarris - -IMPLEMENT_PARAM_CLASS(BlockSize, int) -IMPLEMENT_PARAM_CLASS(ApertureSize, int) - -GPU_PERF_TEST(CornerHarris, cv::gpu::DeviceInfo, MatType, BorderMode, BlockSize, ApertureSize) -{ - int type = GET_PARAM(1); - int borderType = GET_PARAM(2); - int blockSize = GET_PARAM(3); - int apertureSize = GET_PARAM(4); - - cv::Mat img = readImage("gpu/stereobm/aloe-L.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - img.convertTo(img, type, type == CV_32F ? 1.0 / 255.0 : 1.0); - - cv::Mat dst; - - double k = 0.5; - - cv::cornerHarris(img, dst, blockSize, apertureSize, k, borderType); - - TEST_CYCLE() - { - cv::cornerHarris(img, dst, blockSize, apertureSize, k, borderType); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, CornerHarris, testing::Combine( - ALL_DEVICES, - testing::Values(MatType(CV_8UC1), MatType(CV_32FC1)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_REFLECT)), - testing::Values(BlockSize(3), BlockSize(5), BlockSize(7)), - testing::Values(ApertureSize(0), ApertureSize(3), ApertureSize(5), ApertureSize(7)))); - -////////////////////////////////////////////////////////////////////// -// CornerMinEigenVal - -GPU_PERF_TEST(CornerMinEigenVal, cv::gpu::DeviceInfo, MatType, BorderMode, BlockSize, ApertureSize) -{ - int type = GET_PARAM(1); - int borderType = GET_PARAM(2); - int blockSize = GET_PARAM(3); - int apertureSize = GET_PARAM(4); - - cv::Mat img = readImage("gpu/stereobm/aloe-L.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - img.convertTo(img, type, type == CV_32F ? 1.0 / 255.0 : 1.0); - - cv::Mat dst; - - cv::cornerMinEigenVal(img, dst, blockSize, apertureSize, borderType); - - TEST_CYCLE() - { - cv::cornerMinEigenVal(img, dst, blockSize, apertureSize, borderType); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, CornerMinEigenVal, testing::Combine( - ALL_DEVICES, - testing::Values(MatType(CV_8UC1), MatType(CV_32FC1)), - testing::Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_REFLECT)), - testing::Values(BlockSize(3), BlockSize(5), BlockSize(7)), - testing::Values(ApertureSize(0), ApertureSize(3), ApertureSize(5), ApertureSize(7)))); - -////////////////////////////////////////////////////////////////////// -// PyrDown - -GPU_PERF_TEST(PyrDown, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0, 255); - - cv::Mat dst; - - cv::pyrDown(src, dst); - - TEST_CYCLE() - { - cv::pyrDown(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, PyrDown, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)))); - -////////////////////////////////////////////////////////////////////// -// PyrUp - -GPU_PERF_TEST(PyrUp, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0, 255); - - cv::Mat dst; - - cv::pyrUp(src, dst); - - TEST_CYCLE() - { - cv::pyrUp(src, dst); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, PyrUp, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)))); - -////////////////////////////////////////////////////////////////////// -// CvtColor - -GPU_PERF_TEST(CvtColor, cv::gpu::DeviceInfo, cv::Size, MatDepth, CvtColorInfo) -{ - cv::Size size = GET_PARAM(1); - int depth = GET_PARAM(2); - CvtColorInfo info = GET_PARAM(3); - - cv::Mat src(size, CV_MAKETYPE(depth, info.scn)); - fill(src, 0, 255); - - cv::Mat dst; - - cv::cvtColor(src, dst, info.code, info.dcn); - - TEST_CYCLE() - { - cv::cvtColor(src, dst, info.code, info.dcn); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, CvtColor, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_32F)), - testing::Values(CvtColorInfo(4, 4, cv::COLOR_RGBA2BGRA), - CvtColorInfo(4, 1, cv::COLOR_BGRA2GRAY), - CvtColorInfo(1, 4, cv::COLOR_GRAY2BGRA), - CvtColorInfo(3, 3, cv::COLOR_BGR2XYZ), - CvtColorInfo(3, 3, cv::COLOR_XYZ2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2YCrCb), - CvtColorInfo(3, 3, cv::COLOR_YCrCb2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2YUV), - CvtColorInfo(3, 3, cv::COLOR_YUV2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2HSV), - CvtColorInfo(3, 3, cv::COLOR_HSV2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2HLS), - CvtColorInfo(3, 3, cv::COLOR_HLS2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2Lab), - CvtColorInfo(3, 3, cv::COLOR_RGB2Lab), - CvtColorInfo(3, 3, cv::COLOR_BGR2Luv), - CvtColorInfo(3, 3, cv::COLOR_RGB2Luv), - CvtColorInfo(3, 3, cv::COLOR_Lab2BGR), - CvtColorInfo(3, 3, cv::COLOR_Lab2RGB), - CvtColorInfo(3, 3, cv::COLOR_Luv2BGR), - CvtColorInfo(3, 3, cv::COLOR_Luv2RGB), - CvtColorInfo(1, 3, cv::COLOR_BayerBG2BGR), - CvtColorInfo(1, 3, cv::COLOR_BayerGB2BGR), - CvtColorInfo(1, 3, cv::COLOR_BayerRG2BGR), - CvtColorInfo(1, 3, cv::COLOR_BayerGR2BGR), - CvtColorInfo(4, 4, cv::COLOR_RGBA2mRGBA)))); - -////////////////////////////////////////////////////////////////////// -// HoughLines - -IMPLEMENT_PARAM_CLASS(DoSort, bool) - -GPU_PERF_TEST(HoughLines, cv::gpu::DeviceInfo, cv::Size, DoSort) -{ - declare.time(30.0); - - const cv::Size size = GET_PARAM(1); - - const float rho = 1.0f; - const float theta = CV_PI / 180.0f; - const int threshold = 300; - - cv::RNG rng(123456789); - - cv::Mat src(size, CV_8UC1, cv::Scalar::all(0)); - - const int numLines = rng.uniform(500, 2000); - for (int i = 0; i < numLines; ++i) - { - cv::Point p1(rng.uniform(0, src.cols), rng.uniform(0, src.rows)); - cv::Point p2(rng.uniform(0, src.cols), rng.uniform(0, src.rows)); - cv::line(src, p1, p2, cv::Scalar::all(255), 2); - } - - std::vector lines; - cv::HoughLines(src, lines, rho, theta, threshold); - - TEST_CYCLE() - { - cv::HoughLines(src, lines, rho, theta, threshold); - } -} - -INSTANTIATE_TEST_CASE_P(ImgProc, HoughLines, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(DoSort(false), DoSort(true)))); - -#endif diff --git a/modules/gpu/perf_cpu/perf_labeling.cpp b/modules/gpu/perf_cpu/perf_labeling.cpp deleted file mode 100644 index ddf9c3d9bb..0000000000 --- a/modules/gpu/perf_cpu/perf_labeling.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -//M*/ - -#include "perf_precomp.hpp" - -#ifdef HAVE_CUDA - -namespace { - - struct GreedyLabeling - { - struct dot - { - int x; - int y; - - static dot make(int i, int j) - { - dot d; d.x = i; d.y = j; - return d; - } - }; - - struct InInterval - { - InInterval(const int& _lo, const int& _hi) : lo(-_lo), hi(_hi) {}; - const int lo, hi; - - bool operator() (const unsigned char a, const unsigned char b) const - { - int d = a - b; - return lo <= d && d <= hi; - } - }; - - GreedyLabeling(cv::Mat img) - : image(img), _labels(image.size(), CV_32SC1, cv::Scalar::all(-1)) {stack = new dot[image.cols * image.rows];} - - ~GreedyLabeling(){delete[] stack;} - - void operator() (cv::Mat labels) const - { - labels.setTo(cv::Scalar::all(-1)); - InInterval inInt(0, 2); - int cc = -1; - - int* dist_labels = (int*)labels.data; - int pitch = labels.step1(); - - unsigned char* source = (unsigned char*)image.data; - int width = image.cols; - int height = image.rows; - - for (int j = 0; j < image.rows; ++j) - for (int i = 0; i < image.cols; ++i) - { - if (dist_labels[j * pitch + i] != -1) continue; - - dot* top = stack; - dot p = dot::make(i, j); - cc++; - - dist_labels[j * pitch + i] = cc; - - while (top >= stack) - { - int* dl = &dist_labels[p.y * pitch + p.x]; - unsigned char* sp = &source[p.y * image.step1() + p.x]; - - dl[0] = cc; - - //right - if( p.x < (width - 1) && dl[ +1] == -1 && inInt(sp[0], sp[+1])) - *top++ = dot::make(p.x + 1, p.y); - - //left - if( p.x > 0 && dl[-1] == -1 && inInt(sp[0], sp[-1])) - *top++ = dot::make(p.x - 1, p.y); - - //bottom - if( p.y < (height - 1) && dl[+pitch] == -1 && inInt(sp[0], sp[+image.step1()])) - *top++ = dot::make(p.x, p.y + 1); - - //top - if( p.y > 0 && dl[-pitch] == -1 && inInt(sp[0], sp[-image.step1()])) - *top++ = dot::make(p.x, p.y - 1); - - p = *--top; - } - } - } - - cv::Mat image; - cv::Mat _labels; - dot* stack; - }; -} - -GPU_PERF_TEST(ConnectedComponents, cv::gpu::DeviceInfo, cv::Size) -{ - cv::gpu::DeviceInfo devInfo = GET_PARAM(0); - cv::gpu::setDevice(devInfo.deviceID()); - - cv::Mat image = readImage("gpu/labeling/aloe-disp.png", cv::IMREAD_GRAYSCALE); - - GreedyLabeling host(image); - - host(host._labels); - - declare.time(1.0); - - TEST_CYCLE() - { - host(host._labels); - } -} - -INSTANTIATE_TEST_CASE_P(Labeling, ConnectedComponents, testing::Combine(ALL_DEVICES, testing::Values(cv::Size(261, 262)))); - -#endif \ No newline at end of file diff --git a/modules/gpu/perf_cpu/perf_main.cpp b/modules/gpu/perf_cpu/perf_main.cpp deleted file mode 100644 index 6fcf56d0b0..0000000000 --- a/modules/gpu/perf_cpu/perf_main.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "perf_cpu_precomp.hpp" - -#ifdef HAVE_CUDA - -int main(int argc, char **argv) -{ - testing::InitGoogleTest(&argc, argv); - perf::TestBase::Init(argc, argv); - return RUN_ALL_TESTS(); -} - -#else - -int main() -{ - printf("OpenCV was built without CUDA support\n"); - return 0; -} - -#endif diff --git a/modules/gpu/perf_cpu/perf_matop.cpp b/modules/gpu/perf_cpu/perf_matop.cpp deleted file mode 100644 index 7c46eee80e..0000000000 --- a/modules/gpu/perf_cpu/perf_matop.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "perf_cpu_precomp.hpp" - -#ifdef HAVE_CUDA - -////////////////////////////////////////////////////////////////////// -// SetTo - -GPU_PERF_TEST(SetTo, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - cv::Scalar val(1, 2, 3, 4); - - src.setTo(val); - - TEST_CYCLE() - { - src.setTo(val); - } -} - -INSTANTIATE_TEST_CASE_P(MatOp, SetTo, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4), - MatType(CV_64FC1), MatType(CV_64FC3), MatType(CV_64FC4)))); - -////////////////////////////////////////////////////////////////////// -// SetToMasked - -GPU_PERF_TEST(SetToMasked, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0, 255); - - cv::Mat mask(size, CV_8UC1); - fill(mask, 0, 2); - - cv::Scalar val(1, 2, 3, 4); - - src.setTo(val, mask); - - TEST_CYCLE() - { - src.setTo(val, mask); - } -} - -INSTANTIATE_TEST_CASE_P(MatOp, SetToMasked, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4), - MatType(CV_64FC1), MatType(CV_64FC3), MatType(CV_64FC4)))); - -////////////////////////////////////////////////////////////////////// -// CopyToMasked - -GPU_PERF_TEST(CopyToMasked, cv::gpu::DeviceInfo, cv::Size, MatType) -{ - cv::Size size = GET_PARAM(1); - int type = GET_PARAM(2); - - cv::Mat src(size, type); - fill(src, 0, 255); - - cv::Mat mask(size, CV_8UC1); - fill(mask, 0, 2); - - cv::Mat dst; - - src.copyTo(dst, mask); - - TEST_CYCLE() - { - src.copyTo(dst, mask); - } -} - -INSTANTIATE_TEST_CASE_P(MatOp, CopyToMasked, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), - MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), - MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4), - MatType(CV_64FC1), MatType(CV_64FC3), MatType(CV_64FC4)))); - -////////////////////////////////////////////////////////////////////// -// ConvertTo - -GPU_PERF_TEST(ConvertTo, cv::gpu::DeviceInfo, cv::Size, MatDepth, MatDepth) -{ - cv::Size size = GET_PARAM(1); - int depth1 = GET_PARAM(2); - int depth2 = GET_PARAM(3); - - cv::Mat src(size, depth1); - fill(src, 0, 255); - - cv::Mat dst; - - src.convertTo(dst, depth2, 0.5, 1.0); - - TEST_CYCLE() - { - src.convertTo(dst, depth2, 0.5, 1.0); - } -} - -INSTANTIATE_TEST_CASE_P(MatOp, ConvertTo, testing::Combine( - ALL_DEVICES, - GPU_TYPICAL_MAT_SIZES, - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_32F), MatDepth(CV_64F)), - testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_32F), MatDepth(CV_64F)))); - -#endif diff --git a/modules/gpu/perf_cpu/perf_objdetect.cpp b/modules/gpu/perf_cpu/perf_objdetect.cpp deleted file mode 100644 index d9ae2b7c8f..0000000000 --- a/modules/gpu/perf_cpu/perf_objdetect.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "perf_cpu_precomp.hpp" - -#ifdef HAVE_CUDA - -/////////////////////////////////////////////////////////////// -// HOG - -GPU_PERF_TEST_1(HOG, cv::gpu::DeviceInfo) -{ - cv::Mat img = readImage("gpu/hog/road.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - std::vector found_locations; - - cv::HOGDescriptor hog; - hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector()); - - hog.detectMultiScale(img, found_locations); - - TEST_CYCLE() - { - hog.detectMultiScale(img, found_locations); - } -} - -INSTANTIATE_TEST_CASE_P(ObjDetect, HOG, ALL_DEVICES); - -/////////////////////////////////////////////////////////////// -// HaarClassifier - -GPU_PERF_TEST_1(HaarClassifier, cv::gpu::DeviceInfo) -{ - cv::Mat img = readImage("gpu/haarcascade/group_1_640x480_VGA.pgm", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - cv::CascadeClassifier cascade; - - ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/perf/haarcascade_frontalface_alt.xml"))); - - std::vector rects; - - cascade.detectMultiScale(img, rects); - - TEST_CYCLE() - { - cascade.detectMultiScale(img, rects); - } -} - -INSTANTIATE_TEST_CASE_P(ObjDetect, HaarClassifier, ALL_DEVICES); - -//===================== LBP cascade ==========================// -GPU_PERF_TEST_1(LBPClassifier, cv::gpu::DeviceInfo) -{ - cv::Mat img = readImage("gpu/haarcascade/group_1_640x480_VGA.pgm", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - cv::CascadeClassifier cascade; - - ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/lbpcascade/lbpcascade_frontalface.xml"))); - - std::vector rects; - - cascade.detectMultiScale(img, rects); - - TEST_CYCLE() - { - cascade.detectMultiScale(img, rects); - } -} - -INSTANTIATE_TEST_CASE_P(ObjDetect, LBPClassifier, ALL_DEVICES); - -#endif diff --git a/modules/gpu/perf_cpu/perf_utility.cpp b/modules/gpu/perf_cpu/perf_utility.cpp deleted file mode 100644 index 541e6fdc7b..0000000000 --- a/modules/gpu/perf_cpu/perf_utility.cpp +++ /dev/null @@ -1,220 +0,0 @@ -#include "perf_cpu_precomp.hpp" - -using namespace std; -using namespace cv; -using namespace cv::gpu; - -void fill(Mat& m, double a, double b) -{ - RNG rng(123456789); - rng.fill(m, RNG::UNIFORM, a, b); -} - -void PrintTo(const CvtColorInfo& info, ostream* os) -{ - static const char* str[] = - { - "BGR2BGRA", - "BGRA2BGR", - "BGR2RGBA", - "RGBA2BGR", - "BGR2RGB", - "BGRA2RGBA", - - "BGR2GRAY", - "RGB2GRAY", - "GRAY2BGR", - "GRAY2BGRA", - "BGRA2GRAY", - "RGBA2GRAY", - - "BGR2BGR565", - "RGB2BGR565", - "BGR5652BGR", - "BGR5652RGB", - "BGRA2BGR565", - "RGBA2BGR565", - "BGR5652BGRA", - "BGR5652RGBA", - - "GRAY2BGR565", - "BGR5652GRAY", - - "BGR2BGR555", - "RGB2BGR555", - "BGR5552BGR", - "BGR5552RGB", - "BGRA2BGR555", - "RGBA2BGR555", - "BGR5552BGRA", - "BGR5552RGBA", - - "GRAY2BGR555", - "BGR5552GRAY", - - "BGR2XYZ", - "RGB2XYZ", - "XYZ2BGR", - "XYZ2RGB", - - "BGR2YCrCb", - "RGB2YCrCb", - "YCrCb2BGR", - "YCrCb2RGB", - - "BGR2HSV", - "RGB2HSV", - - "", - "", - - "BGR2Lab", - "RGB2Lab", - - "BayerBG2BGR", - "BayerGB2BGR", - "BayerRG2BGR", - "BayerGR2BGR", - - "BGR2Luv", - "RGB2Luv", - - "BGR2HLS", - "RGB2HLS", - - "HSV2BGR", - "HSV2RGB", - - "Lab2BGR", - "Lab2RGB", - "Luv2BGR", - "Luv2RGB", - - "HLS2BGR", - "HLS2RGB", - - "BayerBG2BGR_VNG", - "BayerGB2BGR_VNG", - "BayerRG2BGR_VNG", - "BayerGR2BGR_VNG", - - "BGR2HSV_FULL", - "RGB2HSV_FULL", - "BGR2HLS_FULL", - "RGB2HLS_FULL", - - "HSV2BGR_FULL", - "HSV2RGB_FULL", - "HLS2BGR_FULL", - "HLS2RGB_FULL", - - "LBGR2Lab", - "LRGB2Lab", - "LBGR2Luv", - "LRGB2Luv", - - "Lab2LBGR", - "Lab2LRGB", - "Luv2LBGR", - "Luv2LRGB", - - "BGR2YUV", - "RGB2YUV", - "YUV2BGR", - "YUV2RGB", - - "BayerBG2GRAY", - "BayerGB2GRAY", - "BayerRG2GRAY", - "BayerGR2GRAY", - - //YUV 4:2:0 formats family - "YUV2RGB_NV12", - "YUV2BGR_NV12", - "YUV2RGB_NV21", - "YUV2BGR_NV21", - - "YUV2RGBA_NV12", - "YUV2BGRA_NV12", - "YUV2RGBA_NV21", - "YUV2BGRA_NV21", - - "YUV2RGB_YV12", - "YUV2BGR_YV12", - "YUV2RGB_IYUV", - "YUV2BGR_IYUV", - - "YUV2RGBA_YV12", - "YUV2BGRA_YV12", - "YUV2RGBA_IYUV", - "YUV2BGRA_IYUV", - - "YUV2GRAY_420", - - //YUV 4:2:2 formats family - "YUV2RGB_UYVY", - "YUV2BGR_UYVY", - "YUV2RGB_VYUY", - "YUV2BGR_VYUY", - - "YUV2RGBA_UYVY", - "YUV2BGRA_UYVY", - "YUV2RGBA_VYUY", - "YUV2BGRA_VYUY", - - "YUV2RGB_YUY2", - "YUV2BGR_YUY2", - "YUV2RGB_YVYU", - "YUV2BGR_YVYU", - - "YUV2RGBA_YUY2", - "YUV2BGRA_YUY2", - "YUV2RGBA_YVYU", - "YUV2BGRA_YVYU", - - "YUV2GRAY_UYVY", - "YUV2GRAY_YUY2", - - // alpha premultiplication - "RGBA2mRGBA", - "mRGBA2RGBA", - - "COLORCVT_MAX" - }; - - *os << str[info.code]; -} - -void cv::gpu::PrintTo(const DeviceInfo& info, ostream* os) -{ - *os << info.name(); -} - -Mat readImage(const string& fileName, int flags) -{ - return imread(perf::TestBase::getDataPath(fileName), flags); -} - -const vector& devices() -{ - static vector devs; - static bool first = true; - - if (first) - { - int deviceCount = getCudaEnabledDeviceCount(); - - devs.reserve(deviceCount); - - for (int i = 0; i < deviceCount; ++i) - { - DeviceInfo info(i); - if (info.isCompatible()) - devs.push_back(info); - } - - first = false; - } - - return devs; -} diff --git a/modules/gpu/perf_cpu/perf_utility.hpp b/modules/gpu/perf_cpu/perf_utility.hpp deleted file mode 100644 index 8693cfc3c0..0000000000 --- a/modules/gpu/perf_cpu/perf_utility.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef __OPENCV_PERF_GPU_UTILITY_HPP__ -#define __OPENCV_PERF_GPU_UTILITY_HPP__ - -void fill(cv::Mat& m, double a, double b); - -using perf::MatType; -using perf::MatDepth; - -CV_ENUM(BorderMode, cv::BORDER_REFLECT101, cv::BORDER_REPLICATE, cv::BORDER_CONSTANT, cv::BORDER_REFLECT, cv::BORDER_WRAP) - CV_ENUM(Interpolation, cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_CUBIC, cv::INTER_AREA) -CV_ENUM(NormType, cv::NORM_INF, cv::NORM_L1, cv::NORM_L2, cv::NORM_HAMMING) - -struct CvtColorInfo -{ - int scn; - int dcn; - int code; - - explicit CvtColorInfo(int scn_=0, int dcn_=0, int code_=0) : scn(scn_), dcn(dcn_), code(code_) {} -}; - -void PrintTo(const CvtColorInfo& info, std::ostream* os); - -#define IMPLEMENT_PARAM_CLASS(name, type) \ - class name \ - { \ - public: \ - name ( type arg = type ()) : val_(arg) {} \ - operator type () const {return val_;} \ - private: \ - type val_; \ - }; \ - inline void PrintTo( name param, std::ostream* os) \ - { \ - *os << #name << " = " << testing::PrintToString(static_cast< type >(param)); \ - } - -IMPLEMENT_PARAM_CLASS(Channels, int) - -namespace cv { namespace gpu -{ - void PrintTo(const cv::gpu::DeviceInfo& info, std::ostream* os); -}} - -#define GPU_PERF_TEST(name, ...) \ - struct name : perf::TestBaseWithParam< std::tr1::tuple< __VA_ARGS__ > > \ - { \ - public: \ - name() {} \ - protected: \ - void PerfTestBody(); \ - }; \ - TEST_P(name, perf){ RunPerfTestBody(); } \ - void name :: PerfTestBody() - -#define GPU_PERF_TEST_1(name, param_type) \ - struct name : perf::TestBaseWithParam< param_type > \ - { \ - public: \ - name() {} \ - protected: \ - void PerfTestBody(); \ - }; \ - TEST_P(name, perf){ RunPerfTestBody(); } \ - void name :: PerfTestBody() - -#define GPU_TYPICAL_MAT_SIZES testing::Values(perf::szSXGA, perf::sz1080p, cv::Size(1800, 1500)) - -cv::Mat readImage(const std::string& fileName, int flags = cv::IMREAD_COLOR); - -const std::vector& devices(); - -#define ALL_DEVICES testing::ValuesIn(devices()) - -#define GET_PARAM(k) std::tr1::get< k >(GetParam()) - -#endif // __OPENCV_PERF_GPU_UTILITY_HPP__ diff --git a/modules/gpu/perf_cpu/perf_video.cpp b/modules/gpu/perf_cpu/perf_video.cpp deleted file mode 100644 index 2c3aeb31ce..0000000000 --- a/modules/gpu/perf_cpu/perf_video.cpp +++ /dev/null @@ -1,466 +0,0 @@ -#include "perf_cpu_precomp.hpp" - -#ifdef HAVE_CUDA - -////////////////////////////////////////////////////// -// GoodFeaturesToTrack - -IMPLEMENT_PARAM_CLASS(MinDistance, double) - -GPU_PERF_TEST(GoodFeaturesToTrack, cv::gpu::DeviceInfo, MinDistance) -{ - double minDistance = GET_PARAM(1); - - cv::Mat image = readImage("gpu/perf/aloe.jpg", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(image.empty()); - - cv::Mat corners; - - cv::goodFeaturesToTrack(image, corners, 8000, 0.01, minDistance); - - TEST_CYCLE() - { - cv::goodFeaturesToTrack(image, corners, 8000, 0.01, minDistance); - } -} - -INSTANTIATE_TEST_CASE_P(Video, GoodFeaturesToTrack, testing::Combine( - ALL_DEVICES, - testing::Values(MinDistance(0.0), MinDistance(3.0)))); - -////////////////////////////////////////////////////// -// PyrLKOpticalFlowSparse - -IMPLEMENT_PARAM_CLASS(GraySource, bool) -IMPLEMENT_PARAM_CLASS(Points, int) -IMPLEMENT_PARAM_CLASS(WinSize, int) -IMPLEMENT_PARAM_CLASS(Levels, int) -IMPLEMENT_PARAM_CLASS(Iters, int) - -GPU_PERF_TEST(PyrLKOpticalFlowSparse, cv::gpu::DeviceInfo, GraySource, Points, WinSize, Levels, Iters) -{ - bool useGray = GET_PARAM(1); - int points = GET_PARAM(2); - int win_size = GET_PARAM(3); - int levels = GET_PARAM(4); - int iters = GET_PARAM(5); - - cv::Mat frame0 = readImage("gpu/opticalflow/frame0.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); - ASSERT_FALSE(frame0.empty()); - - cv::Mat frame1 = readImage("gpu/opticalflow/frame1.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); - ASSERT_FALSE(frame1.empty()); - - cv::Mat gray_frame; - if (useGray) - gray_frame = frame0; - else - cv::cvtColor(frame0, gray_frame, cv::COLOR_BGR2GRAY); - - cv::Mat pts; - cv::goodFeaturesToTrack(gray_frame, pts, points, 0.01, 0.0); - - cv::Mat nextPts; - cv::Mat status; - - cv::calcOpticalFlowPyrLK(frame0, frame1, pts, nextPts, status, cv::noArray(), - cv::Size(win_size, win_size), levels - 1, - cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, iters, 0.01)); - - declare.time(20.0); - - TEST_CYCLE() - { - cv::calcOpticalFlowPyrLK(frame0, frame1, pts, nextPts, status, cv::noArray(), - cv::Size(win_size, win_size), levels - 1, - cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, iters, 0.01)); - } -} - -INSTANTIATE_TEST_CASE_P(Video, PyrLKOpticalFlowSparse, testing::Combine( - ALL_DEVICES, - testing::Values(GraySource(true), GraySource(false)), - testing::Values(Points(1000), Points(2000), Points(4000), Points(8000)), - testing::Values(WinSize(9), WinSize(13), WinSize(17), WinSize(21)), - testing::Values(Levels(1), Levels(2), Levels(3)), - testing::Values(Iters(1), Iters(10), Iters(30)))); - -////////////////////////////////////////////////////// -// FarnebackOpticalFlowTest - -GPU_PERF_TEST_1(FarnebackOpticalFlowTest, cv::gpu::DeviceInfo) -{ - cv::Mat frame0 = readImage("gpu/opticalflow/frame0.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame0.empty()); - - cv::Mat frame1 = readImage("gpu/opticalflow/frame1.png", cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame1.empty()); - - cv::Mat flow; - - int numLevels = 5; - double pyrScale = 0.5; - int winSize = 13; - int numIters = 10; - int polyN = 5; - double polySigma = 1.1; - int flags = 0; - - cv::calcOpticalFlowFarneback(frame0, frame1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags); - - declare.time(10); - - TEST_CYCLE() - { - cv::calcOpticalFlowFarneback(frame0, frame1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags); - } -} - -INSTANTIATE_TEST_CASE_P(Video, FarnebackOpticalFlowTest, ALL_DEVICES); - -////////////////////////////////////////////////////// -// FGDStatModel - -namespace cv -{ - template<> void Ptr::delete_obj() - { - cvReleaseBGStatModel(&obj); - } -} - -GPU_PERF_TEST(FGDStatModel, cv::gpu::DeviceInfo, std::string) -{ - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - - cv::VideoCapture cap(inputFile); - ASSERT_TRUE(cap.isOpened()); - - cv::Mat frame; - cap >> frame; - ASSERT_FALSE(frame.empty()); - - IplImage ipl_frame = frame; - cv::Ptr model(cvCreateFGDStatModel(&ipl_frame)); - - declare.time(60); - - for (int i = 0; i < 10; ++i) - { - cap >> frame; - ASSERT_FALSE(frame.empty()); - - ipl_frame = frame; - - startTimer(); - next(); - - cvUpdateBGStatModel(&ipl_frame, model); - - stopTimer(); - } -} - -INSTANTIATE_TEST_CASE_P(Video, FGDStatModel, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")))); - -////////////////////////////////////////////////////// -// MOG - -IMPLEMENT_PARAM_CLASS(LearningRate, double) - -GPU_PERF_TEST(MOG, cv::gpu::DeviceInfo, std::string, Channels, LearningRate) -{ - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - int cn = GET_PARAM(2); - double learningRate = GET_PARAM(3); - - cv::VideoCapture cap(inputFile); - ASSERT_TRUE(cap.isOpened()); - - cv::Mat frame; - - cv::BackgroundSubtractorMOG mog; - cv::Mat foreground; - - cap >> frame; - ASSERT_FALSE(frame.empty()); - - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } - - mog(frame, foreground, learningRate); - - for (int i = 0; i < 10; ++i) - { - cap >> frame; - ASSERT_FALSE(frame.empty()); - - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } - - startTimer(); next(); - mog(frame, foreground, learningRate); - stopTimer(); - } -} - -INSTANTIATE_TEST_CASE_P(Video, MOG, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")), - testing::Values(Channels(1), Channels(3)/*, Channels(4)*/), - testing::Values(LearningRate(0.0), LearningRate(0.01)))); - -////////////////////////////////////////////////////// -// MOG2 - -GPU_PERF_TEST(MOG2_update, cv::gpu::DeviceInfo, std::string, Channels) -{ - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - int cn = GET_PARAM(2); - - cv::VideoCapture cap(inputFile); - ASSERT_TRUE(cap.isOpened()); - - cv::Mat frame; - - cv::BackgroundSubtractorMOG2 mog2; - cv::Mat foreground; - - cap >> frame; - ASSERT_FALSE(frame.empty()); - - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } - - mog2(frame, foreground); - - for (int i = 0; i < 10; ++i) - { - cap >> frame; - ASSERT_FALSE(frame.empty()); - - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } - - startTimer(); next(); - mog2(frame, foreground); - stopTimer(); - } -} - -INSTANTIATE_TEST_CASE_P(Video, MOG2_update, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")), - testing::Values(Channels(1), Channels(3)/*, Channels(4)*/))); - -GPU_PERF_TEST(MOG2_getBackgroundImage, cv::gpu::DeviceInfo, std::string, Channels) -{ - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - int cn = GET_PARAM(2); - - cv::VideoCapture cap(inputFile); - ASSERT_TRUE(cap.isOpened()); - - cv::Mat frame; - - cv::BackgroundSubtractorMOG2 mog2; - cv::Mat foreground; - - for (int i = 0; i < 10; ++i) - { - cap >> frame; - ASSERT_FALSE(frame.empty()); - - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } - - mog2(frame, foreground); - } - - cv::Mat background; - mog2.getBackgroundImage(background); - - TEST_CYCLE() - { - mog2.getBackgroundImage(background); - } -} - -INSTANTIATE_TEST_CASE_P(Video, MOG2_getBackgroundImage, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")), - testing::Values(/*Channels(1),*/ Channels(3)/*, Channels(4)*/))); - -////////////////////////////////////////////////////// -// GMG - -IMPLEMENT_PARAM_CLASS(MaxFeatures, int) - -GPU_PERF_TEST(GMG, cv::gpu::DeviceInfo, std::string, Channels, MaxFeatures) -{ - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - int cn = GET_PARAM(2); - int maxFeatures = GET_PARAM(3); - - cv::VideoCapture cap(inputFile); - ASSERT_TRUE(cap.isOpened()); - - cv::Mat frame; - cap >> frame; - ASSERT_FALSE(frame.empty()); - - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } - - cv::Mat fgmask; - cv::Mat zeros(frame.size(), CV_8UC1, cv::Scalar::all(0)); - - cv::BackgroundSubtractorGMG gmg; - gmg.set("maxFeatures", maxFeatures); - gmg.initialize(frame.size(), 0.0, 255.0); - - gmg(frame, fgmask); - - for (int i = 0; i < 150; ++i) - { - cap >> frame; - if (frame.empty()) - { - cap.open(inputFile); - cap >> frame; - } - - if (cn != 3) - { - cv::Mat temp; - if (cn == 1) - cv::cvtColor(frame, temp, cv::COLOR_BGR2GRAY); - else - cv::cvtColor(frame, temp, cv::COLOR_BGR2BGRA); - cv::swap(temp, frame); - } - - startTimer(); next(); - gmg(frame, fgmask); - stopTimer(); - } -} - -INSTANTIATE_TEST_CASE_P(Video, GMG, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")), - testing::Values(Channels(1), Channels(3), Channels(4)), - testing::Values(MaxFeatures(20), MaxFeatures(40), MaxFeatures(60)))); - -////////////////////////////////////////////////////// -// VideoWriter - -#ifdef WIN32 - -GPU_PERF_TEST(VideoWriter, cv::gpu::DeviceInfo, std::string) -{ - const double FPS = 25.0; - - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - std::string outputFile = cv::tempfile(".avi"); - - cv::VideoCapture reader(inputFile); - ASSERT_TRUE( reader.isOpened() ); - - cv::VideoWriter writer; - - cv::Mat frame; - - declare.time(30); - - for (int i = 0; i < 10; ++i) - { - reader >> frame; - ASSERT_FALSE(frame.empty()); - - if (!writer.isOpened()) - writer.open(outputFile, CV_FOURCC('X', 'V', 'I', 'D'), FPS, frame.size()); - - startTimer(); next(); - writer.write(frame); - stopTimer(); - } -} - -INSTANTIATE_TEST_CASE_P(Video, VideoWriter, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")))); - -#endif // WIN32 - -////////////////////////////////////////////////////// -// VideoReader - -GPU_PERF_TEST(VideoReader, cv::gpu::DeviceInfo, std::string) -{ - std::string inputFile = perf::TestBase::getDataPath(std::string("gpu/video/") + GET_PARAM(1)); - - cv::VideoCapture reader(inputFile); - ASSERT_TRUE( reader.isOpened() ); - - cv::Mat frame; - - reader >> frame; - - declare.time(20); - - TEST_CYCLE_N(10) - { - reader >> frame; - } -} - -INSTANTIATE_TEST_CASE_P(Video, VideoReader, testing::Combine( - ALL_DEVICES, - testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")))); - -#endif From 915169e8b7b4d3293e375eb18e59a07bd4ae2d55 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Fri, 17 Aug 2012 17:09:26 +0400 Subject: [PATCH 012/163] Fix documentation build warnings in gpu module reference --- modules/gpu/doc/video.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/gpu/doc/video.rst b/modules/gpu/doc/video.rst index 378cca71ab..c4f84484a1 100644 --- a/modules/gpu/doc/video.rst +++ b/modules/gpu/doc/video.rst @@ -653,7 +653,7 @@ gpu::GMG_GPU ------------ .. ocv:class:: gpu::GMG_GPU -Class used for background/foreground segmentation. :: + Class used for background/foreground segmentation. :: class GMG_GPU_GPU { @@ -677,9 +677,9 @@ Class used for background/foreground segmentation. :: ... }; -The class discriminates between foreground and background pixels by building and maintaining a model of the background. Any pixel which does not fit this model is then deemed to be foreground. The class implements algorithm described in [GMG2012]_. + The class discriminates between foreground and background pixels by building and maintaining a model of the background. Any pixel which does not fit this model is then deemed to be foreground. The class implements algorithm described in [GMG2012]_. -Here are important members of the class that control the algorithm, which you can set after constructing the class instance: + Here are important members of the class that control the algorithm, which you can set after constructing the class instance: .. ocv:member:: int maxFeatures From 9d6ccecfddd55dd6c72a8dfc372a57a394ef3abd Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Fri, 17 Aug 2012 18:12:40 +0400 Subject: [PATCH 013/163] Fixed layout in third Android tutorial --- doc/_themes/blue/static/default.css_t | 29 +- .../dev_with_OCV_on_Android.rst | 435 +++++++++--------- 2 files changed, 240 insertions(+), 224 deletions(-) diff --git a/doc/_themes/blue/static/default.css_t b/doc/_themes/blue/static/default.css_t index 648e106b50..50a544218a 100644 --- a/doc/_themes/blue/static/default.css_t +++ b/doc/_themes/blue/static/default.css_t @@ -175,6 +175,8 @@ a:hover { div.body p, div.body dd, div.body li { text-align: justify; line-height: 130%; + margin-top: 1em; + margin-bottom: 1em; } div.body h1, @@ -327,16 +329,16 @@ table.field-list { margin-top: 20px; } -ul.simple { +/*ul.simple { list-style: none; -} +}*/ em.menuselection, em.guilabel { font-family: {{ theme_guifont }}; } .enumeratevisibleitemswithsquare ul { -list-style: square; +list-style: square; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; @@ -349,25 +351,25 @@ margin-left: 0px; margin-right: 0px; margin-top: 0.2em; } - + .enumeratevisibleitemswithsquare p { margin-bottom: 0pt; margin-top: 1pt; } - + .enumeratevisibleitemswithsquare dl{ margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; } - + .toctableopencv { - width: 100% ; + width: 100% ; table-layout: fixed; } - + .toctableopencv colgroup col:first-child { @@ -375,12 +377,17 @@ margin-top: 0px; max-width: 100pt !important; min-width: 100pt !important; } - - .toctableopencv colgroup col:nth-child(2) + + .toctableopencv colgroup col:nth-child(2) { width: 100% !important; } - + div.body ul.search li { text-align: left; } + +div.linenodiv { + min-width: 1em; + text-align: right; +} \ No newline at end of file diff --git a/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst b/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst index ca0211a881..d56bd1bc4e 100644 --- a/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst +++ b/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst @@ -57,12 +57,12 @@ Using async initialization is a **recommended** way for application development. To run OpenCV Manager-based application the first time you need to install packages with the `OpenCV Manager` and `OpenCV binary pack` for you platform. You can do it using Google Play Market or manually with ``adb`` tool: - .. code-block:: sh +.. code-block:: sh :linenos: /platform-tools/adb install /apk/OpenCV_2.4.2_Manager.apk /platform-tools/adb install /apk/OpenCV_2.4.2_binary_pack_armv7a.apk - + There is a very base code snippet implementing the async initialization. It shows basic principles. See the "15-puzzle" OpenCV sample for details. .. code-block:: java @@ -107,7 +107,7 @@ There is a very base code snippet implementing the async initialization. It show } It this case application works with OpenCV Manager in asynchronous fashion. ``OnManagerConnected`` callback will be called in UI thread, when initialization finishes. -Please note, that it is not allowed to use OpenCV calls or load OpenCV-dependent native libs before invoking this callback. +Please note, that it is not allowed to use OpenCV calls or load OpenCV-dependent native libs before invoking this callback. Load your own native libraries that depend on OpenCV after the successful OpenCV initialization. Application development with static initialization @@ -130,27 +130,27 @@ This approach is deprecated for the production code, release package is recommen :align: center #. If your application project **doesn't have a JNI part**, just copy the corresponding OpenCV native libs from :file:`/sdk/native/libs/` to your project directory to folder :file:`libs/`. - - In case of the application project **with a JNI part**, instead of manual libraries copying you need to modify your ``Android.mk`` file: + + In case of the application project **with a JNI part**, instead of manual libraries copying you need to modify your ``Android.mk`` file: add the following two code lines after the ``"include $(CLEAR_VARS)"`` and before ``"include path_to_OpenCV-2.4.2-android-sdk/sdk/native/jni/OpenCV.mk"`` .. code-block:: make - :linenos: + :linenos: + + OPENCV_CAMERA_MODULES:=on + OPENCV_INSTALL_MODULES:=on - OPENCV_CAMERA_MODULES:=on - OPENCV_INSTALL_MODULES:=on - The result should look like the following: - + .. code-block:: make - :linenos: + :linenos: - include $(CLEAR_VARS) + include $(CLEAR_VARS) - # OpenCV - OPENCV_CAMERA_MODULES:=on - OPENCV_INSTALL_MODULES:=on - include ../../sdk/native/jni/OpenCV.mk + # OpenCV + OPENCV_CAMERA_MODULES:=on + OPENCV_INSTALL_MODULES:=on + include ../../sdk/native/jni/OpenCV.mk After that the OpenCV libraries will be copied to your application :file:`libs` folder during the JNI part build. @@ -159,28 +159,28 @@ This approach is deprecated for the production code, release package is recommen #. The last step of enabling OpenCV in your application is Java initialization code before call to OpenCV API. It can be done, for example, in the static section of the ``Activity`` class: - .. code-block:: java - :linenos: + .. code-block:: java + :linenos: - static { - if (!OpenCVLoader.initDebug()) { - // Handle initialization error - } - } + static { + if (!OpenCVLoader.initDebug()) { + // Handle initialization error + } + } - If you application includes other OpenCV-dependent native libraries you should load them **after** OpenCV initialization: + If you application includes other OpenCV-dependent native libraries you should load them **after** OpenCV initialization: - .. code-block:: java - :linenos: + .. code-block:: java + :linenos: - static { - if (!OpenCVLoader.initDebug()) { - // Handle initialization error - } else { - System.loadLibrary("my_jni_lib1"); - System.loadLibrary("my_jni_lib2"); - } - } + static { + if (!OpenCVLoader.initDebug()) { + // Handle initialization error + } else { + System.loadLibrary("my_jni_lib1"); + System.loadLibrary("my_jni_lib2"); + } + } Native/C++ ---------- @@ -198,33 +198,33 @@ To build your own Android application, which uses OpenCV from native part, the f .. code-block:: make - include C:\Work\OpenCV4Android\OpenCV-2.4.2-android-sdk\sdk\native\jni\OpenCV.mk + include C:\Work\OpenCV4Android\OpenCV-2.4.2-android-sdk\sdk\native\jni\OpenCV.mk should be inserted into the :file:`jni/Android.mk` file **after** the line .. code-block:: make - include $(CLEAR_VARS) + include $(CLEAR_VARS) #. Several variables can be used to customize OpenCV stuff, but you **don't need** to use them when your application uses the `async initialization` via the `OpenCV Manager` API. - + Note: these variables should be set **before** the ``"include .../OpenCV.mk"`` line: .. code-block:: make - OPENCV_INSTALL_MODULES:=on + OPENCV_INSTALL_MODULES:=on Copies necessary OpenCV dynamic libs to the project ``libs`` folder in order to include them into the APK. .. code-block:: make - OPENCV_CAMERA_MODULES:=off + OPENCV_CAMERA_MODULES:=off Skip native OpenCV camera related libs copying to the project ``libs`` folder. .. code-block:: make - OPENCV_LIB_TYPE:=STATIC + OPENCV_LIB_TYPE:=STATIC Perform static link with OpenCV. By default dynamic link is used and the project JNI lib depends on ``libopencv_java.so``. @@ -232,14 +232,14 @@ To build your own Android application, which uses OpenCV from native part, the f .. code-block:: make - APP_STL := gnustl_static - APP_CPPFLAGS := -frtti -fexceptions + APP_STL := gnustl_static + APP_CPPFLAGS := -frtti -fexceptions Also the line like this one: .. code-block:: make - APP_ABI := armeabi-v7a + APP_ABI := armeabi-v7a should specify the application target platforms. @@ -249,11 +249,11 @@ To build your own Android application, which uses OpenCV from native part, the f .. code-block:: make - APP_PLATFORM := android-9 + APP_PLATFORM := android-9 #. Either use :ref:`manual ` ``ndk-build`` invocation or :ref:`setup Eclipse CDT Builder ` to build native JNI lib before Java part [re]build and APK creation. - + Hello OpenCV Sample =================== @@ -262,208 +262,217 @@ Here are basic steps to guide you trough the process of creating a simple OpenCV It will be capable of accessing camera output, processing it and displaying the result. #. Open Eclipse IDE, create a new clean workspace, create a new Android project (*File -> New -> Android Project*). - + #. Set name, target, package and minSDKVersion accordingly. - + #. Create a new class (*File -> New -> Class*). Name it for example: *HelloOpenCVView*. - .. image:: images/dev_OCV_new_class.png - :alt: Add a new class. - :align: center - * It should extend *SurfaceView* class. + .. image:: images/dev_OCV_new_class.png + :alt: Add a new class. + :align: center - * It also should implement *SurfaceHolder.Callback*, *Runnable*. + * It should extend *SurfaceView* class. + * It also should implement *SurfaceHolder.Callback*, *Runnable*. #. Edit *HelloOpenCVView* class. - * Add an *import* line for *android.content.context*. + * Add an *import* line for *android.content.context*. - * Modify autogenerated stubs: *HelloOpenCVView*, *surfaceCreated*, *surfaceDestroyed* and *surfaceChanged*. - .. code-block:: java + * Modify autogenerated stubs: *HelloOpenCVView*, *surfaceCreated*, *surfaceDestroyed* and *surfaceChanged*. - package com.hello.opencv.test; + .. code-block:: java + :linenos: - import android.content.Context; + package com.hello.opencv.test; - public class HelloOpenCVView extends SurfaceView implements Callback, Runnable { + import android.content.Context; - public HelloOpenCVView(Context context) { - super(context); - getHolder().addCallback(this); - } - - public void surfaceCreated(SurfaceHolder holder) { - (new Thread(this)).start(); - } - - public void surfaceDestroyed(SurfaceHolder holder) { - cameraRelease(); - } - - public void surfaceChanged(SurfaceHolder holder, int format, int width, - int height) { - cameraSetup(width, height); - } + public class HelloOpenCVView extends SurfaceView implements Callback, Runnable { - * Add *cameraOpen*, *cameraRelease* and *cameraSetup* voids as shown below. + public HelloOpenCVView(Context context) { + super(context); + getHolder().addCallback(this); + } - * Also, don't forget to add the public void *run()* as follows: - - .. code-block:: java + public void surfaceCreated(SurfaceHolder holder) { + (new Thread(this)).start(); + } - public void run() { - // TODO: loop { getFrame(), processFrame(), drawFrame() } - } + public void surfaceDestroyed(SurfaceHolder holder) { + cameraRelease(); + } - public boolean cameraOpen() { - return false; //TODO: open camera - } - - private void cameraRelease() { - // TODO release camera - } + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + cameraSetup(width, height); + } - private void cameraSetup(int width, int height) { - // TODO setup camera - } - + //... - .. + * Add *cameraOpen*, *cameraRelease* and *cameraSetup* voids as shown below. + + * Also, don't forget to add the public void *run()* as follows: + + .. code-block:: java + :linenos: + + public void run() { + // TODO: loop { getFrame(), processFrame(), drawFrame() } + } + + public boolean cameraOpen() { + return false; //TODO: open camera + } + + private void cameraRelease() { + // TODO release camera + } + + private void cameraSetup(int width, int height) { + // TODO setup camera + } #. Create a new *Activity* (*New -> Other -> Android -> Android Activity*) and name it, for example: *HelloOpenCVActivity*. For this activity define *onCreate*, *onResume* and *onPause* voids. - .. code-block:: java - public void onCreate (Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mView = new HelloOpenCVView(this); - setContentView (mView); - } + .. code-block:: java + :linenos: - protected void onPause() { - super.onPause(); - mView.cameraRelease(); - } + public void onCreate (Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mView = new HelloOpenCVView(this); + setContentView (mView); + } - protected void onResume() { - super.onResume(); - if( !mView.cameraOpen() ) { - // MessageBox and exit app - AlertDialog ad = new AlertDialog.Builder(this).create(); - ad.setCancelable(false); // This blocks the "BACK" button - ad.setMessage("Fatal error: can't open camera!"); - ad.setButton("OK", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - finish(); - } - }); - ad.show(); - } - - } + protected void onPause() { + super.onPause(); + mView.cameraRelease(); + } + + protected void onResume() { + super.onResume(); + if( !mView.cameraOpen() ) { + // MessageBox and exit app + AlertDialog ad = new AlertDialog.Builder(this).create(); + ad.setCancelable(false); // This blocks the "BACK" button + ad.setMessage("Fatal error: can't open camera!"); + ad.setButton("OK", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + finish(); + } + }); + ad.show(); + } + } #. Add the following permissions to the AndroidManifest.xml file: - .. code-block:: xml - + .. code-block:: xml + :linenos: + + + + + + - - - - #. Reference OpenCV library within your project properties. - .. image:: images/dev_OCV_reference.png - :alt: Reference OpenCV library. - :align: center + + .. image:: images/dev_OCV_reference.png + :alt: Reference OpenCV library. + :align: center #. We now need some code to handle the camera. Update the *HelloOpenCVView* class as follows: - .. code-block:: java - private VideoCapture mCamera; - - public boolean cameraOpen() { - synchronized (this) { - cameraRelease(); - mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID); - if (!mCamera.isOpened()) { - mCamera.release(); - mCamera = null; - Log.e("HelloOpenCVView", "Failed to open native camera"); - return false; - } - } - return true; - } - public void cameraRelease() { - synchronized(this) { - if (mCamera != null) { - mCamera.release(); - mCamera = null; - } - } - } - private void cameraSetup(int width, int height) { - synchronized (this) { - if (mCamera != null && mCamera.isOpened()) { - List sizes = mCamera.getSupportedPreviewSizes(); - int mFrameWidth = width; - int mFrameHeight = height; - { // selecting optimal camera preview size - double minDiff = Double.MAX_VALUE; - for (Size size : sizes) { - if (Math.abs(size.height - height) < minDiff) { - mFrameWidth = (int) size.width; - mFrameHeight = (int) size.height; - minDiff = Math.abs(size.height - height); - } - } - } - mCamera.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, mFrameWidth); - mCamera.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, mFrameHeight); - } - } - } + .. code-block:: java + :linenos: + + private VideoCapture mCamera; + + public boolean cameraOpen() { + synchronized (this) { + cameraRelease(); + mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID); + if (!mCamera.isOpened()) { + mCamera.release(); + mCamera = null; + Log.e("HelloOpenCVView", "Failed to open native camera"); + return false; + } + } + return true; + } + + public void cameraRelease() { + synchronized(this) { + if (mCamera != null) { + mCamera.release(); + mCamera = null; + } + } + } + + private void cameraSetup(int width, int height) { + synchronized (this) { + if (mCamera != null && mCamera.isOpened()) { + List sizes = mCamera.getSupportedPreviewSizes(); + int mFrameWidth = width; + int mFrameHeight = height; + { // selecting optimal camera preview size + double minDiff = Double.MAX_VALUE; + for (Size size : sizes) { + if (Math.abs(size.height - height) < minDiff) { + mFrameWidth = (int) size.width; + mFrameHeight = (int) size.height; + minDiff = Math.abs(size.height - height); + } + } + } + mCamera.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, mFrameWidth); + mCamera.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, mFrameHeight); + } + } + } #. The last step would be to update the *run()* void in *HelloOpenCVView* class as follows: - .. code-block:: java - public void run() { - while (true) { - Bitmap bmp = null; - synchronized (this) { - if (mCamera == null) - break; - if (!mCamera.grab()) - break; - - bmp = processFrame(mCamera); - } - if (bmp != null) { - Canvas canvas = getHolder().lockCanvas(); - if (canvas != null) { - canvas.drawBitmap(bmp, (canvas.getWidth() - bmp.getWidth()) / 2, - (canvas.getHeight() - bmp.getHeight()) / 2, null); - getHolder().unlockCanvasAndPost(canvas); - - } - bmp.recycle(); - } - } - } + .. code-block:: java + :linenos: - protected Bitmap processFrame(VideoCapture capture) { - Mat mRgba = new Mat(); - capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA); - //process mRgba - Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888); - try { - Utils.matToBitmap(mRgba, bmp); - } catch(Exception e) { - Log.e("processFrame", "Utils.matToBitmap() throws an exception: " + e.getMessage()); - bmp.recycle(); - bmp = null; - } - return bmp; - } + public void run() { + while (true) { + Bitmap bmp = null; + synchronized (this) { + if (mCamera == null) + break; + if (!mCamera.grab()) + break; + bmp = processFrame(mCamera); + } + if (bmp != null) { + Canvas canvas = getHolder().lockCanvas(); + if (canvas != null) { + canvas.drawBitmap(bmp, (canvas.getWidth() - bmp.getWidth()) / 2, + (canvas.getHeight() - bmp.getHeight()) / 2, null); + getHolder().unlockCanvasAndPost(canvas); + } + bmp.recycle(); + } + } + } + + protected Bitmap processFrame(VideoCapture capture) { + Mat mRgba = new Mat(); + capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA); + //process mRgba + Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888); + try { + Utils.matToBitmap(mRgba, bmp); + } catch(Exception e) { + Log.e("processFrame", "Utils.matToBitmap() throws an exception: " + e.getMessage()); + bmp.recycle(); + bmp = null; + } + return bmp; + } From ff3aa6cbe1fcd5abd07d6d9637ece1f17cdd1d33 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Fri, 17 Aug 2012 18:28:50 +0400 Subject: [PATCH 014/163] Fix Android build after commit:41b6d25 --- modules/core/src/system.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index e1d57ef8cb..253d840248 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -939,11 +939,11 @@ struct Mutex::Impl { Impl() { InitializeCriticalSection(&cs); refcount = 1; } ~Impl() { DeleteCriticalSection(&cs); } - + void lock() { EnterCriticalSection(&cs); } bool trylock() { return TryEnterCriticalSection(&cs) != 0; } void unlock() { LeaveCriticalSection(&cs); } - + CRITICAL_SECTION cs; int refcount; }; @@ -956,26 +956,26 @@ struct Mutex::Impl { Impl() { sl = OS_SPINLOCK_INIT; refcount = 1; } ~Impl() {} - + void lock() { OSSpinLockLock(&sl); } bool trylock() { return OSSpinLockTry(&sl); } void unlock() { OSSpinLockUnlock(&sl); } - + OSSpinLock sl; int refcount; }; -#elif defined __linux__ +#elif defined __linux__ && !defined ANDROID struct Mutex::Impl { Impl() { pthread_spin_init(&sl, 0); refcount = 1; } ~Impl() { pthread_spin_destroy(&sl); } - + void lock() { pthread_spin_lock(&sl); } bool trylock() { return pthread_spin_trylock(&sl) == 0; } void unlock() { pthread_spin_unlock(&sl); } - + pthread_spinlock_t sl; int refcount; }; @@ -986,11 +986,11 @@ struct Mutex::Impl { Impl() { pthread_mutex_init(&sl, 0); refcount = 1; } ~Impl() { pthread_mutex_destroy(&sl); } - + void lock() { pthread_mutex_lock(&sl); } bool trylock() { return pthread_mutex_trylock(&sl) == 0; } void unlock() { pthread_mutex_unlock(&sl); } - + pthread_mutex_t sl; int refcount; }; @@ -1001,14 +1001,14 @@ Mutex::Mutex() { impl = new Mutex::Impl; } - + Mutex::~Mutex() { if( CV_XADD(&impl->refcount, -1) == 1 ) delete impl; impl = 0; } - + Mutex::Mutex(const Mutex& m) { impl = m.impl; @@ -1023,10 +1023,10 @@ Mutex& Mutex::operator = (const Mutex& m) impl = m.impl; return *this; } - + void Mutex::lock() { impl->lock(); } void Mutex::unlock() { impl->unlock(); } -bool Mutex::trylock() { return impl->trylock(); } +bool Mutex::trylock() { return impl->trylock(); } } From bf4c1df0d0edafab8a225590b0996a077fce1144 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Fri, 17 Aug 2012 19:23:45 +0400 Subject: [PATCH 015/163] Fix formatting in Android tutorials --- .../android_binary_package/O4A_SDK.rst | 68 ++--- .../android_dev_intro.rst | 266 ++++++++++-------- 2 files changed, 183 insertions(+), 151 deletions(-) diff --git a/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst b/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst index 56069eb307..824a9730e3 100644 --- a/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst +++ b/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst @@ -36,21 +36,21 @@ The structure of package contents looks as follows: OpenCV-2.4.2-android-sdk |_ apk - | |_ OpenCV_2.4.2_binary_pack_XXX.apk - | |_ OpenCV_2.4.2_Manager.apk + | |_ OpenCV_2.4.2_binary_pack_XXX.apk + | |_ OpenCV_2.4.2_Manager.apk | |_ doc |_ samples |_ sdk - | |_ etc - | |_ java - | |_ native - | |_ 3rdparty - | |_ jni - | |_ libs - | |_ armeabi - | |_ armeabi-v7a - | |_ x86 + | |_ etc + | |_ java + | |_ native + | |_ 3rdparty + | |_ jni + | |_ libs + | |_ armeabi + | |_ armeabi-v7a + | |_ x86 | |_ license.txt |_ README.android @@ -64,11 +64,11 @@ The structure of package contents looks as follows: * :file:`sdk/etc` folder contains Haar and LBP cascades distributed with OpenCV. * :file:`apk` folder contains Android packages that should be installed on the target Android device to enable OpenCV library access via OpenCV Manager API (see details below). - + On production devices that have access to Google Play Market (and internet) these packages will be installed from Market on the first start of an application using OpenCV Manager API. But dev kits without Market or internet require this packages to be installed manually. (Install the `Manager.apk` and the corresponding `binary_pack.apk` depending on the device CPU, the Manager GUI provides this info). - + **Note**: installation from internet is the preferable way since we may publish updated versions of this packages on the Market. * :file:`samples` folder contains sample applications projects and their prebuilt packages (APK). @@ -76,7 +76,7 @@ The structure of package contents looks as follows: * :file:`doc` folder contains various OpenCV documentation in PDF format. It's also available online at http://docs.opencv.org. - + **Note**: the most recent docs (nightly build) are at http://docs.opencv.org/trunk/. Generally, it's more up-to-date, but can refer to not-yet-released functionality. @@ -94,10 +94,10 @@ Starting version 2.4.2 `OpenCV4Android SDK` uses `OpenCV Manager` API for librar For additional information on OpenCV Manager see the: - -* |OpenCV4Android_Slides|_ - -* |OpenCV4Android_Reference|_ + +* |OpenCV4Android_Slides|_ + +* |OpenCV4Android_Reference|_ .. @@ -196,15 +196,15 @@ Open OpenCV library and samples in Eclipse However, **all these errors are only false-alarms**! Just give a minute to Eclipse to complete initialization. - + In some cases these errors disappear after :menuselection:`Project --> Clean... --> Clean all --> OK` or after pressing :kbd:`F5` (for Refresh action) when selecting error-label-marked projects in :guilabel:`Package Explorer`. Sometimes more advanced manipulations are required: - * The provided projects are configured for ``API 11`` target (and ``API 9`` for the library) that can be missing platform in your Android SDK. - After right click on any project select :guilabel:`Properties` and then :guilabel:`Android` on the left pane. - Click some target with `API Level` 11 or higher: + The provided projects are configured for ``API 11`` target (and ``API 9`` for the library) that can be missing platform in your Android SDK. + After right click on any project select :guilabel:`Properties` and then :guilabel:`Android` on the left pane. + Click some target with `API Level` 11 or higher: .. image:: images/eclipse_8a_target.png :alt: Updating target @@ -239,10 +239,10 @@ Well, running samples from Eclipse is very simple: * Connect your device with :command:`adb` tool from Android SDK or create an emulator with camera support. - * See `Managing Virtual Devices - `_ document for help with Android Emulator. - * See `Using Hardware Devices - `_ for help with real devices (not emulators). + * See `Managing Virtual Devices + `_ document for help with Android Emulator. + * See `Using Hardware Devices + `_ for help with real devices (not emulators). * Select project you want to start in :guilabel:`Package Explorer` and just press :kbd:`Ctrl + F11` or select option :menuselection:`Run --> Run` from the main menu, or click :guilabel:`Run` button on the toolbar. @@ -263,33 +263,33 @@ Well, running samples from Eclipse is very simple: .. image:: images/android_emulator_opencv_manager_fail.png :alt: You will see this message if you have no OpenCV Manager installed :align: center - + To get rid of the message you will need to install `OpenCV Manager` and the appropriate `OpenCV binary pack`. Simply tap :menuselection:`Yes` if you have *Google Play Market* installed on your device/emulator. It will redirect you to the corresponding page on *Google Play Market*. - + If you have no access to the *Market*, which is often the case with emulators - you will need to install the packages from OpenCV4Android SDK folder manually. Open the console/terminal and type in the following two commands: - + .. code-block:: sh :linenos: /platform-tools/adb install /apk/OpenCV_2.4.2_Manager.apk /platform-tools/adb install /apk/OpenCV_2.4.2_binary_pack_armv7a.apk - + If you're running Windows, that will probably look like this: - + .. image:: images/install_opencv_manager_with_adb.png :alt: Run these commands in the console to install OpenCV Manager :align: center - + When done, you will be able to run OpenCV samples on your device/emulator seamlessly. - + * Here is ``Tutorial 2 - Use OpenCV Camera`` sample, running on top of stock camera-preview of the emulator. .. image:: images/emulator_canny.png :height: 600px :alt: Tutorial 1 Basic - 1. Add OpenCV - running Canny :align: center - + What's next =========== diff --git a/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst b/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst index dc95403ffd..db109adae1 100644 --- a/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst +++ b/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst @@ -75,7 +75,7 @@ You need the following software to be installed in order to develop for Android sudo update-java-alternatives --set java-6-sun - **TODO:** add a note on Sun/Oracle Java installation on Ubuntu 12. +.. **TODO:** add a note on Sun/Oracle Java installation on Ubuntu 12. #. **Android SDK** @@ -241,27 +241,29 @@ where: The script :file:`Android.mk` usually has the following structure: .. code-block:: make + :linenos: - LOCAL_PATH := $(call my-dir) + LOCAL_PATH := $(call my-dir) - include $(CLEAR_VARS) - LOCAL_MODULE := - LOCAL_SRC_FILES := - := - ... - := + include $(CLEAR_VARS) + LOCAL_MODULE := + LOCAL_SRC_FILES := + := + ... + := - include $(BUILD_SHARED_LIBRARY) + include $(BUILD_SHARED_LIBRARY) This is the minimal file :file:`Android.mk`, which builds C++ source code of an Android application. Note that the first two lines and the last line are mandatory for any :file:`Android.mk`. Usually the file :file:`Application.mk` is optional, but in case of project using OpenCV, when STL and exceptions are used in C++, it also should be created. Example of the file :file:`Application.mk`: .. code-block:: make + :linenos: - APP_STL := gnustl_static - APP_CPPFLAGS := -frtti -fexceptions - APP_ABI := armeabi-v7a + APP_STL := gnustl_static + APP_CPPFLAGS := -frtti -fexceptions + APP_ABI := armeabi-v7a .. _NDK_build_cli: @@ -332,75 +334,76 @@ We recommend the approach based on Eclipse :abbr:`CDT(C/C++ Development Tooling) #. Open Eclipse and load the Android app project to configure. #. Add C/C++ Nature to the project via Eclipse menu :guilabel:`New -> Other -> C/C++ -> Convert to a C/C++ Project`. - - .. image:: images/eclipse_cdt_cfg1.png - :alt: Configure CDT - :align: center - ` ` + .. image:: images/eclipse_cdt_cfg1.png + :alt: Configure CDT + :align: center - .. image:: images/eclipse_cdt_cfg2.png - :alt: Configure CDT - :align: center + And: + + .. image:: images/eclipse_cdt_cfg2.png + :alt: Configure CDT + :align: center #. Select the project(s) to convert. Specify "Project type" = ``Makefile project``, "Toolchains" = ``Other Toolchain``. - + .. image:: images/eclipse_cdt_cfg3.png :alt: Configure CDT :align: center -#. Open :guilabel:`Project Properties -> C/C++ Build`, unckeck ``Use default build command``, replace "Build command" text from ``"make"`` to - ``"${NDKROOT}/ndk-build.cmd"`` on Windows, +#. Open :guilabel:`Project Properties -> C/C++ Build`, unckeck ``Use default build command``, replace "Build command" text from ``"make"`` to - ``"${NDKROOT}/ndk-build"`` on Linux and MacOS. - - .. image:: images/eclipse_cdt_cfg4.png - :alt: Configure CDT - :align: center + ``"${NDKROOT}/ndk-build.cmd"`` on Windows, + + ``"${NDKROOT}/ndk-build"`` on Linux and MacOS. + + .. image:: images/eclipse_cdt_cfg4.png + :alt: Configure CDT + :align: center #. Go to :guilabel:`Behaviour` tab and change "Workbench build type" section like shown below: - - .. image:: images/eclipse_cdt_cfg5.png - :alt: Configure CDT - :align: center + + .. image:: images/eclipse_cdt_cfg5.png + :alt: Configure CDT + :align: center #. Press :guilabel:`OK` and make sure the ``ndk-build`` is successfully invoked when building the project. - - .. image:: images/eclipse_cdt_cfg6.png - :alt: Configure CDT - :align: center + + .. image:: images/eclipse_cdt_cfg6.png + :alt: Configure CDT + :align: center #. If you open your C++ source file in Eclipse editor, you'll see syntax error notifications. They are not real errors, but additional CDT configuring is required. - - .. image:: images/eclipse_cdt_cfg7.png - :alt: Configure CDT - :align: center + + .. image:: images/eclipse_cdt_cfg7.png + :alt: Configure CDT + :align: center #. Open :guilabel:`Project Properties -> C/C++ General -> Paths and Symbols` and add the following **Include** paths for **C++**: - :: + :: ${NDKROOT}/platforms/android-9/arch-arm/usr/include ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/include ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/include ${ProjDirPath}/../../sdk/native/jni/include - The last path should be changed to the correct absolute or relative path to OpenCV4Android SDK location. - - This should clear the syntax error notifications in Eclipse C++ editor. - - .. image:: images/eclipse_cdt_cfg8.png - :alt: Configure CDT - :align: center + The last path should be changed to the correct absolute or relative path to OpenCV4Android SDK location. - .. note:: The latest Android NDK **r8b** has a bit different STL headers path. So if you use this NDK version please use the following modified **Include** paths list: + This should clear the syntax error notifications in Eclipse C++ editor. - :: + .. image:: images/eclipse_cdt_cfg8.png + :alt: Configure CDT + :align: center - ${NDKROOT}/platforms/android-9/arch-arm/usr/include - ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/include - ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include - ${ProjDirPath}/../../sdk/native/jni/include + .. note:: The latest Android NDK **r8b** uses different STL headers path. So if you use this NDK release add the following **Include** paths list instead: + + :: + + ${NDKROOT}/platforms/android-9/arch-arm/usr/include + ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/include + ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include + ${ProjDirPath}/../../sdk/native/jni/include Debugging and Testing @@ -412,12 +415,16 @@ AVD AVD (*Android Virtual Device*) is not probably the most convenient way to test an OpenCV-dependent application, but sure the most uncomplicated one to configure. #. Assuming you already have *Android SDK* and *Eclipse IDE* installed, in Eclipse go :guilabel:`Window -> AVD Manager`. - **TBD:** how to start AVD Manager without Eclipse... + + .. **TBD:** how to start AVD Manager without Eclipse... + #. Press the :guilabel:`New` button in :guilabel:`AVD Manager` window. #. :guilabel:`Create new Android Virtual Device` window will let you select some properties for your new device, like target API level, size of SD-card and other. - .. image:: images/AVD_create.png - :alt: Configure builders - :align: center + + .. image:: images/AVD_create.png + :alt: Configure builders + :align: center + #. When you click the :guilabel:`Create AVD` button, your new AVD will be availible in :guilabel:`AVD Manager`. #. Press :guilabel:`Start` to launch the device. Be aware that any AVD (a.k.a. Emulator) is usually much slower than a hardware Android device, so it may take up to several minutes to start. #. Go :guilabel:`Run -> Run/Debug` in Eclipse IDE to run your application in regular or debugging mode. :guilabel:`Device Chooser` will let you choose among the running devices or to start a new one. @@ -435,81 +442,106 @@ Windows host computer #. Attach the Android device to your PC with a USB cable. #. Go to :guilabel:`Start Menu` and **right-click** on :guilabel:`Computer`. Select :guilabel:`Manage` in the context menu. You may be asked for Administrative permissions. #. Select :guilabel:`Device Manager` in the left pane and find an unknown device in the list. You may try unplugging it and then plugging back in order to check whether it's your exact equipment appears in the list. - .. image:: images/usb_device_connect_01.png - :alt: Unknown device - :align: center + + .. image:: images/usb_device_connect_01.png + :alt: Unknown device + :align: center + #. Try your luck installing `Google USB drivers` without any modifications: **right-click** on the unknown device, select :guilabel:`Properties` menu item --> :guilabel:`Details` tab --> :guilabel:`Update Driver` button. - .. image:: images/usb_device_connect_05.png - :alt: Device properties - :align: center + + .. image:: images/usb_device_connect_05.png + :alt: Device properties + :align: center + #. Select :guilabel:`Browse computer for driver software`. - .. image:: images/usb_device_connect_06.png - :alt: Browse for driver - :align: center + + .. image:: images/usb_device_connect_06.png + :alt: Browse for driver + :align: center + #. Specify the path to :file:`/extras/google/usb_driver/` folder. - .. image:: images/usb_device_connect_07.png - :alt: Browse for driver - :align: center + + .. image:: images/usb_device_connect_07.png + :alt: Browse for driver + :align: center + #. If you get the prompt to install unverified drivers and report about success - you've finished with USB driver installation. - .. image:: images/usb_device_connect_08.png - :alt: Install prompt - :align: center - ` ` + .. image:: images/usb_device_connect_08.png + :alt: Install prompt + :align: center + + ` ` + + .. image:: images/usb_device_connect_09.png + :alt: Installed OK + :align: center - .. image:: images/usb_device_connect_09.png - :alt: Installed OK - :align: center #. Otherwise (getting the failure like shown below) follow the next steps. - .. image:: images/usb_device_connect_12.png - :alt: No driver - :align: center + + .. image:: images/usb_device_connect_12.png + :alt: No driver + :align: center + #. Again **right-click** on the unknown device, select :guilabel:`Properties --> Details --> Hardware Ids` and copy the line like ``USB\VID_XXXX&PID_XXXX&MI_XX``. - .. image:: images/usb_device_connect_02.png - :alt: Device properties details - :align: center + + .. image:: images/usb_device_connect_02.png + :alt: Device properties details + :align: center + #. Now open file :file:`/extras/google/usb_driver/android_winusb.inf`. Select either ``Google.NTx86`` or ``Google.NTamd64`` section depending on your host system architecture. - .. image:: images/usb_device_connect_03.png - :alt: "android_winusb.inf" - :align: center + + .. image:: images/usb_device_connect_03.png + :alt: "android_winusb.inf" + :align: center + #. There should be a record like existing ones for your device and you need to add one manually. - .. image:: images/usb_device_connect_04.png - :alt: "android_winusb.inf" - :align: center + + .. image:: images/usb_device_connect_04.png + :alt: "android_winusb.inf" + :align: center + #. Save the :file:`android_winusb.inf` file and try to install the USB driver again. - .. image:: images/usb_device_connect_05.png - :alt: Device properties - :align: center - ` ` + .. image:: images/usb_device_connect_05.png + :alt: Device properties + :align: center - .. image:: images/usb_device_connect_06.png - :alt: Browse for driver - :align: center + ` ` - ` ` + .. image:: images/usb_device_connect_06.png + :alt: Browse for driver + :align: center + + ` ` + + .. image:: images/usb_device_connect_07.png + :alt: Browse for driver + :align: center - .. image:: images/usb_device_connect_07.png - :alt: Browse for driver - :align: center #. This time installation should go successfully. - .. image:: images/usb_device_connect_08.png - :alt: Install prompt - :align: center - ` ` + .. image:: images/usb_device_connect_08.png + :alt: Install prompt + :align: center + + ` ` + + .. image:: images/usb_device_connect_09.png + :alt: Installed OK + :align: center - .. image:: images/usb_device_connect_09.png - :alt: Installed OK - :align: center #. And an unknown device is now recognized as an Android phone. - .. image:: images/usb_device_connect_10.png - :alt: "Known" device - :align: center + + .. image:: images/usb_device_connect_10.png + :alt: "Known" device + :align: center + #. Successful device USB connection can be verified in console via ``adb devices`` command. - .. image:: images/usb_device_connect_11.png - :alt: "adb devices" - :align: center + + .. image:: images/usb_device_connect_11.png + :alt: "adb devices" + :align: center #. Now, in Eclipse go :guilabel:`Run -> Run/Debug` to run your application in regular or debugging mode. :guilabel:`Device Chooser` will let you choose among the devices. @@ -519,13 +551,13 @@ By default Linux doesn't recognize Android devices, but it's easy to fix this is .. code-block:: guess - SUBSYSTEM=="usb", ATTR{idVendor}=="1004", MODE="0666", GROUP="plugdev" + SUBSYSTEM=="usb", ATTR{idVendor}=="1004", MODE="0666", GROUP="plugdev" Then restart your adb server (even better to restart the system), plug in your Android device and execute :command:`adb devices` command. You will see the list of attached devices: - .. image:: images/usb_device_connect_ubuntu.png - :alt: List of attached devices - :align: center +.. image:: images/usb_device_connect_ubuntu.png + :alt: List of attached devices + :align: center MacOS host computer ^^^^^^^^^^^^^^^^^^^ From a4bffd96c470be50eb21880beb4e1e895c39ae84 Mon Sep 17 00:00:00 2001 From: Alexander Mordvintesv Date: Sat, 18 Aug 2012 19:43:32 +0300 Subject: [PATCH 016/163] added deconvolution.py sample and example images --- samples/python2/data/licenseplate_motion.jpg | Bin 0 -> 58364 bytes samples/python2/data/text_defocus.jpg | Bin 0 -> 32176 bytes samples/python2/data/text_motion.jpg | Bin 0 -> 26637 bytes samples/python2/deconvolution.py | 118 +++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 samples/python2/data/licenseplate_motion.jpg create mode 100644 samples/python2/data/text_defocus.jpg create mode 100644 samples/python2/data/text_motion.jpg create mode 100644 samples/python2/deconvolution.py diff --git a/samples/python2/data/licenseplate_motion.jpg b/samples/python2/data/licenseplate_motion.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9723ea148b0d91ee8651d91b336ec1073f5e001f GIT binary patch literal 58364 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 literal 0 HcmV?d00001 diff --git a/samples/python2/data/text_motion.jpg b/samples/python2/data/text_motion.jpg new file mode 100644 index 0000000000000000000000000000000000000000..781f095c2d4f63c2648175434bf6874c980813fc GIT binary patch literal 26637 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�k&R37a z%CHZn_klc^^)j=91g*44wR6xRy=p_Zn&B$r4JRXkcSY5FdS1abjq|>V>1_Hc5Bq1| zb1vv;vdC0Po@m=%zY>JNA3 zXAyNeTcwW;h1FI$O2Y^#?v{7zv_F4Rxa^>uIV|uE=0MSF0A#WpP&WNfR!hyN(qk-V zbc(Egi2819G2|b*;>tCNJ8>eX15JFe$mD0{V{@(Bx$44(-+I8zKJX!WofGADp=^sW zO%T&+lIKX3JhWuCNO>Gpd2N$fi|m3KW!qRw6!opeE$yPrz$6e~_AhQ0!K8Dma} zpeLKJiXAaj^KltoRYuAJS+V1@X_g^Sd5DQ;B~vmbW_IsO=w#_=AcISEOIqZ)gk`6z-bG8{CP8rF$i8u>KrDJdtUDRz1~2(m-M0C zSe}oUVhA$E+98MQ#5mu3SX5Yk%AT9;QRp{Bp|cF%Jiq6=v*SOW{BXhq+`6<+;|Nbu z(9(S+o@-3N>UGg)9nN4=ctuleXjiv-;--z=#sVYcYgSFxDbSufzh++(hu zJY5w=tM11YJ0YA1muWcBSt2wK|Hdz@$zMv7*Z;EV0JK3EjNni zF>W%T5-K2<7So2Hq!F~G&C(lUBFkf*Y9za)Np|X4xo8w)8pDExhRa~-=hx3i8v7LN zVuay*k~^qZ+Wht6kcU!LpR5Q2X_0D=2ikQND%pK4>>30UbVB^h;6cFUl;E3A{VSGP z4^MmHzpTu-mmZaM(l9&$n>u?zYq#iH0r$Y&R-J$*t)uICs|@Sx_~&sFh_w1z!Dymw>wzs z@mZEtD(m|cECj21d)g)$9hLulg_6oKmN0DQ5PLKJU3Q+^-Wl82vtF!k03*393fh2+=gJTFJm-VO$8HTAXLNa5lFb)?tn<<3z%*8_V@hKJ3_epHrR- zB>L6`!@gOn(A1o^HH5`jUu`h2nMgvhNss!AkRQB?WaJwSC1rIF$Orv%{FT{m0kMT81^(tM zc*-;7xGlHTBR!RYmrivkmh~|z?|A1;KO;J+Q3C!LFcrWtDx9W2v1&^>S+C-plc83S4u&UQm_P1k&MzA-u=R=VShjYI zv(W8h zF3a`-UE8-rdW8)YPI67=jaCW4XN)U-UX#@eDb-&`)6HqU-M$o5zcFkt^U85oyxy0& zyWo2k)%{l86Sq9Epu?Na*uVOP3u)uwvfBVJnk>7tlNVWmOS|LzDx~0>0K51`uIZg{ zD~H?Hhr0k1WLjc)-|1Yb5c(eUX1{;d=TlKBa%iP~LE(H9$+h~q@52)ugB3X%f+hFS zGY>d=90u>qz$vM>k`wN)m5jnx&xUW?B!6BQ%^XN`4u1P)5yc}-m>bLze2e)^Bz(@^ z>MxOvrFIF*A@(+7OYQDVg%lR~{`iy-zG`FsL$6X=F2reOZoJfEPP%%qXo|y7L-LWf zGP`IPT{QO|ziN;-xIy#S2UI@X#SQRbt<}%6NL{WKjM(#P$r62f=&SgWOdo4qk?Ul} zHB9K6p-rohec<>S(}I`Lm#TS=KE6VTLSf64+H9pRYObKf&h)qzp|V0Hc&iU~wB>^K z{Y*K_kp`#c9-*WbLz8SlerC@R=i615;iZQirAD$|>8pD!F>Tkv;rJZ-QMKZ4w#SYg zju|tjQEYLlX;=638Qql_q7;vGrd{+8Bt8_h{Fy0-VtOIAZD_qk>~-le*Wl@jpB`k% z!R|`wZ2izs;eWlLS=hK^)Cm(qfFaP8lUhp>kKP2Qj?Ka3-|3yq6Qd-&lW92Cqb~8# z*f^kkU4Gc?tFFpcpZo^n@k?ZR#)}H~+9lM98F?9$w-HQQc^r3#vR--0Ki3(X|Lg#a z?6DDZ3L^$uFQVJk22P^yJZBOVO5X=^=0@@8+t0)bT6IkqUDg)Oo?n&izysaAwd~>x zTtk{%$53i+26$V0U3E)KGXI~P;iBkpi7;~RrBue>b$sybkzC|xyy zoHnNmj%7(X{(AMsfQ#v*_f2&<;=@+XQ*J*MMD%HwZt00QN2mBUukz`+jF(X-3MC^e z?QP#>ytJ<2lJw(?m}m0__nvQu8mERbnRPBDc9;hey9Y0D9fcK=;K^Nh2_#OE!Zv+v z+2R%yDPS045HwdY64K5+Q# zBD}|Z4i8XXJPLZhI7Blw@N?W$Za#)A#*~=aMYJ(w*_qZ|N=z_kd;(#_pBQIanNWMc58k#aB|6#ACcIr_Ci`3V|XHbTWaKSyc@ zVp(ZLaxOccE;xO7;3)zOIxh~ci4mJBE$gNmrbO!yC~3VssMLbS!g;FQklrp$Af@Wt zZAV9SDR%3V9&eC@HAtniX0@eUuXC2n?x=uQY3_qT&$U+j$Gd0yaC&j*fV7SZ5e^>00h zVZVm#rS-jNaEmXnxyy4zah|hY$EJ?A)QWA`YOrgjiL^n|iRF%q8Gp{Yl%Dyq)nhX~ z(EjJ;I@+EN3PT%1+#G*`25Iy%qyj)@dhRzds647)q=;hUd1m}S#`+xIVA zmWi=iSJ&7L=EUf5!l6wsT{7!$@nFMjEm>LQcaEfFJvA{xxL)a*GNwQ0g8tm^LYEc7 z>RpoyOVrj1e?b_Fkknr}<`cyvDA<4Wy+_N-WNAxyk2AU#{I;ATgT&CE|=xuqRq+=4ulcmB#Jp&I^mrZ$@M zbPp(v{&|$D?wsvkqS1928aB;L>~Jq&%yaTAn)@kW-mlB>*$a(Hje8f zk=8WgPu_9jQl@5)a-q=fXv(~tCF*6~NqvSoEa%G_?uk_c zC|9MTx+Z+J_=DcP+fL(&lR^=@E2vJbo!nLHQ)U^5qX+Z5g_RX-np?^n%(%B^aa>u) z$);GVI)5ohn~cT6;hEtMTR{jh=rP3kCO^Y0PNb68HJESV!=o9cqJp<44G;s#K6JR# zr+Wl`^;@*LSOSw-5JucKdRhrC(4D~jo#nHBxLbP7wn6i<^@;q?CnkcuhyyReL?e@% z{Et0NGgIO`{>JA%ydHh)ZvPB_TYkNUgQu=Y!yj@6d};jf!;4UN zX1?f6ffMTJY{Fxm_H(5E=MUu9+c{0Rsxr90J+sbP^?cLFR{%{Jbrz2|_1qJMZy(p+ zJ3{xQw(~i9UdN$7XIuBqn=*jH#-1@q|8WmOe6T%Bfwbp)KJ3g;hWpnPVqO|K#k9&i z7`{?*6aMslpnby;#=?O6AGu%qO;k=7wbr< zbkwW1`aB#@H45T7^Swa=!e9LHMVEc0ay7aeV}!*o_E;+Ad!|XeK*o&V` z=|tg_5=IEsitN)>k@-m?I?H4ELG9it$pPYWZDP0prJ(#r5RKM{dT&joR1SUm>j`zK zn6W^IXdK`=Ae9|!L+w&)pr6Hw)o{lRUg|1WnJT;LFr=2R!q8n0RW!w9_P40CEX8s) z73K%N5T+D&+lWKHnw1{!f9xA_?Por%(h$2GC5PrwXm^Cyb>B*NsdRkNdt<@GXd=*G z%R6P;CevlYHh#xUsObH)=a-j`R#m>KLOpqc?8o;3!zfM5)89m-s8%_T&QP9)BGJov zyW3MqL`TI5&c?fe&C6&n8kQ66*nyKe_=Sy+>#asb=?3r%Fg(hx?uvd=A@^)*Y)n(ZSTc?DPS^fL?F)KgD2%UX(&JMJ}3 zac%aqHwTuK*U#%ivtG0(5V3W!b|IKK%kZ%!d}$6&s8Da_^s{@+EwfAUioHFvD*sU? z=C)92qoSY2$C4ffq{Eo5W`}6B?3$l{`*^8#%lXpucb`-Web2KEx;4V3lJ!xXCf&mo4uW)h8?Dz93g4Y_B-MZmh~>dy6R>XKi0E4o!C z2{@}ht_+!YvwDMU8EJhMH~BghfoC0=bI|NwQ?<1s{{aDjtwd{2H#J4#1dv@i8Bdsw$*-b<#^q#bKTLZG*x`dv<)3xz>bx5@pw zV>DrYs{K6SFty=z@<+aRqPi@FMI+!-P{X>OpM{L&$Iv2~0}91-=P=7wxf-vMhKMhm z4RF0pRq1i~z-_dUz)6io{VU2*1C4z5ulx#o_vX}8N1#Iz<6Sx|%&viVQ=}%|^Gi(^ zaB1-FURM?$#@w^#rH;)$;Ldr~`rIH|kk4v>4=Jz|Q9A65J9REFe>OFDY4Tyq*S=Kd zmVOM>mX8VWa>yEcDygT8+^eKb+Z~h)ndaX_;ASgscg>7s;>WBP^kX67~LW|rq?Qf zoRL$PXyYWPQxUh38;yZwPxAm}-rS1xfbyu#NlnEQCCd3N!4PgL6UadVK)1lp`*{*FQxF17^NdG%;wby z>fh}(r}ICnZ{0()Rw`xp`lW1im&;-R{dA0lx`YI;Xey|`Qg?4>i_bt%r zj)Og=fz|GQRT)3TQ9L)ZgNm(%%e?ACL_cN&>k9Wv&payiqy$}xT`fI{n)D8c2y6xH z`wgHfcMKkytM;w4yyRY{TCd*7$0^#9xHd}eJC&cfc-#9TvlYh>)t+ZqIXHN8sOc%r{HS=Xxn)*SFks196eb5Xr#&eW1xJu6FyFx^$FEy>kc^$NVzf zS}3nH3pqt}Icd_JK))nuBnpPN;`59v=x1OX06r8Kg6>mbY6qu+V@RjXlG}uh{c=<1C}5Woe`=L!o8-xFk6rr z`QQy7N-6gt(?&L?NpQAQ$gSxqi?MS8)AwJaWZimc8Qarsi*CZtmd&Yn7aY0Kt5W(C z8-M>W_rolCuI8c<cGxRhH(Br5HqSiFFoJY94*I0OKiFgki?+wU=l7DBi=kAiGL-p0{>~zrg2N*| zxmQ03o-FeGkc`*%)Acr$mwbt7)j^);Yq(VLl~!F;<8+tJSFhv^a!N1@$uk5yUo!!Cmg&X(myURuSM+)Yow5`oNqAV0Gwolwc1kWj7GC*<4V0aIbSZ-XX0d3uapAG4!y zY3#_W#1%^3v+HSes*^b6o9iD1-k{sGlpP8^CBm+3$S>N8ZduHWLxzRs{QM>L{2xd% z&sADJyjWMOMctLO=iNP}meq|DP(FM;rkt;ENOp4eIA4#~jio7cY?(0Lh;rn|*j%GL zeQ?2y-||-6vmGz*Hl=&j8n>*54so1URHCuI_nOh-*}OPc_T8YZ{zq9WKk6~o%^IiV z2J;%>UH8kWC~ki7w|V7Dyc#Lj221N`gwx|@p9RfdU({CWwCVDtz8cZ{JcEGHmG0&8 zysLAn=2Rr}x2J zGu4YT2BLX#nFzVI=MJfRpSFs<_Mt(U4ky0I8W!&@7KE)V7W?|dQN{XRO^9xKNTHuI zix-@NJNAlq=|eg3sqk^FkWvAuh=L2(90=0zchr&SBZ6XYFPlp~EIXRU!i608)&5pi zgTeJ(jY}zD`Qs+hA1*Taa76Ih?oD@mMq3BNR1zh_@0Rmu6Umk5dicpSSzb4e0oSpG$EjZ^xYiQ059iB8gY%L?ZjsE;~Z0Y<~-R`X%}3L=>vRxq)_^iNpx z8Z}EmlEtSl0g!Q+kFNC4oU46u8u%v5k(GGEvJ+2AmUcIuae~ z1?}>Xi#hKE&Uu;F2)w`^*SM?p{ zQF-O|_Yxn@TC=G2(%rqlIH%rfQ=POco~`z?m}YO<#xzTG+0v0klakOiP8!rcy$^7> zYYuUj`jIBCmFU+Dg?*(bF&!q43PSH4Wn3nt@Xhaj|B3J<|9mRWhP}M*yH+yHD>

s4$z@%HfEJO-`xUN**h+3an^eL$rn>M3%?g6b}c=_5uE zw11RQEry-^=Cpc=s57Q68)@y0Go}@)LCTt3J*A4nKK;2|YWT=L{(@2hivy4yYWVAZ zX!n=TRNJpgnW9D5Ty5_oKVY9Z$$>|vEmdNS8Aj4ZL;T*V)1E5O7|`(d@}9rm@kMFg z%cx+d!*(PAU)OSF;udb+%lnpSrx^xcu6EAI`qI=$X5zPM20bM(@SE7iz&uCEYdGh8 zFVoBQV$H-rY@7;!#cPR=z2+a{bT{LQMr zI6}Udc)fcMd{Pz7G^7W#=iwCw35!H)KEnX>8SIU*~4bU?Lijk_Pe!3LQJ`fMSR1Pb>X!pa2tqVf8(+4e# zIU3zWHaS8~*_HfYk=}b$ERl$E^OF9WskkOoMmvT;lkbJmFsDdfDX!8cI^RE?{bOi{%fs-yTOc|HE@+V z>y}@^W*cN0gW__ynR)q+Fw$|hIzMVnHloh3y8```+66O*k4&k!4ys-4?lxlp)3N*ML5mI_ zl)QDsC@+QqnRu^S?osFsC6XR7G{vN%iM5;(?_S5VPm z+&R>9YwLOH5$f|0)h!0qJ{G#n+AVV^|76mT{M3+q#y+ss58&dq(S@H!j%$8 zWA)37^Yqx^8 zzMg$HnLa?D1xZZ7Lb|2YuSj8{!4L$hX`3O$*g0ohuAPGW$e(o|Fbq4}KR%b8BSgFa zLotgHRaXa7FUKdN?Yjg|Fz*%~?Iqq4=`lRB)d#)WcH<5AH|v%(wIDKbsvaG2vmQq7=a0`n`(dC2n)9rUYv*XGA#2P@cg zX{D9-0k&g2w@OGz3GSUm*K%){@#2N=n|E?q>b%0Ei0mvE%!Q&1^qZ`|OV z9E{mIn~R@iJt8DS&S3O>W*_$xLwLi%VHX+Y5Fw2_B%ebBEc!;0Cm&OigGh8|L^Gx3 zjIa86+LlW5;XM%*_w|AG&b%I_IYi$({Pk@}Dk;gP2ir`OoM4#{Pg(MM@v))F>S-Sd8kw`Rtv&jJx zOs68|xpKF%+T!y>)eH4LwdV;UcrNYq={X?QNpSbf&1K!t{5k&q3GgCL_d{+i|7VY; zc3HUr6@NEND!msr8<8lpR&esXKYZ{>Xzy=h>Co zO?QaIz|r%3_h`PiYu2Zvk=m1%Q}0%e=SIXU3<|94iB$sHBI@Pm%E!R~GK(Lbnb))n|#HO_8~-j5I%X+?-12?>Oqhsa``Crt6@~ zZ94f2Yc7LjxSRVaonPYAG=0uf6K!6$Bm#=0z4B}rRTLuU!_;G#Wb#Rb5%am;-J3R% z7s){c24DF09#fvSYVnVde2PCz?Ny#g=5)LMl+M(Ik$$@AKCV^MIj~WkAnBbr)6}y5 zvp{~pf}<)FE)Q{!dLM?E@qJx9>XhU5jrfxNRC6?nO@`ss&&f2Y<#XYE`A&1RRPzOP z-)bfBS@n{Buy7nj>R}2&=}B`_Rn!Ia$!XretzM|%w~bU=SdzmB31HersB!C>PlWgN zYtw-!=CvHE9wKe76p&cU`?hS5CAqJ)179uf$*?1Uwf3~i)K=KymE5i z3iM2W?}w0UkdwsAoHVj-29PtKd5z_OfK6bHf)flCJdQas#cFi|DW6xQGS1 z^I_7>dKWBs*~e2XLxjGRcalfXQuTK{U|MQ@(Vc7Z&FK^Zlc3~+>=MA7+b`EJOb15! za?@&2%wc5XK!GpD+B|O%lx8G)&0cG`MN@31pfb8q_iCQbm*CH2-Lc&fx(m8pQ<;?* zX2jHwB8}kbx!Pj;4&|vv1bsQom1E@jI`gSU=Jgz(NUimfWo_r_kS^G<;7&fTJ>u}) z=Aur1VcxodQLAHIQ>8$l$`1G7Nx!2-8Toas$4lGfDCI#)Hwk3qY*lIdSJt4(XwE}4 z{EfGindzG*AGrkfl`0ESyU!*=d<2q16nNugCNoL2T-gb0Bv<$7Oz(__l>kU9}Se82o3#^KKrcHi9y9i>3FLOn#3eZwXYCwJ3KRUz4Or#C;F4o& zxV7(PDUVk_OfK|vyn@&_2nU=o4Bt`pHXqj*~AWnn z5~1UKT_s|V@6PnZ5rM+e$De;~YK=UG@@@!yF5~2T;S7frIz)VbFKFdo_O%mMDR|-| z<2h9E2exM%RwZpPhHAJlSUN)p&F<6eeqBedZ|F~$YjWLQyer%3gnmXm>`pGQK{dYl zMP=ZgM+~ZkoKr3@9(f+Aq{+a7$V||M~T2`hZOd>P~XVHxxVb?z})ap(4Xn z0@DRZEHLqzA!75CqPA90uM^^5KT^L-0nf=IF!so%5HPSior7(+mPb}ULpzq>; zweih};9=1rlzNDGc_p`1wd@P((BKVaHTMOH;U2GZY14SXlREySMnht)@O*&+XOk*3 z7!%7z-uwzp<)y)yD2~nAa;u>Ygq*=v?G^ZRhEo1YWx5ATF7O#_QRfQkD7nar7&x6A z$6Rsy(u?ao7-RI$7nv1R*DsG9S!IhS>$=b;ah(HRvb#Domo ze4oHBwsJD@W|hnCSFeW+`P#jgDOZ%&C#w|ZufNmov33m07wQlFfrw7T1={Z&zd&6= zQMehKZZ zyyPv{l5ohE5A*GOf-YNlq=J!ooSHV~S8r3tuLyw@(vu*`Z##?b<^n2bG#9O2ouNgGYZxv?C;CbwY_52ILSM2y&k`m&QHBl8>!TFDRfoI zso%2m2=W<8+r0I*`fXLKU<;pD$w}DwFwlCZqfCS{;k}K;+p9a(aBEXHMZ-UOv>3 z*;5CeC-|*h9>~cuL@$m%Uc_r{nZufuf97?`2Vh2$Ly+dMD-ng4BBpM7su?_~LDJFe zG0I$A9~x^f4QMzP^Zr%&BV;jKdW1Nv_)fGR7uNRZ3NuHLx2sH3ItOuyj<#m5(lPYD zc2(lq>kcO1?3VOaaQf%5Acg7>{_X2Q^ATS6+FU8e_=e~zlj-8zv-!j!Rrl^#v5h=j zkly%Ovmj}njkQcn)Mu<$Rx2SpdW~63x`~)Oe>}Cs?-e9)W-#@ppNlg8aDgwxvMK&; zz8Xy1n~=;XV)E;3@{Fl2mH{)-_aZve6Bti%&>m~zd1ml!gm@H=nZ-%i=}hcO;QQ6>0VBfA zu#jm&das~MOnRWfFU##1{8i%>6!Y?;W)2WX!9?o={8)@`pyr}MrbeDL64T>yZe0zd ziw*CE8~4hbj~30LX{>T$FXBfuNqrk1AjC`)m1SM$F$M}h;xxFV>XGVZ>sZn zW6S1Hv1o&L;k{)B9oNfy8!`fx`lV9ucW_CR7aV(Mli5Dk1AdxE7Fo&al1q+D z7p(jl1^Fb=%c#Se)K;z@L(^37hp#APNN$^{#G6(5@dycA&0KVRo}@oZ9z$3T4G&5x zXf`D*Kl4=(8Illg4$}wYb()Lc42S?4Cqp5$C9FdqshPtJ7CaFvMoF1rxqMNb`8dpc z;9xS6WzIy5c-a)}D?U%&NOQba^qkib zJX`Oh(lETh^96>Vy>achfv^08$OC^#&pi?2Zag}xl#k!wnwTH4FM zmJ3VLs|Up8m%yKImYN{l@z#rR=Fp_f@DC$#t6c)7$pAAMuliv;A;7GVst=!Q@KnjH zxYp70e^qcT{!A|Z|CwRAM6yof%-lK{opPaWqRE%;u|d%Q0DNB-tp%`8~gX;Ca3FJbQgU@Av0@0a+XCYdz4Tsb7_` zGNqi1Oy(Yxa}38j9}SWF3=JPS#n+E4?RS`?OonSIxaQQ~+qXq8u%A4ZneA5>XsA!G z+{C?Jh}j7SOVo|b&ALG#qHfUp8bF{&6OGI9tI-opK%pbn@4CYPrfv`p6t~cnf$910 z#qF`-C0EaB1w9a~M@#6WhlY!|4Y}YZQHG8im_(pjORN_-;Sa=gQZUZ}V%*Z;{xMHK z!OBoSP68QUKM7_o#FTAvIFtt-c8q@~JspIPGw|P)nPQj#(7CG$ow&T*ctglvrVbK5n)%m-_R{|b7{pY(PqF?Ab0=!nbnM}>Z6hR zfDYD(5@cVRQc4p+XZbL2)<`z~47h7ld%(H0BtZB~GvJ^?otBS2O0`k$W3y0&3f_(QnNQTBm9=hX2JO*7w2xfjVH_aHf#cE)nt9 zsjl78rXj)sG~_4it^tey1Kk3@q=V@P{N6V4*&Am0F)yd9x79px?`nI*@+R4`cj2dR zY)-KyzTVr3_*Tx*j=k7j&QOIPGbmzF&zPos9oAS1ybjV%HikiW=sDB4tV%O*h6{Wi zr37d&H$UPY6fbnda=)3oPPDg9|*E0-iAiLSjv!58_OI*!rN{d@Nb)a^kK(3Z_uh17Gnh4PcZ%sBgkOhm2t*d1^(=He5#EW8&cum4G4-+s-3ktw4;*vvjQBS! z=_}C-MFv3OLu8-I*@x-l;{u?VX_mrW;`YG-@D$^NgFc|Wd468Ho~%HMaY(%SoIuNz zTe_^S6ae4uN-^7RzwL=tX8 zfPDm=X5VSODn(#KR=wzc6_X5ZZZQpStHnBf%{C#kh7RPuCtKce#2n6;S(Od1yE|`v zB?J<38{c$c;4{|eECQ@_Q+H6xJAN-$1*c~}>%Da__~B;!lnZ~OE(Ux9C3?HPjj1L* z$@{`we_e4a3pql*e|$!v3=0}m-U132s`JD^l3=Sv1Ui{WZ&MaH+ zO!#u)uhw5_k2wAw_JtD-SaM0kB!pMX6rL>1(tD33x28_)peHgsg4NB+cOse5YoV$1 z?#KTC`J7w;M8MAsz&s44iT|!SoS9DG;T!Lyx9=Qt@49dBLtA;-6W=zHKf5)}?R$_% zqWBtx(H|x0$gLWBWUlQy^g@+k92o&#^`DJck9GdS4D94;v`GuP6XA9W&JO6pwd3Rd zlNX8e2cAx&*)Lxk@=r@~>ZZWbw|LuP-Yk1uVdP-yb#Sv!a za~sC?--^BHHS}`CbqsPDNy>uED$UI7&2IJuOBq&*<4_ahk89N2zFh{qbZWC1d2v7C z=OimNKOnDWl5&sX`9>5pHT5$2!y2bKw&~IsLW~f6`kZSQAU3-J^>}A#OB?-Dj{FBB zoHetI?IVt4IubX-o)wPyzE^bhdV`uNY`pH{Z1WhhKH#X>`m@-h zpvO1n2^q5TY_0nFy0STc^O5DWU=?V659e02#P$!_ z`Hi+WM)RxLoDYtKUi&CAbo1efFV$b)RVhc?w-5Z(JoW{)Jf0!fE=_4Y z{^c4FrAu9T-h9}^+6e{oR2@nZ98ZT{RN65YGsI-M*dr)RRvglCoW2Uk8Vl>aDYZ<&7aTv%Kda{Rp?W%YlprKdii z(`*diz`M?cMH#RzlS0qdKJ9=Nainc~E^$}t>+op@S5y8tFUT_aHOkHcy;>R|INLpA z{($yF@_vgzW4O}B=(Y$T4gdRAzsA4U@zB*Xe?fh|-xTgekQa;h-rqDOaph7TcJ1Vg zen~J+i9zN&1=v1ICf@zt!Pmble)z23YX|zcty5}}7|(1&=HXGpjyeNwIHpU${db}R z(I`?Q66Kgu`ojzn4k^OD$R3(QG|kn%o=Z=s;`o}TDudT~<+#mqpTt|O2d@6*z3=XG zc*BkLXh=9Fd*A@Hq~Yp7c#v*0Bm^e3vb~_M<=N0U>glWQ_e{QVyC?>NdO- zHZLKK-3i-`8U{|yvX6C4MJ<&F9i{`nWuSE|dMG z+B|MB-USB?7@-UG@)@4J4~|KL+IQS{Kg)ZyJx8$?qp|h;FEKG8Tbl;Ac-*Xfa-A^MB%qb|TtA1s9TefY$5?o5tl^)jWsidH5I59h z>$BMFrvhU}9`vIu?S8x5-JSX>biBpx-i<$w4wu4WbzT2~KW5XJ7j51Mt2A5kZ7j*K z26)-l)mXmVd8BxSgRk=xiPV;krMxbZOTeV}7PS1C$La`6 zIZjlIl$Oy0S7+I;^60d;V*TbT z-MM2n+!(vj+4krg`jk;?pDgwHB=2%|&VPVZ`}74<8Zr|H-w9v4^8*xE5$05tDm=Hu z=Cs3?Zmk9yyCw`YP&tC=^_Fd#liO6ZhhV=+jN>O; zfd-762|H5g6)$!#Zc^f&`AFAWX-wD%W0R(Sxgkl)<~^v>N?v5f&6s;J@u21ADK!#| z1E7ZADRBn#-;ZJE<4%E1C3~DpaLmrO5(*@OK$rGeAz_61DCs zRyl$0Mgi8I*o|7IpoaXfB!%OL5Ah;8V-zE-VdL=1-RWdN+#;|81-s7fx{vu3;M^Ef z7x(|PE55QTLTHVY^42a|flTY!B0;Pj#o|hLfeo^1K7-B-MdeA=b-LJR30LgYO`Dx@ zcEa4;Qs@Xfh}FPM+!py+bE}H|F)M-RsKASCfgW9kW5)!_n4TVrZ~x2jC|<%tXD^o2 zxe9N>pKnPmWl;cNaioe%GJ%t|&z|q4?#Y?H9_n7=l;P|`JpX6#pvUeOO>G-s>u_|I za|^C`&;b529}RL~*G7mty&LNgPD-3g1Yk&yHibE7&DM;4QsMNy z6hc@dSQs_&9)if4zFHWP3-6h{s!PdrKW8@0@Y_zb&daLpP%z`wlX@%sqz-7??$W%W zuR}8MimHYegB1z!Mat1i!`Z861{CbxL-igrEJ1fiH1r>NnQF_a@jeKak`w;Jops?z#Dr_J~QiMB;ET1fz zyc`&VeXpr=7VU<*&wUC5lBZ~#BhKIGQ7wKEvDA9-xCPBp^NoeynzpcKcRAc2i{Nt`%! zof_4O^7BeGRE!gGHtbKZk#ge?XhYIUE`pyyp%pPH?+X|*Nboe*I4N}9O2-pKLGnKp zoDJQx=MdVn6{>zM3m!%=&y8e}#ae75tb-g5dUl{i8gLy5u;|+2kco|e4KFnX?>%`61`GBQaA_t@;HPQ5Iq-vm`Ro{!~vZ3p{LtH^Ls)L_S0p=DbE08Az zSY@qHYY!^80m{{Lc5m)b<1Pzc>E}C@9BF literal 0 HcmV?d00001 diff --git a/samples/python2/deconvolution.py b/samples/python2/deconvolution.py new file mode 100644 index 0000000000..cbce8a2c50 --- /dev/null +++ b/samples/python2/deconvolution.py @@ -0,0 +1,118 @@ +''' +Wiener deconvolution. + +Sample shows how DFT can be used to perform Weiner deconvolution [1] +of an image with user-defined point spread function (PSF) + +Usage: + deconvolution.py [--circle] + [--angle ] + [--d ] + [--snr ] + [] + + Use sliders to adjust PSF paramitiers. + Keys: + SPACE - switch btw linear/cirular PSF + ESC - exit + +Examples: + deconvolution.py --angle 135 --d 22 data/licenseplate_motion.jpg + (image source: http://www.topazlabs.com/infocus/_images/licenseplate_compare.jpg) + + deconvolution.py --angle 86 --d 31 data/text_motion.jpg + deconvolution.py --circle --d 19 data/text_defocus.jpg + (image source: compact digital photo camera, no artificial distortion) + + +[1] http://en.wikipedia.org/wiki/Wiener_deconvolution +''' + +import numpy as np +import cv2 +from common import nothing + + +def blur_edge(img, d=31): + h, w = img.shape[:2] + img_pad = cv2.copyMakeBorder(img, d, d, d, d, cv2.BORDER_WRAP) + img_blur = cv2.GaussianBlur(img_pad, (2*d+1, 2*d+1), -1)[d:-d,d:-d] + y, x = np.indices((h, w)) + dist = np.dstack([x, w-x-1, y, h-y-1]).min(-1) + w = np.minimum(np.float32(dist)/d, 1.0) + return img*w + img_blur*(1-w) + +def motion_kernel(angle, d, sz=65): + kern = np.ones((1, d), np.float32) + c, s = np.cos(angle), np.sin(angle) + A = np.float32([[c, -s, 0], [s, c, 0]]) + sz2 = sz // 2 + A[:,2] = (sz2, sz2) - np.dot(A[:,:2], ((d-1)*0.5, 0)) + kern = cv2.warpAffine(kern, A, (sz, sz), flags=cv2.INTER_CUBIC) + return kern + +def defocus_kernel(d, sz=65): + kern = np.zeros((sz, sz), np.uint8) + cv2.circle(kern, (sz, sz), d, 255, -1, cv2.CV_AA, shift=1) + kern = np.float32(kern) / 255.0 + return kern + + +if __name__ == '__main__': + print __doc__ + import sys, getopt + opts, args = getopt.getopt(sys.argv[1:], '', ['circle', 'angle=', 'd=', 'snr=']) + opts = dict(opts) + try: fn = args[0] + except: fn = 'data/licenseplate_motion.jpg' + + win = 'deconvolution' + + img = cv2.imread(fn, 0) + img = np.float32(img)/255.0 + cv2.imshow('input', img) + + img = blur_edge(img) + IMG = cv2.dft(img, flags=cv2.DFT_COMPLEX_OUTPUT) + + defocus = '--circle' in opts + + def update(_): + ang = np.deg2rad( cv2.getTrackbarPos('angle', win) ) + d = cv2.getTrackbarPos('d', win) + noise = 10**(-0.1*cv2.getTrackbarPos('SNR (db)', win)) + + if defocus: + psf = defocus_kernel(d) + else: + psf = motion_kernel(ang, d) + cv2.imshow('psf', psf) + + psf /= psf.sum() + psf_pad = np.zeros_like(img) + kh, kw = psf.shape + psf_pad[:kh, :kw] = psf + PSF = cv2.dft(psf_pad, flags=cv2.DFT_COMPLEX_OUTPUT, nonzeroRows = kh) + PSF2 = (PSF**2).sum(-1) + iPSF = PSF / (PSF2 + noise)[...,np.newaxis] + RES = cv2.mulSpectrums(IMG, iPSF, 0) + res = cv2.idft(RES, flags=cv2.DFT_SCALE | cv2.DFT_REAL_OUTPUT ) + res = np.roll(res, -kh//2, 0) + res = np.roll(res, -kw//2, 1) + cv2.imshow(win, res) + + cv2.namedWindow(win) + cv2.namedWindow('psf', 0) + cv2.createTrackbar('angle', win, int(opts.get('--angle', 135)), 180, update) + cv2.createTrackbar('d', win, int(opts.get('--d', 22)), 50, update) + cv2.createTrackbar('SNR (db)', win, int(opts.get('--snr', 25)), 50, update) + update(None) + + while True: + ch = cv2.waitKey() + if ch == 27: + break + if ch == ord(' '): + defocus = not defocus + update(None) + From 8e2258c494db6bc701aceab443278f1f10e6d867 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Sun, 19 Aug 2012 00:20:08 +0400 Subject: [PATCH 017/163] Fix Windows build after commit:41b6d25 --- modules/core/src/parallel.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp index c238f992b0..8072a11589 100644 --- a/modules/core/src/parallel.cpp +++ b/modules/core/src/parallel.cpp @@ -116,7 +116,22 @@ namespace cv #elif defined HAVE_CONCURRENCY - Concurrency::parallel_for(range.start, range.end, body); + class ConcurrencyProxyLoopBody + { + public: + ConcurrencyProxyLoopBody(const ParallelLoopBody& body) : _body(body) {} + + void operator ()(int i) const + { + _body(Range(i, i + 1)); + } + + private: + const ParallelLoopBody& _body; + ConcurrencyProxyLoopBody& operator=(const ConcurrencyProxyLoopBody&) {return *this;} + } proxy(body); + + Concurrency::parallel_for(range.start, range.end, proxy); #elif defined HAVE_OPENMP From 1f42de39a33a3a5e2f9f21d4ea36219b42d6a865 Mon Sep 17 00:00:00 2001 From: Victor Passichenko Date: Sun, 19 Aug 2012 13:13:58 +0400 Subject: [PATCH 018/163] Add non-local means denoising algorithm implementatation into photo module --- modules/photo/doc/denoising.rst | 91 ++++ modules/photo/doc/photo.rst | 1 + .../photo/include/opencv2/photo/denoising.hpp | 79 ++++ modules/photo/src/arrays.hpp | 161 +++++++ modules/photo/src/denoising.cpp | 220 ++++++++++ .../src/fast_nlmeans_denoising_invoker.hpp | 342 +++++++++++++++ ...fast_nlmeans_denoising_invoker_commons.hpp | 120 ++++++ .../fast_nlmeans_multi_denoising_invoker.hpp | 394 ++++++++++++++++++ modules/photo/test/test_denoising.cpp | 213 ++++++++++ 9 files changed, 1621 insertions(+) create mode 100644 modules/photo/doc/denoising.rst create mode 100644 modules/photo/include/opencv2/photo/denoising.hpp create mode 100644 modules/photo/src/arrays.hpp create mode 100644 modules/photo/src/denoising.cpp create mode 100644 modules/photo/src/fast_nlmeans_denoising_invoker.hpp create mode 100644 modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp create mode 100644 modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp create mode 100644 modules/photo/test/test_denoising.cpp diff --git a/modules/photo/doc/denoising.rst b/modules/photo/doc/denoising.rst new file mode 100644 index 0000000000..957ec88006 --- /dev/null +++ b/modules/photo/doc/denoising.rst @@ -0,0 +1,91 @@ +Denoising +========== + +.. highlight:: cpp + +fastNlMeansDenoising +----------- +Perform image denoising using Non-local Means Denoising algorithm http://www.ipol.im/pub/algo/bcm_non_local_means_denoising/ +with several computational optimizations. Noise expected to be a gaussian white noise + +.. ocv:function:: void fastNlMeansDenoising( Mat& src, Mat& dst, int templateWindowSize, int searchWindowSize, int h ) + + :param src: Input 8-bit 1-channel, 2-channel or 3-channel image. + + :param dst: Output image with the same size and type as ``src`` . + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength. Big h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise + +This function expected to be applied to grayscale images. For colored images look at ``fastNlMeansDenoisingColored``. +Advanced usage of this functions can be manual denoising of colored image in different colorspaces. +Such approach is used in ``fastNlMeansDenoisingColored`` by converting image to CIELAB colorspace and then separately denoise L and AB components with different h parameter. + +fastNlMeansDenoisingColored +----------- +Modification of ``fastNlMeansDenoising`` function for colored images + +.. ocv:function:: void fastNlMeansDenoisingColored( Mat& src, Mat& dst, int templateWindowSize, int searchWindowSize, int h, int hForColorComponents ) + + :param src: Input 8-bit 3-channel image. + + :param dst: Output image with the same size and type as ``src`` . + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise + + :param hForColorComponents: The same as h but for color components. For most images value equals 10 will be enought to remove colored noise and do not distort colors + +The function converts image to CIELAB colorspace and then separately denoise L and AB components with given h parameters using ``fastNlMeansDenoising`` function. + +fastNlMeansDenoisingMulti +----------- +Modification of ``fastNlMeansDenoising`` function for images sequence where consequtive images have been captured in small period of time. For example video. This version of the function is for grayscale images or for manual manipulation with colorspaces. +For more details see http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.131.6394 + +.. ocv:function:: void fastNlMeansDenoisingMulti( const std::vector& srcImgs, int imgToDenoiseIndex, int temporalWindowSize, Mat& dst, int templateWindowSize, int searchWindowSize, int h) + + :param srcImgs: Input 8-bit 1-channel, 2-channel or 3-channel images sequence. All images should have the same type and size. + + :param imgToDenoiseIndex: Target image to denoise index in ``srcImgs`` sequence + + :param temporalWindowSize: Number of surrounding images to use for target image denoising. Should be odd. Images from ``imgToDenoiseIndex - temporalWindowSize / 2`` to ``imgToDenoiseIndex - temporalWindowSize / 2`` from ``srcImgs`` will be used to denoise ``srcImgs[imgToDenoiseIndex]`` image. + + :param dst: Output image with the same size and type as ``srcImgs`` images. + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise + +fastNlMeansDenoisingColoredMulti +----------- +Modification of ``fastNlMeansDenoisingMulti`` function for colored images sequences + +.. ocv:function:: void fastNlMeansDenoisingColoredMulti( const std::vector& srcImgs, int imgToDenoiseIndex, int temporalWindowSize, Mat& dst, int templateWindowSize, int searchWindowSize, int h, int hForColorComponents) + + :param srcImgs: Input 8-bit 3-channel images sequence. All images should have the same type and size. + + :param imgToDenoiseIndex: Target image to denoise index in ``srcImgs`` sequence + + :param temporalWindowSize: Number of surrounding images to use for target image denoising. Should be odd. Images from ``imgToDenoiseIndex - temporalWindowSize / 2`` to ``imgToDenoiseIndex - temporalWindowSize / 2`` from ``srcImgs`` will be used to denoise ``srcImgs[imgToDenoiseIndex]`` image. + + :param dst: Output image with the same size and type as ``srcImgs`` images. + + :param templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels + + :param searchWindowSize: Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels + + :param h: Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise. + + :param hForColorComponents: The same as h but for color components. + +The function converts images to CIELAB colorspace and then separately denoise L and AB components with given h parameters using ``fastNlMeansDenoisingMulti`` function. + diff --git a/modules/photo/doc/photo.rst b/modules/photo/doc/photo.rst index 9d8636ee73..6f05239120 100644 --- a/modules/photo/doc/photo.rst +++ b/modules/photo/doc/photo.rst @@ -8,3 +8,4 @@ photo. Computational Photography :maxdepth: 2 inpainting + denoising diff --git a/modules/photo/include/opencv2/photo/denoising.hpp b/modules/photo/include/opencv2/photo/denoising.hpp new file mode 100644 index 0000000000..b322c31755 --- /dev/null +++ b/modules/photo/include/opencv2/photo/denoising.hpp @@ -0,0 +1,79 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_DENOISING_HPP__ +#define __OPENCV_DENOISING_HPP__ + +#include "opencv2/core/core.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include + +#ifdef __cplusplus + +/*! \namespace cv + Namespace where all the C++ OpenCV functionality resides + */ +namespace cv +{ + +CV_EXPORTS void fastNlMeansDenoising( const Mat& src, Mat& dst, + int templateWindowSize, int searchWindowSize, int h); + +CV_EXPORTS void fastNlMeansDenoisingColored( const Mat& src, Mat& dst, + int templateWindowSize, int searchWindowSize, + int h, int hForColorComponents); + +CV_EXPORTS void fastNlMeansDenoisingMulti( const std::vector& srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + Mat& dst, + int templateWindowSize, int searchWindowSize, int h); + +CV_EXPORTS void fastNlMeansDenoisingColoredMulti( const std::vector& srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + Mat& dst, + int templateWindowSize, int searchWindowSize, + int h, int hForColorComponents); + +} +#endif + +#endif diff --git a/modules/photo/src/arrays.hpp b/modules/photo/src/arrays.hpp new file mode 100644 index 0000000000..c1c4e5f971 --- /dev/null +++ b/modules/photo/src/arrays.hpp @@ -0,0 +1,161 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_DENOISING_ARRAYS_HPP__ +#define __OPENCV_DENOISING_ARRAYS_HPP__ + +template struct Array2d { + T* a; + int n1,n2; + bool needToDeallocArray; + + Array2d(const Array2d& array2d): + a(array2d.a), n1(array2d.n1), n2(array2d.n2), needToDeallocArray(false) + { + if (array2d.needToDeallocArray) { + // copy constructor for self allocating arrays not supported + throw new exception(); + } + } + + Array2d(T* _a, int _n1, int _n2): + a(_a), n1(_n1), n2(_n2), needToDeallocArray(false) {} + + Array2d(int _n1, int _n2): + n1(_n1), n2(_n2), needToDeallocArray(true) + { + a = new T[n1*n2]; + } + + ~Array2d() { + if (needToDeallocArray) { + delete a; + } + } + + T* operator [] (int i) { + return a + i*n2; + } + + inline T* row_ptr(int i) { + return (*this)[i]; + } +}; + +template struct Array3d { + T* a; + int n1,n2,n3; + bool needToDeallocArray; + + Array3d(T* _a, int _n1, int _n2, int _n3): + a(_a), n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(false) {} + + Array3d(int _n1, int _n2, int _n3): + n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(true) + { + a = new T[n1*n2*n3]; + } + + ~Array3d() { + if (needToDeallocArray) { + delete a; + } + } + + Array2d operator [] (int i) { + Array2d array2d(a + i*n2*n3, n2, n3); + return array2d; + } + + inline T* row_ptr(int i1, int i2) { + return a + i1*n2*n3 + i2*n3; + } +}; + +template struct Array4d { + T* a; + int n1,n2,n3,n4; + bool needToDeallocArray; + int steps[4]; + + void init_steps() { + steps[0] = n2*n3*n4; + steps[1] = n3*n4; + steps[2] = n4; + steps[3] = 1; + } + + Array4d(T* _a, int _n1, int _n2, int _n3, int _n4): + a(_a), n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(false) + { + init_steps(); + } + + Array4d(int _n1, int _n2, int _n3, int _n4): + n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(true) + { + a = new T[n1*n2*n3*n4]; + init_steps(); + } + + ~Array4d() { + if (needToDeallocArray) { + delete a; + } + } + + Array3d operator [] (int i) { + Array3d array3d(a + i*n2*n3*n4, n2, n3, n4); + return array3d; + } + + inline T* row_ptr(int i1, int i2, int i3) { + return a + i1*n2*n3*n4 + i2*n3*n4 + i3*n4; + } + + inline int step_size(int dimension) { + return steps[dimension]; + } +}; + +#endif + + diff --git a/modules/photo/src/denoising.cpp b/modules/photo/src/denoising.cpp new file mode 100644 index 0000000000..39643e33dc --- /dev/null +++ b/modules/photo/src/denoising.cpp @@ -0,0 +1,220 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/photo/denoising.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "fast_nlmeans_denoising_invoker.hpp" +#include "fast_nlmeans_multi_denoising_invoker.hpp" + +void cv::fastNlMeansDenoising( const cv::Mat& src, cv::Mat& dst, + int templateWindowSize, int searchWindowSize, int h) +{ + switch (src.type()) { + case CV_8U: + parallel_for(cv::BlockedRange(0, src.rows), + FastNlMeansDenoisingInvoker( + src, dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC2: + parallel_for(cv::BlockedRange(0, src.rows), + FastNlMeansDenoisingInvoker( + src, dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC3: + parallel_for(cv::BlockedRange(0, src.rows), + FastNlMeansDenoisingInvoker( + src, dst, templateWindowSize, searchWindowSize, h)); + break; + default: + CV_Error(CV_StsBadArg, + "Unsupported matrix format! Only uchar, Vec2b, Vec3b are supported"); + } +} + +void cv::fastNlMeansDenoisingColored( const cv::Mat& src, cv::Mat& dst, + int templateWindowSize, int searchWindowSize, + int h, int hForColorComponents) +{ + if (src.type() != CV_8UC3) { + CV_Error(CV_StsBadArg, "Type of input image should be CV_8UC3!"); + return; + } + + Mat src_lab; + cvtColor(src, src_lab, CV_LBGR2Lab); + + Mat l(src.size(), CV_8U); + Mat ab(src.size(), CV_8UC2); + Mat l_ab[] = { l, ab }; + int from_to[] = { 0,0, 1,1, 2,2 }; + mixChannels(&src_lab, 1, l_ab, 2, from_to, 3); + + fastNlMeansDenoising(l, l, templateWindowSize, searchWindowSize, h); + fastNlMeansDenoising(ab, ab, templateWindowSize, searchWindowSize, hForColorComponents); + + Mat l_ab_denoised[] = { l, ab }; + Mat dst_lab(src.size(), src.type()); + mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3); + + cvtColor(dst_lab, dst, CV_Lab2LBGR); +} + +static void fastNlMeansDenoisingMultiCheckPreconditions( + const std::vector& srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + int templateWindowSize, int searchWindowSize) +{ + int src_imgs_size = srcImgs.size(); + if (src_imgs_size == 0) { + CV_Error(CV_StsBadArg, "Input images vector should not be empty!"); + } + + if (temporalWindowSize % 2 == 0 || + searchWindowSize % 2 == 0 || + templateWindowSize % 2 == 0) { + CV_Error(CV_StsBadArg, "All windows sizes should be odd!"); + } + + int temporalWindowHalfSize = temporalWindowSize / 2; + if (imgToDenoiseIndex - temporalWindowHalfSize < 0 || + imgToDenoiseIndex + temporalWindowHalfSize >= src_imgs_size) + { + CV_Error(CV_StsBadArg, + "imgToDenoiseIndex and temporalWindowSize " + "should be choosen corresponding srcImgs size!"); + } + + for (int i = 1; i < src_imgs_size; i++) { + if (srcImgs[0].size() != srcImgs[i].size() || srcImgs[0].type() != srcImgs[i].type()) { + CV_Error(CV_StsBadArg, "Input images should have the same size and type!"); + } + } +} + +void cv::fastNlMeansDenoisingMulti( const std::vector& srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + cv::Mat& dst, + int templateWindowSize, int searchWindowSize, int h) +{ + fastNlMeansDenoisingMultiCheckPreconditions( + srcImgs, imgToDenoiseIndex, + temporalWindowSize, templateWindowSize, searchWindowSize + ); + + switch (srcImgs[0].type()) { + case CV_8U: + parallel_for(cv::BlockedRange(0, srcImgs[0].rows), + FastNlMeansMultiDenoisingInvoker( + srcImgs, imgToDenoiseIndex, temporalWindowSize, + dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC2: + parallel_for(cv::BlockedRange(0, srcImgs[0].rows), + FastNlMeansMultiDenoisingInvoker( + srcImgs, imgToDenoiseIndex, temporalWindowSize, + dst, templateWindowSize, searchWindowSize, h)); + break; + case CV_8UC3: + parallel_for(cv::BlockedRange(0, srcImgs[0].rows), + FastNlMeansMultiDenoisingInvoker( + srcImgs, imgToDenoiseIndex, temporalWindowSize, + dst, templateWindowSize, searchWindowSize, h)); + break; + default: + CV_Error(CV_StsBadArg, + "Unsupported matrix format! Only uchar, Vec2b, Vec3b are supported"); + } +} + +void cv::fastNlMeansDenoisingColoredMulti( const std::vector& srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + cv::Mat& dst, + int templateWindowSize, int searchWindowSize, + int h, int hForColorComponents) +{ + fastNlMeansDenoisingMultiCheckPreconditions( + srcImgs, imgToDenoiseIndex, + temporalWindowSize, templateWindowSize, searchWindowSize + ); + + int src_imgs_size = srcImgs.size(); + + if (srcImgs[0].type() != CV_8UC3) { + CV_Error(CV_StsBadArg, "Type of input images should be CV_8UC3!"); + return; + } + + int from_to[] = { 0,0, 1,1, 2,2 }; + + // TODO convert only required images + vector src_lab(src_imgs_size); + vector l(src_imgs_size); + vector ab(src_imgs_size); + for (int i = 0; i < src_imgs_size; i++) { + src_lab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC3); + l[i] = Mat::zeros(srcImgs[0].size(), CV_8UC1); + ab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC2); + cvtColor(srcImgs[i], src_lab[i], CV_LBGR2Lab); + + Mat l_ab[] = { l[i], ab[i] }; + mixChannels(&src_lab[i], 1, l_ab, 2, from_to, 3); + } + + Mat dst_l; + Mat dst_ab; + + fastNlMeansDenoisingMulti( + l, imgToDenoiseIndex, temporalWindowSize, + dst_l, templateWindowSize, searchWindowSize, h); + + fastNlMeansDenoisingMulti( + ab, imgToDenoiseIndex, temporalWindowSize, + dst_ab, templateWindowSize, searchWindowSize, hForColorComponents); + + Mat l_ab_denoised[] = { dst_l, dst_ab }; + Mat dst_lab(srcImgs[0].size(), srcImgs[0].type()); + mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3); + + cvtColor(dst_lab, dst, CV_Lab2LBGR); +} + + diff --git a/modules/photo/src/fast_nlmeans_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_denoising_invoker.hpp new file mode 100644 index 0000000000..58e4a45e17 --- /dev/null +++ b/modules/photo/src/fast_nlmeans_denoising_invoker.hpp @@ -0,0 +1,342 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_HPP__ +#define __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_HPP__ + +#include "precomp.hpp" +#include +#include +#include +#include + +#include "fast_nlmeans_denoising_invoker_commons.hpp" +#include "arrays.hpp" + +using namespace std; +using namespace cv; + +template +struct FastNlMeansDenoisingInvoker { + public: + FastNlMeansDenoisingInvoker(const Mat& src, Mat& dst, + int template_window_size, int search_window_size, const double h); + + void operator() (const BlockedRange& range) const; + + private: + const Mat& src_; + Mat& dst_; + + Mat extended_src_; + int border_size_; + + int template_window_size_; + int search_window_size_; + + int template_window_half_size_; + int search_window_half_size_; + + int fixed_point_mult_; + int almost_template_window_size_sq_bin_shift; + vector almost_dist2weight; + + void calcDistSumsForFirstElementInRow( + int i, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const; + + void calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const; +}; + +template +FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker( + const cv::Mat& src, + cv::Mat& dst, + int template_window_size, + int search_window_size, + const double h) : src_(src), dst_(dst) +{ + template_window_half_size_ = template_window_size / 2; + search_window_half_size_ = search_window_size / 2; + template_window_size_ = template_window_half_size_ * 2 + 1; + search_window_size_ = search_window_half_size_ * 2 + 1; + + border_size_ = search_window_half_size_ + template_window_half_size_; + copyMakeBorder(src_, extended_src_, + border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); + + const int max_estimate_sum_value = search_window_size_ * search_window_size_ * 255; + fixed_point_mult_ = numeric_limits::max() / max_estimate_sum_value; + + // precalc weight for every possible l2 dist between blocks + // additional optimization of precalced weights to replace division(averaging) by binary shift + int template_window_size_sq = template_window_size_ * template_window_size_; + almost_template_window_size_sq_bin_shift = 0; + while (1 << almost_template_window_size_sq_bin_shift < template_window_size_sq) { + almost_template_window_size_sq_bin_shift++; + } + + int almost_template_window_size_sq = 1 << almost_template_window_size_sq_bin_shift; + double almost_dist2actual_dist_multiplier = + ((double) almost_template_window_size_sq) / template_window_size_sq; + + int max_dist = 256 * 256 * src_.channels(); + int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); + almost_dist2weight.resize(almost_max_dist); + + const double WEIGHT_THRESHOLD = 0.001; + for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { + double dist = almost_dist * almost_dist2actual_dist_multiplier; + int weight = cvRound(fixed_point_mult_ * std::exp(- dist / (h * h * src_.channels()))); + + if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) { + weight = 0; + } + + almost_dist2weight[almost_dist] = weight; + } + // additional optimization init end + + if (dst_.empty()) { + dst_ = Mat::zeros(src_.size(), src_.type()); + } +} + +template +void FastNlMeansDenoisingInvoker::operator() (const BlockedRange& range) const { + int row_from = range.begin(); + int row_to = range.end() - 1; + + int dist_sums_array[search_window_size_ * search_window_size_]; + Array2d dist_sums(dist_sums_array, search_window_size_, search_window_size_); + + // for lazy calc optimization + int col_dist_sums_array[template_window_size_ * search_window_size_ * search_window_size_]; + Array3d col_dist_sums(&col_dist_sums_array[0], + template_window_size_, search_window_size_, search_window_size_); + + int first_col_num = -1; + + Array3d up_col_dist_sums(src_.cols, search_window_size_, search_window_size_); + + for (int i = row_from; i <= row_to; i++) { + for (int j = 0; j < src_.cols; j++) { + int search_window_y = i - search_window_half_size_; + int search_window_x = j - search_window_half_size_; + + // calc dist_sums + if (j == 0) { + calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); + first_col_num = 0; + + } else { // calc cur dist_sums using previous dist_sums + if (i == row_from) { + calcDistSumsForElementInFirstRow(i, j, first_col_num, + dist_sums, col_dist_sums, up_col_dist_sums); + + } else { + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = + border_size_ + i - search_window_half_size_; + + int start_bx = + border_size_ + j - search_window_half_size_ + template_window_half_size_; + + T a_up = extended_src_.at(ay - template_window_half_size_ - 1, ax); + T a_down = extended_src_.at(ay + template_window_half_size_, ax); + + // copy class member to local variable for optimization + int search_window_size = search_window_size_; + + for (int y = 0; y < search_window_size; y++) { + int* dist_sums_row = dist_sums.row_ptr(y); + + int* col_dist_sums_row = col_dist_sums.row_ptr(first_col_num,y); + + int* up_col_dist_sums_row = up_col_dist_sums.row_ptr(j, y); + + const T* b_up_ptr = + extended_src_.ptr(start_by - template_window_half_size_ - 1 + y); + + const T* b_down_ptr = + extended_src_.ptr(start_by + template_window_half_size_ + y); + + for (int x = 0; x < search_window_size; x++) { + dist_sums_row[x] -= col_dist_sums_row[x]; + + col_dist_sums_row[x] = + up_col_dist_sums_row[x] + + calcUpDownDist( + a_up, a_down, + b_up_ptr[start_bx + x], b_down_ptr[start_bx + x] + ); + + dist_sums_row[x] += col_dist_sums_row[x]; + + up_col_dist_sums_row[x] = col_dist_sums_row[x]; + + } + } + } + + first_col_num = (first_col_num + 1) % template_window_size_; + } + + // calc weights + int weights_sum = 0; + + int estimation[src_.channels()]; + for (int channel_num = 0; channel_num < src_.channels(); channel_num++) { + estimation[channel_num] = 0; + } + + for (int y = 0; y < search_window_size_; y++) { + const T* cur_row_ptr = extended_src_.ptr(border_size_ + search_window_y + y); + int* dist_sums_row = dist_sums.row_ptr(y); + for (int x = 0; x < search_window_size_; x++) { + int almostAvgDist = + dist_sums_row[x] >> almost_template_window_size_sq_bin_shift; + + int weight = almost_dist2weight[almostAvgDist]; + weights_sum += weight; + + T p = cur_row_ptr[border_size_ + search_window_x + x]; + incWithWeight(estimation, weight, p); + } + } + + if (weights_sum > 0) { + for (int channel_num = 0; channel_num < src_.channels(); channel_num++) { + estimation[channel_num] = + cvRound(((double)estimation[channel_num]) / weights_sum); + } + + dst_.at(i,j) = saturateCastFromArray(estimation); + + } else { // weights_sum == 0 + dst_.at(i,j) = src_.at(i,j); + } + } + } +} + +template +inline void FastNlMeansDenoisingInvoker::calcDistSumsForFirstElementInRow( + int i, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const +{ + int j = 0; + + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[y][x] = 0; + for (int tx = 0; tx < template_window_size_; tx++) { + col_dist_sums[tx][y][x] = 0; + } + + int start_y = i + y - search_window_half_size_; + int start_x = j + x - search_window_half_size_; + + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { + int dist = calcDist(extended_src_, + border_size_ + i + ty, border_size_ + j + tx, + border_size_ + start_y + ty, border_size_ + start_x + tx); + + dist_sums[y][x] += dist; + col_dist_sums[tx + template_window_half_size_][y][x] += dist; + } + } + + up_col_dist_sums[j][y][x] = col_dist_sums[template_window_size_ - 1][y][x]; + } + } +} + +template +inline void FastNlMeansDenoisingInvoker::calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array2d& dist_sums, + Array3d& col_dist_sums, + Array3d& up_col_dist_sums) const +{ + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = border_size_ + i - search_window_half_size_; + int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_; + + int new_last_col_num = first_col_num; + + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[y][x] -= col_dist_sums[first_col_num][y][x]; + + col_dist_sums[new_last_col_num][y][x] = 0; + int by = start_by + y; + int bx = start_bx + x; + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + col_dist_sums[new_last_col_num][y][x] += + calcDist(extended_src_, ay + ty, ax, by + ty, bx); + } + + dist_sums[y][x] += col_dist_sums[new_last_col_num][y][x]; + + up_col_dist_sums[j][y][x] = col_dist_sums[new_last_col_num][y][x]; + } + } +} + +#endif diff --git a/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp b/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp new file mode 100644 index 0000000000..c1084f15e9 --- /dev/null +++ b/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp @@ -0,0 +1,120 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_COMMONS_HPP__ +#define __OPENCV_FAST_NLMEANS_DENOISING_INVOKER_COMMONS_HPP__ + +#include +#include +#include + +using namespace std; +using namespace cv; + +template static inline int calcDist(const T a, const T b); + +template <> inline int calcDist(const uchar a, const uchar b) { + return (a-b) * (a-b); +} + +template <> inline int calcDist(const Vec2b a, const Vec2b b) { + return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]); +} + +template <> inline int calcDist(const Vec3b a, const Vec3b b) { + return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2]); +} + +template static inline int calcDist(const Mat& m, int i1, int j1, int i2, int j2) { + const T a = m.at(i1, j1); + const T b = m.at(i2, j2); + return calcDist(a,b); +} + +template static inline int calcUpDownDist(T a_up, T a_down, T b_up, T b_down) { + return calcDist(a_down,b_down) - calcDist(a_up, b_up); +} + +template <> inline int calcUpDownDist(uchar a_up, uchar a_down, uchar b_up, uchar b_down) { + int A = a_down - b_down; + int B = a_up - b_up; + return (A-B)*(A+B); +} + +template static inline void incWithWeight(int* estimation, int weight, T p); + +template <> inline void incWithWeight(int* estimation, int weight, uchar p) { + estimation[0] += weight * p; +} + +template <> inline void incWithWeight(int* estimation, int weight, Vec2b p) { + estimation[0] += weight * p[0]; + estimation[1] += weight * p[1]; +} + +template <> inline void incWithWeight(int* estimation, int weight, Vec3b p) { + estimation[0] += weight * p[0]; + estimation[1] += weight * p[1]; + estimation[2] += weight * p[2]; +} + +template static inline T saturateCastFromArray(int* estimation); + +template <> inline uchar saturateCastFromArray(int* estimation) { + return saturate_cast(estimation[0]); +} + +template <> inline Vec2b saturateCastFromArray(int* estimation) { + Vec2b res; + res[0] = saturate_cast(estimation[0]); + res[1] = saturate_cast(estimation[1]); + return res; +} + +template <> inline Vec3b saturateCastFromArray(int* estimation) { + Vec3b res; + res[0] = saturate_cast(estimation[0]); + res[1] = saturate_cast(estimation[1]); + res[2] = saturate_cast(estimation[2]); + return res; +} + +#endif diff --git a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp new file mode 100644 index 0000000000..cb08c7e434 --- /dev/null +++ b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp @@ -0,0 +1,394 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective icvers. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__ +#define __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__ + +#include "precomp.hpp" +#include +#include +#include +#include + +#include "fast_nlmeans_denoising_invoker_commons.hpp" +#include "arrays.hpp" + +using namespace std; +using namespace cv; + +template +struct FastNlMeansMultiDenoisingInvoker { + public: + FastNlMeansMultiDenoisingInvoker( + const std::vector& srcImgs, int imgToDenoiseIndex, int temporalWindowSize, + Mat& dst, int template_window_size, int search_window_size, const double h); + + void operator() (const BlockedRange& range) const; + + private: + int rows_; + int cols_; + int channels_count_; + + Mat& dst_; + + vector extended_srcs_; + Mat main_extended_src_; + int border_size_; + + int template_window_size_; + int search_window_size_; + int temporal_window_size_; + + int template_window_half_size_; + int search_window_half_size_; + int temporal_window_half_size_; + + int fixed_point_mult_; + int almost_template_window_size_sq_bin_shift; + vector almost_dist2weight; + + void calcDistSumsForFirstElementInRow( + int i, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const; + + void calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const; +}; + +template +FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker( + const vector& srcImgs, + int imgToDenoiseIndex, + int temporalWindowSize, + cv::Mat& dst, + int template_window_size, + int search_window_size, + const double h) : dst_(dst), extended_srcs_(srcImgs.size()) +{ + rows_ = srcImgs[0].rows; + cols_ = srcImgs[0].cols; + channels_count_ = srcImgs[0].channels(); + + template_window_half_size_ = template_window_size / 2; + search_window_half_size_ = search_window_size / 2; + temporal_window_half_size_ = temporalWindowSize / 2; + + template_window_size_ = template_window_half_size_ * 2 + 1; + search_window_size_ = search_window_half_size_ * 2 + 1; + temporal_window_size_ = temporal_window_half_size_ * 2 + 1; + + border_size_ = search_window_half_size_ + template_window_half_size_; + for (int i = 0; i < temporal_window_size_; i++) { + copyMakeBorder( + srcImgs[imgToDenoiseIndex - temporal_window_half_size_ + i], extended_srcs_[i], + border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); + } + main_extended_src_ = extended_srcs_[temporal_window_half_size_]; + + const int max_estimate_sum_value = + temporal_window_size_ * search_window_size_ * search_window_size_ * 255; + + fixed_point_mult_ = numeric_limits::max() / max_estimate_sum_value; + + // precalc weight for every possible l2 dist between blocks + // additional optimization of precalced weights to replace division(averaging) by binary shift + int template_window_size_sq = template_window_size_ * template_window_size_; + almost_template_window_size_sq_bin_shift = 0; + while (1 << almost_template_window_size_sq_bin_shift < template_window_size_sq) { + almost_template_window_size_sq_bin_shift++; + } + + int almost_template_window_size_sq = 1 << almost_template_window_size_sq_bin_shift; + double almost_dist2actual_dist_multiplier = + ((double) almost_template_window_size_sq) / template_window_size_sq; + + int max_dist = 256 * 256 * channels_count_; + int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); + almost_dist2weight.resize(almost_max_dist); + + const double WEIGHT_THRESHOLD = 0.001; + for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { + double dist = almost_dist * almost_dist2actual_dist_multiplier; + int weight = cvRound(fixed_point_mult_ * std::exp(- dist / (h * h * channels_count_))); + + if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) { + weight = 0; + } + + almost_dist2weight[almost_dist] = weight; + } + // additional optimization init end + + if (dst_.empty()) { + dst_ = Mat::zeros(srcImgs[0].size(), srcImgs[0].type()); + } +} + +template +void FastNlMeansMultiDenoisingInvoker::operator() (const BlockedRange& range) const { + int row_from = range.begin(); + int row_to = range.end() - 1; + + int dist_sums_array[temporal_window_size_ * search_window_size_ * search_window_size_]; + Array3d dist_sums(dist_sums_array, + temporal_window_size_, search_window_size_, search_window_size_); + + // for lazy calc optimization + int col_dist_sums_array[ + template_window_size_ * temporal_window_size_ * search_window_size_ * search_window_size_]; + + Array4d col_dist_sums(col_dist_sums_array, + template_window_size_, temporal_window_size_, search_window_size_, search_window_size_); + + int first_col_num = -1; + + Array4d up_col_dist_sums( + cols_, temporal_window_size_, search_window_size_, search_window_size_); + + for (int i = row_from; i <= row_to; i++) { + for (int j = 0; j < cols_; j++) { + int search_window_y = i - search_window_half_size_; + int search_window_x = j - search_window_half_size_; + + // calc dist_sums + if (j == 0) { + calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); + first_col_num = 0; + + } else { // calc cur dist_sums using previous dist_sums + if (i == row_from) { + calcDistSumsForElementInFirstRow(i, j, first_col_num, + dist_sums, col_dist_sums, up_col_dist_sums); + + } else { + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = + border_size_ + i - search_window_half_size_; + + int start_bx = + border_size_ + j - search_window_half_size_ + template_window_half_size_; + + T a_up = main_extended_src_.at(ay - template_window_half_size_ - 1, ax); + T a_down = main_extended_src_.at(ay + template_window_half_size_, ax); + + // copy class member to local variable for optimization + int search_window_size = search_window_size_; + + for (int d = 0; d < temporal_window_size_; d++) { + Mat cur_extended_src = extended_srcs_[d]; + Array2d cur_dist_sums = dist_sums[d]; + Array2d cur_col_dist_sums = col_dist_sums[first_col_num][d]; + Array2d cur_up_col_dist_sums = up_col_dist_sums[j][d]; + for (int y = 0; y < search_window_size; y++) { + int* dist_sums_row = cur_dist_sums.row_ptr(y); + + int* col_dist_sums_row = cur_col_dist_sums.row_ptr(y); + + int* up_col_dist_sums_row = cur_up_col_dist_sums.row_ptr(y); + + const T* b_up_ptr = + cur_extended_src.ptr(start_by - template_window_half_size_ - 1 + y); + const T* b_down_ptr = + cur_extended_src.ptr(start_by + template_window_half_size_ + y); + + for (int x = 0; x < search_window_size; x++) { + dist_sums_row[x] -= col_dist_sums_row[x]; + + col_dist_sums_row[x] = up_col_dist_sums_row[x] + + calcUpDownDist( + a_up, a_down, + b_up_ptr[start_bx + x], b_down_ptr[start_bx + x] + ); + + dist_sums_row[x] += col_dist_sums_row[x]; + + up_col_dist_sums_row[x] = col_dist_sums_row[x]; + + } + } + } + } + + first_col_num = (first_col_num + 1) % template_window_size_; + } + + // calc weights + int weights_sum = 0; + + int estimation[channels_count_]; + for (int channel_num = 0; channel_num < channels_count_; channel_num++) { + estimation[channel_num] = 0; + } + for (int d = 0; d < temporal_window_size_; d++) { + for (int y = 0; y < search_window_size_; y++) { + const T* cur_row_ptr = + extended_srcs_[d].ptr(border_size_ + search_window_y + y); + + int* dist_sums_row = dist_sums.row_ptr(d, y); + + for (int x = 0; x < search_window_size_; x++) { + int almostAvgDist = + dist_sums_row[x] >> almost_template_window_size_sq_bin_shift; + + int weight = almost_dist2weight[almostAvgDist]; + weights_sum += weight; + + T p = cur_row_ptr[border_size_ + search_window_x + x]; + incWithWeight(estimation, weight, p); + } + } + } + + if (weights_sum > 0) { + for (int channel_num = 0; channel_num < channels_count_; channel_num++) { + estimation[channel_num] = + cvRound(((double)estimation[channel_num]) / weights_sum); + } + + dst_.at(i,j) = saturateCastFromArray(estimation); + + } else { // weights_sum == 0 + dst_.at(i,j) = extended_srcs_[temporal_window_half_size_].at(i,j); + } + } + } +} + +template +inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForFirstElementInRow( + int i, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const +{ + int j = 0; + + for (int d = 0; d < temporal_window_size_; d++) { + Mat cur_extended_src = extended_srcs_[d]; + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[d][y][x] = 0; + for (int tx = 0; tx < template_window_size_; tx++) { + col_dist_sums[tx][d][y][x] = 0; + } + + int start_y = i + y - search_window_half_size_; + int start_x = j + x - search_window_half_size_; + + int* dist_sums_ptr = &dist_sums[d][y][x]; + int* col_dist_sums_ptr = &col_dist_sums[0][d][y][x]; + int col_dist_sums_step = col_dist_sums.step_size(0); + for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + int dist = calcDist( + main_extended_src_.at( + border_size_ + i + ty, border_size_ + j + tx), + cur_extended_src.at( + border_size_ + start_y + ty, border_size_ + start_x + tx) + ); + + *dist_sums_ptr += dist; + *col_dist_sums_ptr += dist; + } + col_dist_sums_ptr += col_dist_sums_step; + } + + up_col_dist_sums[j][d][y][x] = col_dist_sums[template_window_size_ - 1][d][y][x]; + } + } + } +} + +template +inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForElementInFirstRow( + int i, + int j, + int first_col_num, + Array3d& dist_sums, + Array4d& col_dist_sums, + Array4d& up_col_dist_sums) const +{ + int ay = border_size_ + i; + int ax = border_size_ + j + template_window_half_size_; + + int start_by = border_size_ + i - search_window_half_size_; + int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_; + + int new_last_col_num = first_col_num; + + for (int d = 0; d < temporal_window_size_; d++) { + Mat cur_extended_src = extended_srcs_[d]; + for (int y = 0; y < search_window_size_; y++) { + for (int x = 0; x < search_window_size_; x++) { + dist_sums[d][y][x] -= col_dist_sums[first_col_num][d][y][x]; + + col_dist_sums[new_last_col_num][d][y][x] = 0; + int by = start_by + y; + int bx = start_bx + x; + + int* col_dist_sums_ptr = &col_dist_sums[new_last_col_num][d][y][x]; + for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { + *col_dist_sums_ptr += + calcDist( + main_extended_src_.at(ay + ty, ax), + cur_extended_src.at(by + ty, bx) + ); + } + + dist_sums[d][y][x] += col_dist_sums[new_last_col_num][d][y][x]; + + up_col_dist_sums[j][d][y][x] = col_dist_sums[new_last_col_num][d][y][x]; + } + } + } +} + +#endif diff --git a/modules/photo/test/test_denoising.cpp b/modules/photo/test/test_denoising.cpp new file mode 100644 index 0000000000..39aa699811 --- /dev/null +++ b/modules/photo/test/test_denoising.cpp @@ -0,0 +1,213 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/photo/denoising.hpp" +#include + +using namespace cv; +using namespace std; + +class CV_DenoisingGrayscaleTest : public cvtest::BaseTest +{ +public: + CV_DenoisingGrayscaleTest(); + ~CV_DenoisingGrayscaleTest(); +protected: + void run(int); +}; + +CV_DenoisingGrayscaleTest::CV_DenoisingGrayscaleTest() {} +CV_DenoisingGrayscaleTest::~CV_DenoisingGrayscaleTest() {} + +void CV_DenoisingGrayscaleTest::run( int ) +{ + string folder = string(ts->get_data_path()) + "denoising/"; + Mat orig = imread(folder + "lena_noised_gaussian_sigma=10.png", 0); + Mat exp = imread(folder + "lena_noised_denoised_grayscale_tw=7_sw=21_h=10.png", 0); + + if (orig.empty() || exp.empty()) + { + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); + return; + } + + Mat res; + fastNlMeansDenoising(orig, res, 7, 21, 10); + + if (norm(res - exp) > 0) { + ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH ); + } else { + ts->set_failed_test_info(cvtest::TS::OK); + } +} + +class CV_DenoisingColoredTest : public cvtest::BaseTest +{ +public: + CV_DenoisingColoredTest(); + ~CV_DenoisingColoredTest(); +protected: + void run(int); +}; + +CV_DenoisingColoredTest::CV_DenoisingColoredTest() {} +CV_DenoisingColoredTest::~CV_DenoisingColoredTest() {} + +void CV_DenoisingColoredTest::run( int ) +{ + string folder = string(ts->get_data_path()) + "denoising/"; + Mat orig = imread(folder + "lena_noised_gaussian_sigma=10.png", 1); + Mat exp = imread(folder + "lena_noised_denoised_lab12_tw=7_sw=21_h=10_h2=10.png", 1); + + if (orig.empty() || exp.empty()) + { + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); + return; + } + + Mat res; + fastNlMeansDenoisingColored(orig, res, 7, 21, 10, 10); + + if (norm(res - exp) > 0) { + ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH ); + } else { + ts->set_failed_test_info(cvtest::TS::OK); + } +} + +class CV_DenoisingGrayscaleMultiTest : public cvtest::BaseTest +{ +public: + CV_DenoisingGrayscaleMultiTest(); + ~CV_DenoisingGrayscaleMultiTest(); +protected: + void run(int); +}; + +CV_DenoisingGrayscaleMultiTest::CV_DenoisingGrayscaleMultiTest() {} +CV_DenoisingGrayscaleMultiTest::~CV_DenoisingGrayscaleMultiTest() {} + +void CV_DenoisingGrayscaleMultiTest::run( int ) +{ + string folder = string(ts->get_data_path()) + "denoising/"; + + const int imgs_count = 3; + vector src_imgs(imgs_count); + src_imgs[0] = imread(folder + "lena_noised_gaussian_sigma=20_multi_0.png", 0); + src_imgs[1] = imread(folder + "lena_noised_gaussian_sigma=20_multi_1.png", 0); + src_imgs[2] = imread(folder + "lena_noised_gaussian_sigma=20_multi_2.png", 0); + + Mat exp = imread(folder + "lena_noised_denoised_multi_tw=7_sw=21_h=15.png", 0); + + bool have_empty_src = false; + for (int i = 0; i < imgs_count; i++) { + have_empty_src |= src_imgs[i].empty(); + } + + if (have_empty_src || exp.empty()) + { + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); + return; + } + + Mat res; + fastNlMeansDenoisingMulti(src_imgs, imgs_count / 2, imgs_count, res, 7, 21, 15); + + if (norm(res - exp) > 0) { + ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH ); + } else { + ts->set_failed_test_info(cvtest::TS::OK); + } +} + +class CV_DenoisingColoredMultiTest : public cvtest::BaseTest +{ +public: + CV_DenoisingColoredMultiTest(); + ~CV_DenoisingColoredMultiTest(); +protected: + void run(int); +}; + +CV_DenoisingColoredMultiTest::CV_DenoisingColoredMultiTest() {} +CV_DenoisingColoredMultiTest::~CV_DenoisingColoredMultiTest() {} + +void CV_DenoisingColoredMultiTest::run( int ) +{ + string folder = string(ts->get_data_path()) + "denoising/"; + + const int imgs_count = 3; + vector src_imgs(imgs_count); + src_imgs[0] = imread(folder + "lena_noised_gaussian_sigma=20_multi_0.png", 1); + src_imgs[1] = imread(folder + "lena_noised_gaussian_sigma=20_multi_1.png", 1); + src_imgs[2] = imread(folder + "lena_noised_gaussian_sigma=20_multi_2.png", 1); + + Mat exp = imread(folder + "lena_noised_denoised_multi_lab12_tw=7_sw=21_h=10_h2=15.png", 1); + + bool have_empty_src = false; + for (int i = 0; i < imgs_count; i++) { + have_empty_src |= src_imgs[i].empty(); + } + + if (have_empty_src || exp.empty()) + { + ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); + return; + } + + Mat res; + fastNlMeansDenoisingColoredMulti(src_imgs, imgs_count / 2, imgs_count, res, 7, 21, 10, 15); + + if (norm(res - exp) > 0) { + ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH ); + } else { + ts->set_failed_test_info(cvtest::TS::OK); + } +} + + +TEST(Imgproc_DenoisingGrayscale, regression) { CV_DenoisingGrayscaleTest test; test.safe_run(); } +TEST(Imgproc_DenoisingColored, regression) { CV_DenoisingColoredTest test; test.safe_run(); } +TEST(Imgproc_DenoisingGrayscaleMulti, regression) { CV_DenoisingGrayscaleMultiTest test; test.safe_run(); } +TEST(Imgproc_DenoisingColoredMulti, regression) { CV_DenoisingColoredMultiTest test; test.safe_run(); } + From 4993748c91ef222cd79b05e2c4d8437581b0caef Mon Sep 17 00:00:00 2001 From: Sergiu Dotenco Date: Sun, 19 Aug 2012 15:25:07 +0200 Subject: [PATCH 019/163] added missing includes --- modules/calib3d/test/test_affine3d_estimator.cpp | 1 + modules/calib3d/test/test_chesscorners.cpp | 1 + modules/gpu/test/precomp.hpp | 1 + 3 files changed, 3 insertions(+) diff --git a/modules/calib3d/test/test_affine3d_estimator.cpp b/modules/calib3d/test/test_affine3d_estimator.cpp index 95742a919a..9eed8e97d7 100644 --- a/modules/calib3d/test/test_affine3d_estimator.cpp +++ b/modules/calib3d/test/test_affine3d_estimator.cpp @@ -48,6 +48,7 @@ using namespace std; #include #include #include +#include #include #include #include diff --git a/modules/calib3d/test/test_chesscorners.cpp b/modules/calib3d/test/test_chesscorners.cpp index f6d513d299..d69212121d 100644 --- a/modules/calib3d/test/test_chesscorners.cpp +++ b/modules/calib3d/test/test_chesscorners.cpp @@ -42,6 +42,7 @@ #include "test_precomp.hpp" #include "test_chessboardgenerator.hpp" +#include #include #include diff --git a/modules/gpu/test/precomp.hpp b/modules/gpu/test/precomp.hpp index afc3be8559..5c1c4c1f49 100644 --- a/modules/gpu/test/precomp.hpp +++ b/modules/gpu/test/precomp.hpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include From ddc7bd76591d42f264b21f1773a786c241eed576 Mon Sep 17 00:00:00 2001 From: Sergiu Dotenco Date: Sun, 19 Aug 2012 15:30:41 +0200 Subject: [PATCH 020/163] fixed compilation errors caused by std::tuple --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cce10bacd..80cf798ee6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -336,6 +336,7 @@ include(cmake/OpenCVCompilerOptions.cmake REQUIRED) # ---------------------------------------------------------------------------- if(MSVC) include(cmake/OpenCVCRTLinkage.cmake REQUIRED) + add_definitions(-D_VARIADIC_MAX=10) endif(MSVC) From 1a621c2916e0793a3380d5121be9470e2dac882b Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Sun, 19 Aug 2012 19:36:43 +0400 Subject: [PATCH 021/163] Fix build warnings --- modules/calib3d/src/triangulate.cpp | 4 +-- modules/gpu/src/graphcuts.cpp | 2 +- modules/gpu/test/test_imgproc.cpp | 2 +- modules/imgproc/perf/perf_warp.cpp | 16 +++++----- modules/ml/src/em.cpp | 2 +- .../test_rotation_and_scale_invariance.cpp | 30 +++++++++---------- modules/objdetect/src/hog.cpp | 2 +- .../opencv2/stitching/detail/seam_finders.hpp | 2 +- modules/stitching/src/seam_finders.cpp | 8 ++--- modules/video/src/bgfg_gmg.cpp | 2 +- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/modules/calib3d/src/triangulate.cpp b/modules/calib3d/src/triangulate.cpp index c86a7834c1..5d6037a05f 100644 --- a/modules/calib3d/src/triangulate.cpp +++ b/modules/calib3d/src/triangulate.cpp @@ -416,10 +416,10 @@ void cv::triangulatePoints( InputArray _projMatr1, InputArray _projMatr2, Mat points1 = _projPoints1.getMat(), points2 = _projPoints2.getMat(); if((points1.rows == 1 || points1.cols == 1) && points1.channels() == 2) - points1 = points1.reshape(1, points1.total()).t(); + points1 = points1.reshape(1, static_cast(points1.total())).t(); if((points2.rows == 1 || points2.cols == 1) && points2.channels() == 2) - points2 = points2.reshape(1, points2.total()).t(); + points2 = points2.reshape(1, static_cast(points2.total())).t(); CvMat cvMatr1 = matr1, cvMatr2 = matr2; CvMat cvPoints1 = points1, cvPoints2 = points2; diff --git a/modules/gpu/src/graphcuts.cpp b/modules/gpu/src/graphcuts.cpp index 58fcde8f09..fc3ac1edf0 100644 --- a/modules/gpu/src/graphcuts.cpp +++ b/modules/gpu/src/graphcuts.cpp @@ -48,7 +48,7 @@ void cv::gpu::graphcut(GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, Gpu void cv::gpu::graphcut(GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, Stream&) { throw_nogpu(); } void cv::gpu::connectivityMask(const GpuMat&, GpuMat&, const cv::Scalar&, const cv::Scalar&, Stream&) { throw_nogpu(); } -void cv::gpu::labelComponents(const GpuMat& mask, GpuMat& components, int, Stream& stream) { throw_nogpu(); } +void cv::gpu::labelComponents(const GpuMat&, GpuMat&, int, Stream&) { throw_nogpu(); } #else /* !defined (HAVE_CUDA) */ diff --git a/modules/gpu/test/test_imgproc.cpp b/modules/gpu/test/test_imgproc.cpp index 4d67de59d3..b3c9dfdfa1 100644 --- a/modules/gpu/test/test_imgproc.cpp +++ b/modules/gpu/test/test_imgproc.cpp @@ -1154,7 +1154,7 @@ TEST_P(HoughLines, Accuracy) const std::string fileName = GET_PARAM(1); const float rho = 1.0f; - const float theta = CV_PI / 180.0f; + const float theta = static_cast(CV_PI / 180); const int threshold = 50; cv::Mat img = readImage(fileName, cv::IMREAD_GRAYSCALE); diff --git a/modules/imgproc/perf/perf_warp.cpp b/modules/imgproc/perf/perf_warp.cpp index 823ff53f18..8f309a21d5 100644 --- a/modules/imgproc/perf/perf_warp.cpp +++ b/modules/imgproc/perf/perf_warp.cpp @@ -125,8 +125,8 @@ void update_map(const Mat& src, Mat& map_x, Mat& map_y, const int remapMode ) case HALF_SIZE: if( i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75 ) { - map_x.at(j,i) = 2*( i - src.cols*0.25 ) + 0.5 ; - map_y.at(j,i) = 2*( j - src.rows*0.25 ) + 0.5 ; + map_x.at(j,i) = 2*( i - src.cols*0.25f ) + 0.5f ; + map_y.at(j,i) = 2*( j - src.rows*0.25f ) + 0.5f ; } else { @@ -135,16 +135,16 @@ void update_map(const Mat& src, Mat& map_x, Mat& map_y, const int remapMode ) } break; case UPSIDE_DOWN: - map_x.at(j,i) = i ; - map_y.at(j,i) = src.rows - j ; + map_x.at(j,i) = static_cast(i) ; + map_y.at(j,i) = static_cast(src.rows - j) ; break; case REFLECTION_X: - map_x.at(j,i) = src.cols - i ; - map_y.at(j,i) = j ; + map_x.at(j,i) = static_cast(src.cols - i) ; + map_y.at(j,i) = static_cast(j) ; break; case REFLECTION_BOTH: - map_x.at(j,i) = src.cols - i ; - map_y.at(j,i) = src.rows - j ; + map_x.at(j,i) = static_cast(src.cols - i) ; + map_y.at(j,i) = static_cast(src.rows - j) ; break; } // end of switch } diff --git a/modules/ml/src/em.cpp b/modules/ml/src/em.cpp index 39b58e0d49..20f365e1de 100644 --- a/modules/ml/src/em.cpp +++ b/modules/ml/src/em.cpp @@ -386,7 +386,7 @@ void EM::computeLogWeightDivDet() for(int clusterIndex = 0; clusterIndex < nclusters; clusterIndex++) { double logDetCov = 0.; - const int evalCount = covsEigenValues[clusterIndex].total(); + const int evalCount = static_cast(covsEigenValues[clusterIndex].total()); for(int di = 0; di < evalCount; di++) logDetCov += std::log(covsEigenValues[clusterIndex].at(covMatType != EM::COV_MAT_SPHERICAL ? di : 0)); diff --git a/modules/nonfree/test/test_rotation_and_scale_invariance.cpp b/modules/nonfree/test/test_rotation_and_scale_invariance.cpp index 9c099f8927..b5cb62bbdc 100644 --- a/modules/nonfree/test/test_rotation_and_scale_invariance.cpp +++ b/modules/nonfree/test/test_rotation_and_scale_invariance.cpp @@ -54,7 +54,7 @@ static Mat generateHomography(float angle) { // angle - rotation around Oz in degrees - float angleRadian = angle * CV_PI / 180.; + float angleRadian = static_cast(angle * CV_PI / 180); Mat H = Mat::eye(3, 3, CV_32FC1); H.at(0,0) = H.at(1,1) = std::cos(angleRadian); H.at(0,1) = -std::sin(angleRadian); @@ -69,8 +69,8 @@ Mat rotateImage(const Mat& srcImage, float angle, Mat& dstImage, Mat& dstMask) // angle - rotation around Oz in degrees float diag = std::sqrt(static_cast(srcImage.cols * srcImage.cols + srcImage.rows * srcImage.rows)); Mat LUShift = Mat::eye(3, 3, CV_32FC1); // left up - LUShift.at(0,2) = -srcImage.cols/2; - LUShift.at(1,2) = -srcImage.rows/2; + LUShift.at(0,2) = static_cast(-srcImage.cols/2); + LUShift.at(1,2) = static_cast(-srcImage.rows/2); Mat RDShift = Mat::eye(3, 3, CV_32FC1); // right down RDShift.at(0,2) = diag/2; RDShift.at(1,2) = diag/2; @@ -114,7 +114,7 @@ void scaleKeyPoints(const vector& src, vector& dst, float sc static float calcCirclesIntersectArea(const Point2f& p0, float r0, const Point2f& p1, float r1) { - float c = norm(p0 - p1), sqr_c = c * c; + float c = static_cast(norm(p0 - p1)), sqr_c = c * c; float sqr_r0 = r0 * r0; float sqr_r1 = r1 * r1; @@ -125,7 +125,7 @@ float calcCirclesIntersectArea(const Point2f& p0, float r0, const Point2f& p1, f float minR = std::min(r0, r1); float maxR = std::max(r0, r1); if(c + minR <= maxR) - return CV_PI * minR * minR; + return static_cast(CV_PI * minR * minR); float cos_halfA0 = (sqr_r0 + sqr_c - sqr_r1) / (2 * r0 * c); float cos_halfA1 = (sqr_r1 + sqr_c - sqr_r0) / (2 * r1 * c); @@ -133,15 +133,15 @@ float calcCirclesIntersectArea(const Point2f& p0, float r0, const Point2f& p1, f float A0 = 2 * acos(cos_halfA0); float A1 = 2 * acos(cos_halfA1); - return 0.5 * sqr_r0 * (A0 - sin(A0)) + - 0.5 * sqr_r1 * (A1 - sin(A1)); + return 0.5f * sqr_r0 * (A0 - sin(A0)) + + 0.5f * sqr_r1 * (A1 - sin(A1)); } static float calcIntersectRatio(const Point2f& p0, float r0, const Point2f& p1, float r1) { float intersectArea = calcCirclesIntersectArea(p0, r0, p1, r1); - float unionArea = CV_PI * (r0 * r0 + r1 * r1) - intersectArea; + float unionArea = static_cast(CV_PI) * (r0 * r0 + r1 * r1) - intersectArea; return intersectArea / unionArea; } @@ -160,7 +160,7 @@ void matchKeyPoints(const vector& keypoints0, const Mat& H, matches.clear(); vector usedMask(keypoints1.size(), 0); - for(size_t i0 = 0; i0 < keypoints0.size(); i0++) + for(int i0 = 0; i0 < static_cast(keypoints0.size()); i0++) { int nearestPointIndex = -1; float maxIntersectRatio = 0.f; @@ -176,7 +176,7 @@ void matchKeyPoints(const vector& keypoints0, const Mat& H, if(intersectRatio > maxIntersectRatio) { maxIntersectRatio = intersectRatio; - nearestPointIndex = i1; + nearestPointIndex = static_cast(i1); } } @@ -222,7 +222,7 @@ protected: const int maxAngle = 360, angleStep = 15; for(int angle = 0; angle < maxAngle; angle += angleStep) { - Mat H = rotateImage(image0, angle, image1, mask1); + Mat H = rotateImage(image0, static_cast(angle), image1, mask1); vector keypoints1; featureDetector->detect(image1, keypoints1, mask1); @@ -339,10 +339,10 @@ protected: const int maxAngle = 360, angleStep = 15; for(int angle = 0; angle < maxAngle; angle += angleStep) { - Mat H = rotateImage(image0, angle, image1, mask1); + Mat H = rotateImage(image0, static_cast(angle), image1, mask1); vector keypoints1; - rotateKeyPoints(keypoints0, H, angle, keypoints1); + rotateKeyPoints(keypoints0, H, static_cast(angle), keypoints1); Mat descriptors1; descriptorExtractor->compute(image1, keypoints1, descriptors1); @@ -457,7 +457,7 @@ protected: keyPointMatchesCount++; // Check does this inlier have consistent sizes - const float maxSizeDiff = 0.8;//0.9f; // grad + const float maxSizeDiff = 0.8f;//0.9f; // grad float size0 = keypoints0[matches[m].trainIdx].size; float size1 = osiKeypoints1[matches[m].queryIdx].size; CV_Assert(size0 > 0 && size1 > 0); @@ -545,7 +545,7 @@ protected: resize(image0, image1, Size(), 1./scale, 1./scale); vector keypoints1; - scaleKeyPoints(keypoints0, keypoints1, 1./scale); + scaleKeyPoints(keypoints0, keypoints1, 1.0f/scale); Mat descriptors1; descriptorExtractor->compute(image1, keypoints1, descriptors1); diff --git a/modules/objdetect/src/hog.cpp b/modules/objdetect/src/hog.cpp index 485334cc36..19decfb536 100644 --- a/modules/objdetect/src/hog.cpp +++ b/modules/objdetect/src/hog.cpp @@ -2563,7 +2563,7 @@ void HOGDescriptor::readALTModel(std::string modelfile) throw Exception(); } int kernel_type; - int nread; + size_t nread; nread=fread(&(kernel_type),sizeof(int),1,modelfl); {// ignore these diff --git a/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp b/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp index c700a169c0..fc1fcc7b75 100644 --- a/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp @@ -120,7 +120,7 @@ private: ImagePairLess(const std::vector &images, const std::vector &corners) : src_(&images[0]), corners_(&corners[0]) {} - bool operator() (const std::pair &l, const std::pair &r) const + bool operator() (const std::pair &l, const std::pair &r) const { Point c1 = corners_[l.first] + Point(src_[l.first].cols / 2, src_[l.first].rows / 2); Point c2 = corners_[l.second] + Point(src_[l.second].cols / 2, src_[l.second].rows / 2); diff --git a/modules/stitching/src/seam_finders.cpp b/modules/stitching/src/seam_finders.cpp index 723a087034..3e10398ee7 100644 --- a/modules/stitching/src/seam_finders.cpp +++ b/modules/stitching/src/seam_finders.cpp @@ -166,7 +166,7 @@ void DpSeamFinder::find(const vector &src, const vector &corners, ve if (src.size() == 0) return; - vector > pairs; + vector > pairs; for (size_t i = 0; i+1 < src.size(); ++i) for (size_t j = i+1; j < src.size(); ++j) @@ -177,7 +177,7 @@ void DpSeamFinder::find(const vector &src, const vector &corners, ve for (size_t i = 0; i < pairs.size(); ++i) { - int i0 = pairs[i].first, i1 = pairs[i].second; + size_t i0 = pairs[i].first, i1 = pairs[i].second; process(src[i0], src[i1], corners[i0], corners[i1], masks[i0], masks[i1]); } @@ -393,7 +393,7 @@ void DpSeamFinder::resolveConflicts( bool hasConflict = true; while (hasConflict) { - int c1, c2; + int c1 = 0, c2 = 0; hasConflict = false; for (set >::iterator itr = edges_.begin(); itr != edges_.end(); ++itr) @@ -635,7 +635,7 @@ bool DpSeamFinder::getSeamTips(int comp1, int comp2, Point &p1, Point &p2) double cx = cvRound(sum[idx[i]].x / size); double cy = cvRound(sum[idx[i]].y / size); - int closest = -1; + size_t closest = points[idx[i]].size(); double minDist = numeric_limits::max(); for (size_t j = 0; j < points[idx[i]].size(); ++j) diff --git a/modules/video/src/bgfg_gmg.cpp b/modules/video/src/bgfg_gmg.cpp index f2e52b5930..056da3826e 100644 --- a/modules/video/src/bgfg_gmg.cpp +++ b/modules/video/src/bgfg_gmg.cpp @@ -290,7 +290,7 @@ namespace normalizeHistogram(weights, nfeatures); } - fgmask_row[x] = (uchar)(-isForeground); + fgmask_row[x] = (uchar)(-(schar)isForeground); } } } From c9f2ff44876349a3164025b0919d51378e3002ff Mon Sep 17 00:00:00 2001 From: Alexander Mordvintesv Date: Sun, 19 Aug 2012 20:36:50 +0300 Subject: [PATCH 022/163] added texture_flow.py sample --- samples/python2/data/starry_night.jpg | Bin 0 -> 302901 bytes samples/python2/texture_flow.py | 36 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 samples/python2/data/starry_night.jpg create mode 100644 samples/python2/texture_flow.py diff --git a/samples/python2/data/starry_night.jpg b/samples/python2/data/starry_night.jpg new file mode 100644 index 0000000000000000000000000000000000000000..824e0e5a27f100926314a9efaa11a518e2877fb1 GIT binary patch literal 302901 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%0DgdZs%fm#?^cFZhrlu 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 LKJovo{ag7j`lc5- literal 0 HcmV?d00001 diff --git a/samples/python2/texture_flow.py b/samples/python2/texture_flow.py new file mode 100644 index 0000000000..7de5dff6e2 --- /dev/null +++ b/samples/python2/texture_flow.py @@ -0,0 +1,36 @@ +''' +Texture flow direction estimation. + +Sample shows how cv2.cornerEigenValsAndVecs function can be used +to estimate image texture flow direction. + +Usage: + texture_flow.py [] +''' + +import numpy as np +import cv2 + +if __name__ == '__main__': + import sys + try: fn = sys.argv[1] + except: fn = 'data/starry_night.jpg' + + img = cv2.imread(fn) + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + h, w = img.shape[:2] + + eigen = cv2.cornerEigenValsAndVecs(gray, 15, 3) + eigen = eigen.reshape(h, w, 3, 2) # [[e1, e2], v1, v2] + flow = eigen[:,:,2] + + vis = img.copy() + vis[:] = (192 + np.uint32(vis)) / 2 + d = 12 + points = np.dstack( np.mgrid[d/2:w:d, d/2:h:d] ).reshape(-1, 2) + for x, y in points: + vx, vy = np.int32(flow[y, x]*d) + cv2.line(vis, (x-vx, y-vy), (x+vx, y+vy), (0, 0, 0), 1, cv2.CV_AA) + cv2.imshow('input', img) + cv2.imshow('flow', vis) + cv2.waitKey() From 66eb96d719309ed8f3252ef0ea27632005d65ec6 Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Sun, 19 Aug 2012 22:43:27 +0400 Subject: [PATCH 023/163] minor warning fix --- modules/core/src/cuda/matrix_operations.cu | 13 +++++++++++-- modules/core/src/gpumat.cpp | 4 ---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/modules/core/src/cuda/matrix_operations.cu b/modules/core/src/cuda/matrix_operations.cu index 6bf1549dd5..671fa5fc31 100644 --- a/modules/core/src/cuda/matrix_operations.cu +++ b/modules/core/src/cuda/matrix_operations.cu @@ -44,7 +44,7 @@ #include "opencv2/gpu/device/transform.hpp" #include "opencv2/gpu/device/functional.hpp" -namespace cv { namespace gpu { namespace device +namespace cv { namespace gpu { namespace device { template struct shift_and_sizeof; template <> struct shift_and_sizeof { enum { shift = 0 }; }; @@ -272,7 +272,7 @@ namespace cv { namespace gpu { namespace device template struct TransformFunctorTraits< Convertor > : detail::ConvertTraits< Convertor > { }; - + template void cvt_(DevMem2Db src, DevMem2Db dst, double alpha, double beta, cudaStream_t stream) { @@ -282,6 +282,11 @@ namespace cv { namespace gpu { namespace device cv::gpu::device::transform((DevMem2D_)src, (DevMem2D_)dst, op, WithOutMask(), stream); } +#if defined __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wmissing-declarations" +#endif + void convert_gpu(DevMem2Db src, int sdepth, DevMem2Db dst, int ddepth, double alpha, double beta, cudaStream_t stream) { typedef void (*caller_t)(DevMem2Db src, DevMem2Db dst, double alpha, double beta, cudaStream_t stream); @@ -318,4 +323,8 @@ namespace cv { namespace gpu { namespace device func(src, dst, alpha, beta, stream); } + +#if defined __clang__ +# pragma clang diagnostic pop +#endif }}} // namespace cv { namespace gpu { namespace device diff --git a/modules/core/src/gpumat.cpp b/modules/core/src/gpumat.cpp index c901bf4925..105a5ff15f 100644 --- a/modules/core/src/gpumat.cpp +++ b/modules/core/src/gpumat.cpp @@ -1199,10 +1199,6 @@ namespace void setTo(GpuMat& m, Scalar s, const GpuMat& mask) const { - NppiSize sz; - sz.width = m.cols; - sz.height = m.rows; - if (mask.empty()) { if (s[0] == 0.0 && s[1] == 0.0 && s[2] == 0.0 && s[3] == 0.0) From 9c13b84e35b8108dd958416451e404eeccb9a37b Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Mon, 20 Aug 2012 00:06:12 +0400 Subject: [PATCH 024/163] fixed unused warnings --- modules/gpu/perf/perf_core.cpp | 3 ++ modules/gpu/perf_cpu/perf_core.cpp | 3 ++ modules/gpu/src/calib3d.cpp | 21 ++++----- modules/gpu/src/cascadeclassifier.cpp | 8 ++-- modules/gpu/src/match_template.cpp | 65 ++++++++++++++------------- modules/gpu/src/split_merge.cpp | 1 - modules/gpu/test/test_objdetect.cpp | 21 ++++----- 7 files changed, 65 insertions(+), 57 deletions(-) diff --git a/modules/gpu/perf/perf_core.cpp b/modules/gpu/perf/perf_core.cpp index f413432041..588bae59d8 100644 --- a/modules/gpu/perf/perf_core.cpp +++ b/modules/gpu/perf/perf_core.cpp @@ -1607,6 +1607,7 @@ GPU_PERF_TEST(Norm, cv::gpu::DeviceInfo, cv::Size, MatDepth, NormType) { dst = cv::gpu::norm(src, normType, buf); } + (void)dst; } INSTANTIATE_TEST_CASE_P(Core, Norm, testing::Combine( @@ -1642,6 +1643,7 @@ GPU_PERF_TEST(NormDiff, cv::gpu::DeviceInfo, cv::Size, NormType) { dst = cv::gpu::norm(src1, src2, normType); } + (void)dst; } INSTANTIATE_TEST_CASE_P(Core, NormDiff, testing::Combine( @@ -1829,6 +1831,7 @@ GPU_PERF_TEST(CountNonZero, cv::gpu::DeviceInfo, cv::Size, MatDepth) { dst = cv::gpu::countNonZero(src, buf); } + (void)dst; } INSTANTIATE_TEST_CASE_P(Core, CountNonZero, testing::Combine( diff --git a/modules/gpu/perf_cpu/perf_core.cpp b/modules/gpu/perf_cpu/perf_core.cpp index fb87009584..24e19a8abe 100644 --- a/modules/gpu/perf_cpu/perf_core.cpp +++ b/modules/gpu/perf_cpu/perf_core.cpp @@ -1229,6 +1229,7 @@ GPU_PERF_TEST(Norm, cv::gpu::DeviceInfo, cv::Size, MatDepth, NormType) { dst = cv::norm(src, normType); } + (void)dst; } INSTANTIATE_TEST_CASE_P(Core, Norm, testing::Combine( @@ -1259,6 +1260,7 @@ GPU_PERF_TEST(NormDiff, cv::gpu::DeviceInfo, cv::Size, NormType) { dst = cv::norm(src1, src2, normType); } + (void)dst; } INSTANTIATE_TEST_CASE_P(Core, NormDiff, testing::Combine( @@ -1338,6 +1340,7 @@ GPU_PERF_TEST(CountNonZero, cv::gpu::DeviceInfo, cv::Size, MatDepth) { dst = cv::countNonZero(src); } + (void)dst; } INSTANTIATE_TEST_CASE_P(Core, CountNonZero, testing::Combine( diff --git a/modules/gpu/src/calib3d.cpp b/modules/gpu/src/calib3d.cpp index bc522f372c..8897996269 100644 --- a/modules/gpu/src/calib3d.cpp +++ b/modules/gpu/src/calib3d.cpp @@ -56,14 +56,14 @@ void cv::gpu::solvePnPRansac(const Mat&, const Mat&, const Mat&, const Mat&, Mat #else -namespace cv { namespace gpu { namespace device +namespace cv { namespace gpu { namespace device { - namespace transform_points + namespace transform_points { void call(const DevMem2D_ src, const float* rot, const float* transl, DevMem2D_ dst, cudaStream_t stream); } - namespace project_points + namespace project_points { void call(const DevMem2D_ src, const float* rot, const float* transl, const float* proj, DevMem2D_ dst, cudaStream_t stream); } @@ -154,11 +154,11 @@ namespace class TransformHypothesesGenerator { public: - TransformHypothesesGenerator(const Mat& object_, const Mat& image_, const Mat& dist_coef_, - const Mat& camera_mat_, int num_points_, int subset_size_, + TransformHypothesesGenerator(const Mat& object_, const Mat& image_, const Mat& dist_coef_, + const Mat& camera_mat_, int num_points_, int subset_size_, Mat rot_matrices_, Mat transl_vectors_) - : object(&object_), image(&image_), dist_coef(&dist_coef_), camera_mat(&camera_mat_), - num_points(num_points_), subset_size(subset_size_), rot_matrices(rot_matrices_), + : object(&object_), image(&image_), dist_coef(&dist_coef_), camera_mat(&camera_mat_), + num_points(num_points_), subset_size(subset_size_), rot_matrices(rot_matrices_), transl_vectors(transl_vectors_) {} void operator()(const BlockedRange& range) const @@ -211,9 +211,10 @@ namespace void cv::gpu::solvePnPRansac(const Mat& object, const Mat& image, const Mat& camera_mat, const Mat& dist_coef, Mat& rvec, Mat& tvec, bool use_extrinsic_guess, - int num_iters, float max_dist, int min_inlier_count, + int num_iters, float max_dist, int min_inlier_count, vector* inliers) { + (void)min_inlier_count; CV_Assert(object.rows == 1 && object.cols > 0 && object.type() == CV_32FC3); CV_Assert(image.rows == 1 && image.cols > 0 && image.type() == CV_32FC2); CV_Assert(object.cols == image.cols); @@ -236,7 +237,7 @@ void cv::gpu::solvePnPRansac(const Mat& object, const Mat& image, const Mat& cam Mat transl_vectors(1, num_iters * 3, CV_32F); // Generate set of hypotheses using small subsets of the input data - TransformHypothesesGenerator body(object, image_normalized, empty_dist_coef, eye_camera_mat, + TransformHypothesesGenerator body(object, image_normalized, empty_dist_coef, eye_camera_mat, num_points, subset_size, rot_matrices, transl_vectors); parallel_for(BlockedRange(0, num_iters), body); @@ -246,7 +247,7 @@ void cv::gpu::solvePnPRansac(const Mat& object, const Mat& image, const Mat& cam GpuMat d_hypothesis_scores(1, num_iters, CV_32S); solve_pnp_ransac::computeHypothesisScores( num_iters, num_points, rot_matrices.ptr(), transl_vectors.ptr(), - d_object.ptr(), d_image_normalized.ptr(), max_dist * max_dist, + d_object.ptr(), d_image_normalized.ptr(), max_dist * max_dist, d_hypothesis_scores.ptr()); // Find the best hypothesis index diff --git a/modules/gpu/src/cascadeclassifier.cpp b/modules/gpu/src/cascadeclassifier.cpp index 1f277f0cf7..570cb7a806 100644 --- a/modules/gpu/src/cascadeclassifier.cpp +++ b/modules/gpu/src/cascadeclassifier.cpp @@ -143,7 +143,7 @@ public: } unsigned int process(const GpuMat& image, GpuMat& objectsBuf, float scaleFactor, int minNeighbors, - bool findLargestObject, bool visualizeInPlace, cv::Size minSize, cv::Size maxObjectSize) + bool findLargestObject, bool visualizeInPlace, cv::Size minSize, cv::Size /*maxObjectSize*/) { CV_Assert( scaleFactor > 1 && image.depth() == CV_8U); @@ -380,12 +380,12 @@ public: LbpCascade(){} virtual ~LbpCascade(){} - virtual unsigned int process(const GpuMat& image, GpuMat& objects, float scaleFactor, int groupThreshold, bool findLargestObject, - bool visualizeInPlace, cv::Size minObjectSize, cv::Size maxObjectSize) + virtual unsigned int process(const GpuMat& image, GpuMat& objects, float scaleFactor, int groupThreshold, bool /*findLargestObject*/, + bool /*visualizeInPlace*/, cv::Size minObjectSize, cv::Size maxObjectSize) { CV_Assert(scaleFactor > 1 && image.depth() == CV_8U); - const int defaultObjSearchNum = 100; + // const int defaultObjSearchNum = 100; const float grouping_eps = 0.2f; if( !objects.empty() && objects.depth() == CV_32S) diff --git a/modules/gpu/src/match_template.cpp b/modules/gpu/src/match_template.cpp index c4a8180682..c988000a57 100644 --- a/modules/gpu/src/match_template.cpp +++ b/modules/gpu/src/match_template.cpp @@ -52,9 +52,9 @@ void cv::gpu::matchTemplate(const GpuMat&, const GpuMat&, GpuMat&, int, Stream&) #else -namespace cv { namespace gpu { namespace device +namespace cv { namespace gpu { namespace device { - namespace match_template + namespace match_template { void matchTemplateNaive_CCORR_8U(const DevMem2Db image, const DevMem2Db templ, DevMem2Df result, int cn, cudaStream_t stream); void matchTemplateNaive_CCORR_32F(const DevMem2Db image, const DevMem2Db templ, DevMem2Df result, int cn, cudaStream_t stream); @@ -71,47 +71,47 @@ namespace cv { namespace gpu { namespace device void matchTemplatePrepared_CCOFF_8U(int w, int h, const DevMem2D_ image_sum, unsigned int templ_sum, DevMem2Df result, cudaStream_t stream); void matchTemplatePrepared_CCOFF_8UC2( int w, int h, - const DevMem2D_ image_sum_r, - const DevMem2D_ image_sum_g, + const DevMem2D_ image_sum_r, + const DevMem2D_ image_sum_g, unsigned int templ_sum_r, - unsigned int templ_sum_g, + unsigned int templ_sum_g, DevMem2Df result, cudaStream_t stream); void matchTemplatePrepared_CCOFF_8UC3( - int w, int h, - const DevMem2D_ image_sum_r, + int w, int h, + const DevMem2D_ image_sum_r, const DevMem2D_ image_sum_g, const DevMem2D_ image_sum_b, - unsigned int templ_sum_r, - unsigned int templ_sum_g, - unsigned int templ_sum_b, + unsigned int templ_sum_r, + unsigned int templ_sum_g, + unsigned int templ_sum_b, DevMem2Df result, cudaStream_t stream); void matchTemplatePrepared_CCOFF_8UC4( - int w, int h, - const DevMem2D_ image_sum_r, + int w, int h, + const DevMem2D_ image_sum_r, const DevMem2D_ image_sum_g, const DevMem2D_ image_sum_b, const DevMem2D_ image_sum_a, - unsigned int templ_sum_r, - unsigned int templ_sum_g, - unsigned int templ_sum_b, - unsigned int templ_sum_a, + unsigned int templ_sum_r, + unsigned int templ_sum_g, + unsigned int templ_sum_b, + unsigned int templ_sum_a, DevMem2Df result, cudaStream_t stream); void matchTemplatePrepared_CCOFF_NORMED_8U( - int w, int h, const DevMem2D_ image_sum, + int w, int h, const DevMem2D_ image_sum, const DevMem2D_ image_sqsum, unsigned int templ_sum, unsigned long long templ_sqsum, DevMem2Df result, cudaStream_t stream); void matchTemplatePrepared_CCOFF_NORMED_8UC2( - int w, int h, + int w, int h, const DevMem2D_ image_sum_r, const DevMem2D_ image_sqsum_r, const DevMem2D_ image_sum_g, const DevMem2D_ image_sqsum_g, unsigned int templ_sum_r, unsigned long long templ_sqsum_r, unsigned int templ_sum_g, unsigned long long templ_sqsum_g, DevMem2Df result, cudaStream_t stream); void matchTemplatePrepared_CCOFF_NORMED_8UC3( - int w, int h, + int w, int h, const DevMem2D_ image_sum_r, const DevMem2D_ image_sqsum_r, const DevMem2D_ image_sum_g, const DevMem2D_ image_sqsum_g, const DevMem2D_ image_sum_b, const DevMem2D_ image_sqsum_b, @@ -120,7 +120,7 @@ namespace cv { namespace gpu { namespace device unsigned int templ_sum_b, unsigned long long templ_sqsum_b, DevMem2Df result, cudaStream_t stream); void matchTemplatePrepared_CCOFF_NORMED_8UC4( - int w, int h, + int w, int h, const DevMem2D_ image_sum_r, const DevMem2D_ image_sqsum_r, const DevMem2D_ image_sum_g, const DevMem2D_ image_sqsum_g, const DevMem2D_ image_sum_b, const DevMem2D_ image_sqsum_b, @@ -131,7 +131,7 @@ namespace cv { namespace gpu { namespace device unsigned int templ_sum_a, unsigned long long templ_sqsum_a, DevMem2Df result, cudaStream_t stream); - void normalize_8U(int w, int h, const DevMem2D_ image_sqsum, + void normalize_8U(int w, int h, const DevMem2D_ image_sqsum, unsigned long long templ_sqsum, DevMem2Df result, int cn, cudaStream_t stream); void extractFirstChannel_32F(const DevMem2Db image, DevMem2Df result, int cn, cudaStream_t stream); @@ -140,17 +140,17 @@ namespace cv { namespace gpu { namespace device using namespace ::cv::gpu::device::match_template; -namespace +namespace { - // Evaluates optimal template's area threshold. If - // template's area is less than the threshold, we use naive match + // Evaluates optimal template's area threshold. If + // template's area is less than the threshold, we use naive match // template version, otherwise FFT-based (if available) int getTemplateThreshold(int method, int depth) { switch (method) { - case CV_TM_CCORR: + case CV_TM_CCORR: if (depth == CV_32F) return 250; if (depth == CV_8U) return 300; break; @@ -162,10 +162,10 @@ namespace return 0; } - + void matchTemplate_CCORR_32F( const GpuMat& image, const GpuMat& templ, GpuMat& result, MatchTemplateBuf &buf, Stream& stream) - { + { result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F); if (templ.size().area() < getTemplateThreshold(CV_TM_CCORR, CV_32F)) { @@ -223,10 +223,11 @@ namespace normalize_8U(templ.cols, templ.rows, buf.image_sqsums[0], templ_sqsum, result, image.channels(), StreamAccessor::getStream(stream)); } - + void matchTemplate_SQDIFF_32F( const GpuMat& image, const GpuMat& templ, GpuMat& result, MatchTemplateBuf &buf, Stream& stream) { + (void)buf; result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F); matchTemplateNaive_SQDIFF_32F(image, templ, result, image.channels(), StreamAccessor::getStream(stream)); } @@ -362,7 +363,7 @@ namespace { case 2: matchTemplatePrepared_CCOFF_NORMED_8UC2( - templ.cols, templ.rows, + templ.cols, templ.rows, buf.image_sums[0], buf.image_sqsums[0], buf.image_sums[1], buf.image_sqsums[1], (unsigned int)templ_sum[0], (unsigned long long)templ_sqsum[0], @@ -371,7 +372,7 @@ namespace break; case 3: matchTemplatePrepared_CCOFF_NORMED_8UC3( - templ.cols, templ.rows, + templ.cols, templ.rows, buf.image_sums[0], buf.image_sqsums[0], buf.image_sums[1], buf.image_sqsums[1], buf.image_sums[2], buf.image_sqsums[2], @@ -382,7 +383,7 @@ namespace break; case 4: matchTemplatePrepared_CCOFF_NORMED_8UC4( - templ.cols, templ.rows, + templ.cols, templ.rows, buf.image_sums[0], buf.image_sqsums[0], buf.image_sums[1], buf.image_sqsums[1], buf.image_sums[2], buf.image_sqsums[2], @@ -391,7 +392,7 @@ namespace (unsigned int)templ_sum[1], (unsigned long long)templ_sqsum[1], (unsigned int)templ_sum[2], (unsigned long long)templ_sqsum[2], (unsigned int)templ_sum[3], (unsigned long long)templ_sqsum[3], - result, StreamAccessor::getStream(stream)); + result, StreamAccessor::getStream(stream)); break; default: CV_Error(CV_StsBadArg, "matchTemplate: unsupported number of channels"); diff --git a/modules/gpu/src/split_merge.cpp b/modules/gpu/src/split_merge.cpp index 2d5b1b13c1..3153c5f339 100644 --- a/modules/gpu/src/split_merge.cpp +++ b/modules/gpu/src/split_merge.cpp @@ -119,7 +119,6 @@ namespace int depth = src.depth(); int num_channels = src.channels(); - Size size = src.size(); if (depth == CV_64F) { diff --git a/modules/gpu/test/test_objdetect.cpp b/modules/gpu/test/test_objdetect.cpp index 927762b2b0..f867533c80 100644 --- a/modules/gpu/test/test_objdetect.cpp +++ b/modules/gpu/test/test_objdetect.cpp @@ -302,13 +302,13 @@ PARAM_TEST_CASE(LBP_Read_classifier, cv::gpu::DeviceInfo, int) TEST_P(LBP_Read_classifier, Accuracy) { - cv::gpu::CascadeClassifier_GPU classifier; + cv::gpu::CascadeClassifier_GPU classifier; std::string classifierXmlPath = std::string(cvtest::TS::ptr()->get_data_path()) + "lbpcascade/lbpcascade_frontalface.xml"; ASSERT_TRUE(classifier.load(classifierXmlPath)); } -INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, LBP_Read_classifier, - testing::Combine(ALL_DEVICES, testing::Values(0))); +INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, LBP_Read_classifier, + testing::Combine(ALL_DEVICES, testing::Values(0))); PARAM_TEST_CASE(LBP_classify, cv::gpu::DeviceInfo, int) @@ -344,31 +344,32 @@ TEST_P(LBP_classify, Accuracy) for (; it != rects.end(); ++it) cv::rectangle(markedImage, *it, CV_RGB(0, 0, 255)); - cv::gpu::CascadeClassifier_GPU gpuClassifier; + cv::gpu::CascadeClassifier_GPU gpuClassifier; ASSERT_TRUE(gpuClassifier.load(classifierXmlPath)); cv::gpu::GpuMat gpu_rects; cv::gpu::GpuMat tested(grey); int count = gpuClassifier.detectMultiScale(tested, gpu_rects); +#if defined (LOG_CASCADE_STATISTIC) cv::Mat downloaded(gpu_rects); - const cv::Rect* faces = downloaded.ptr(); + const cv::Rect* faces = downloaded.ptr(); for (int i = 0; i < count; i++) { cv::Rect r = faces[i]; -#if defined (LOG_CASCADE_STATISTIC) - std::cout << r.x << " " << r.y << " " << r.width << " " << r.height << std::endl; + std::cout << r.x << " " << r.y << " " << r.width << " " << r.height << std::endl; cv::rectangle(markedImage, r , CV_RGB(255, 0, 0)); -#endif } +#endif #if defined (LOG_CASCADE_STATISTIC) - cv::imshow("Res", markedImage); cv::waitKey(); + cv::imshow("Res", markedImage); cv::waitKey(); #endif + (void)count; } INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, LBP_classify, - testing::Combine(ALL_DEVICES, testing::Values(0))); + testing::Combine(ALL_DEVICES, testing::Values(0))); } // namespace From aeaf1a6f6d724552f3b7dd4c5dbcd1d0652a6e78 Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Mon, 20 Aug 2012 02:26:23 +0400 Subject: [PATCH 025/163] refactoring in Emulation --- modules/gpu/src/cuda/ccomponetns.cu | 4 ++-- modules/gpu/src/cuda/lbp.cu | 2 +- modules/gpu/src/opencv2/gpu/device/emulation.hpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/gpu/src/cuda/ccomponetns.cu b/modules/gpu/src/cuda/ccomponetns.cu index 275066a2ab..07f2410caa 100644 --- a/modules/gpu/src/cuda/ccomponetns.cu +++ b/modules/gpu/src/cuda/ccomponetns.cu @@ -316,7 +316,7 @@ namespace cv { namespace gpu { namespace device } } - changed = Emulation::sycthOr(changed); + changed = Emulation::syncthreadsOr(changed); if (!changed) break; @@ -474,7 +474,7 @@ namespace cv { namespace gpu { namespace device } } } - } while (Emulation::sycthOr(changed)); + } while (Emulation::syncthreadsOr(changed)); } __global__ void flatten(const DevMem2D edges, DevMem2Di comps) diff --git a/modules/gpu/src/cuda/lbp.cu b/modules/gpu/src/cuda/lbp.cu index e96692cefb..edfbf6ea59 100644 --- a/modules/gpu/src/cuda/lbp.cu +++ b/modules/gpu/src/cuda/lbp.cu @@ -279,7 +279,7 @@ namespace cv { namespace gpu { namespace device rect.z = __float2int_rn(windowW * scale); rect.w = __float2int_rn(windowH * scale); - int res = Emulation::smem::atomicInc(classified, (unsigned int)objects.cols); + int res = atomicInc(classified, (unsigned int)objects.cols); objects(0, res) = rect; } } diff --git a/modules/gpu/src/opencv2/gpu/device/emulation.hpp b/modules/gpu/src/opencv2/gpu/device/emulation.hpp index 1a6f5794cf..074e911275 100644 --- a/modules/gpu/src/opencv2/gpu/device/emulation.hpp +++ b/modules/gpu/src/opencv2/gpu/device/emulation.hpp @@ -51,11 +51,11 @@ namespace cv { namespace gpu { namespace device struct Emulation { - static __device__ __forceinline__ int sycthOr(int pred) + static __device__ __forceinline__ int syncthreadsOr(int pred) { #if defined (__CUDA_ARCH__) && (__CUDA_ARCH__ < 200) // just campilation stab - return false; + return 0; #else return __syncthreads_or(pred); #endif From ede3781e3efdcf7e5333638c0808ea80190aa4dd Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Mon, 20 Aug 2012 02:27:54 +0400 Subject: [PATCH 026/163] fixed -Wstrict_alliasing warning for GCC --- modules/gpu/src/imgproc.cpp | 8 ++++- .../gpu/src/nvidia/NCVHaarObjectDetection.hpp | 32 ++++++++++++------- .../gpu/src/nvidia/NPP_staging/NPP_staging.cu | 18 +++++++---- .../nvidia/TestHaarCascadeApplication.cpp | 6 ++-- modules/gpu/test/nvidia/main_nvidia.cpp | 4 ++- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/modules/gpu/src/imgproc.cpp b/modules/gpu/src/imgproc.cpp index 31ab44cb8d..fe1ad7bd89 100644 --- a/modules/gpu/src/imgproc.cpp +++ b/modules/gpu/src/imgproc.cpp @@ -261,6 +261,12 @@ namespace } } +#if defined __GNUC__ && __GNUC__ > 2 && __GNUC_MINOR__ > 4 +typedef Npp32s __attribute__((__may_alias__)) Npp32s_a; +#else +typedef Npp32s Npp32s_a; +#endif + void cv::gpu::copyMakeBorder(const GpuMat& src, GpuMat& dst, int top, int bottom, int left, int right, int borderType, const Scalar& value, Stream& s) { CV_Assert(src.depth() <= CV_32F && src.channels() <= 4); @@ -308,7 +314,7 @@ void cv::gpu::copyMakeBorder(const GpuMat& src, GpuMat& dst, int top, int bottom case CV_32FC1: { Npp32f val = saturate_cast(value[0]); - Npp32s nVal = *(reinterpret_cast(&val)); + Npp32s nVal = *(reinterpret_cast(&val)); nppSafeCall( nppiCopyConstBorder_32s_C1R(src.ptr(), static_cast(src.step), srcsz, dst.ptr(), static_cast(dst.step), dstsz, top, left, nVal) ); break; diff --git a/modules/gpu/src/nvidia/NCVHaarObjectDetection.hpp b/modules/gpu/src/nvidia/NCVHaarObjectDetection.hpp index 79872cbfa4..fd0e53e904 100644 --- a/modules/gpu/src/nvidia/NCVHaarObjectDetection.hpp +++ b/modules/gpu/src/nvidia/NCVHaarObjectDetection.hpp @@ -67,7 +67,11 @@ // Guaranteed size cross-platform classifier structures // //============================================================================== - +#if defined __GNUC__ && __GNUC__ > 2 && __GNUC_MINOR__ > 4 +typedef Ncv32f __attribute__((__may_alias__)) Ncv32f_a; +#else +typedef Ncv32f Ncv32f_a; +#endif struct HaarFeature64 { @@ -87,7 +91,7 @@ struct HaarFeature64 __host__ NCVStatus setWeight(Ncv32f weight) { - ((Ncv32f*)&(this->_ui2.y))[0] = weight; + ((Ncv32f_a*)&(this->_ui2.y))[0] = weight; return NCV_SUCCESS; } @@ -102,7 +106,7 @@ struct HaarFeature64 __device__ __host__ Ncv32f getWeight(void) { - return *(Ncv32f*)(&this->_ui2.y); + return *(Ncv32f_a*)(&this->_ui2.y); } }; @@ -168,14 +172,13 @@ public: } }; - struct HaarClassifierNodeDescriptor32 { uint1 _ui1; __host__ NCVStatus create(Ncv32f leafValue) { - *(Ncv32f *)&this->_ui1 = leafValue; + *(Ncv32f_a *)&this->_ui1 = leafValue; return NCV_SUCCESS; } @@ -187,7 +190,7 @@ struct HaarClassifierNodeDescriptor32 __host__ Ncv32f getLeafValueHost(void) { - return *(Ncv32f *)&this->_ui1.x; + return *(Ncv32f_a *)&this->_ui1.x; } #ifdef __CUDACC__ @@ -203,6 +206,11 @@ struct HaarClassifierNodeDescriptor32 } }; +#if defined __GNUC__ && __GNUC__ > 2 && __GNUC_MINOR__ > 4 +typedef Ncv32u __attribute__((__may_alias__)) Ncv32u_a; +#else +typedef Ncv32u Ncv32u_a; +#endif struct HaarClassifierNode128 { @@ -216,19 +224,19 @@ struct HaarClassifierNode128 __host__ NCVStatus setThreshold(Ncv32f t) { - this->_ui4.y = *(Ncv32u *)&t; + this->_ui4.y = *(Ncv32u_a *)&t; return NCV_SUCCESS; } __host__ NCVStatus setLeftNodeDesc(HaarClassifierNodeDescriptor32 nl) { - this->_ui4.z = *(Ncv32u *)&nl; + this->_ui4.z = *(Ncv32u_a *)&nl; return NCV_SUCCESS; } __host__ NCVStatus setRightNodeDesc(HaarClassifierNodeDescriptor32 nr) { - this->_ui4.w = *(Ncv32u *)&nr; + this->_ui4.w = *(Ncv32u_a *)&nr; return NCV_SUCCESS; } @@ -239,7 +247,7 @@ struct HaarClassifierNode128 __host__ __device__ Ncv32f getThreshold(void) { - return *(Ncv32f*)&this->_ui4.y; + return *(Ncv32f_a*)&this->_ui4.y; } __host__ __device__ HaarClassifierNodeDescriptor32 getLeftNodeDesc(void) @@ -264,7 +272,7 @@ struct HaarStage64 __host__ NCVStatus setStageThreshold(Ncv32f t) { - this->_ui2.x = *(Ncv32u *)&t; + this->_ui2.x = *(Ncv32u_a *)&t; return NCV_SUCCESS; } @@ -290,7 +298,7 @@ struct HaarStage64 __host__ __device__ Ncv32f getStageThreshold(void) { - return *(Ncv32f*)&this->_ui2.x; + return *(Ncv32f_a*)&this->_ui2.x; } __host__ __device__ Ncv32u getStartClassifierRootNodeOffset(void) diff --git a/modules/gpu/src/nvidia/NPP_staging/NPP_staging.cu b/modules/gpu/src/nvidia/NPP_staging/NPP_staging.cu index 6e0f5eb26a..f75453930b 100644 --- a/modules/gpu/src/nvidia/NPP_staging/NPP_staging.cu +++ b/modules/gpu/src/nvidia/NPP_staging/NPP_staging.cu @@ -1423,7 +1423,7 @@ NCVStatus compactVector_32u_device(Ncv32u *d_src, Ncv32u srcLen, (d_hierSums.ptr() + partSumOffsets[i], partSumNums[i], NULL, d_hierSums.ptr() + partSumOffsets[i+1], - NULL); + 0); } else { @@ -1433,7 +1433,7 @@ NCVStatus compactVector_32u_device(Ncv32u *d_src, Ncv32u srcLen, (d_hierSums.ptr() + partSumOffsets[i], partSumNums[i], NULL, NULL, - NULL); + 0); } ncvAssertCUDALastErrorReturn(NPPST_CUDA_KERNEL_EXECUTION_ERROR); @@ -1557,16 +1557,21 @@ NCVStatus nppsStCompact_32s(Ncv32s *d_src, Ncv32u srcLen, } +#if defined __GNUC__ && __GNUC__ > 2 && __GNUC_MINOR__ > 4 +typedef Ncv32u __attribute__((__may_alias__)) Ncv32u_a; +#else +typedef Ncv32u Ncv32u_a; +#endif + NCVStatus nppsStCompact_32f(Ncv32f *d_src, Ncv32u srcLen, Ncv32f *d_dst, Ncv32u *p_dstLen, Ncv32f elemRemove, Ncv8u *pBuffer, Ncv32u bufSize, cudaDeviceProp &devProp) { return nppsStCompact_32u((Ncv32u *)d_src, srcLen, (Ncv32u *)d_dst, p_dstLen, - *(Ncv32u *)&elemRemove, pBuffer, bufSize, devProp); + *(Ncv32u_a *)&elemRemove, pBuffer, bufSize, devProp); } - NCVStatus nppsStCompact_32u_host(Ncv32u *h_src, Ncv32u srcLen, Ncv32u *h_dst, Ncv32u *dstLen, Ncv32u elemRemove) { @@ -1602,17 +1607,16 @@ NCVStatus nppsStCompact_32u_host(Ncv32u *h_src, Ncv32u srcLen, NCVStatus nppsStCompact_32s_host(Ncv32s *h_src, Ncv32u srcLen, Ncv32s *h_dst, Ncv32u *dstLen, Ncv32s elemRemove) { - return nppsStCompact_32u_host((Ncv32u *)h_src, srcLen, (Ncv32u *)h_dst, dstLen, *(Ncv32u *)&elemRemove); + return nppsStCompact_32u_host((Ncv32u *)h_src, srcLen, (Ncv32u *)h_dst, dstLen, *(Ncv32u_a *)&elemRemove); } NCVStatus nppsStCompact_32f_host(Ncv32f *h_src, Ncv32u srcLen, Ncv32f *h_dst, Ncv32u *dstLen, Ncv32f elemRemove) { - return nppsStCompact_32u_host((Ncv32u *)h_src, srcLen, (Ncv32u *)h_dst, dstLen, *(Ncv32u *)&elemRemove); + return nppsStCompact_32u_host((Ncv32u *)h_src, srcLen, (Ncv32u *)h_dst, dstLen, *(Ncv32u_a *)&elemRemove); } - //============================================================================== // // Filter.cu diff --git a/modules/gpu/test/nvidia/TestHaarCascadeApplication.cpp b/modules/gpu/test/nvidia/TestHaarCascadeApplication.cpp index e53f7f3a4f..fe4f5d6a3e 100644 --- a/modules/gpu/test/nvidia/TestHaarCascadeApplication.cpp +++ b/modules/gpu/test/nvidia/TestHaarCascadeApplication.cpp @@ -245,8 +245,8 @@ bool TestHaarCascadeApplication::process() int devId; ncvAssertCUDAReturn(cudaGetDevice(&devId), false); - cudaDeviceProp devProp; - ncvAssertCUDAReturn(cudaGetDeviceProperties(&devProp, devId), false); + cudaDeviceProp _devProp; + ncvAssertCUDAReturn(cudaGetDeviceProperties(&_devProp, devId), false); ncvStat = ncvApplyHaarClassifierCascade_device( d_integralImage, d_rectStdDev, d_pixelMask, @@ -254,7 +254,7 @@ bool TestHaarCascadeApplication::process() haar, h_HaarStages, d_HaarStages, d_HaarNodes, d_HaarFeatures, false, searchRoiU, 1, 1.0f, *this->allocatorGPU.get(), *this->allocatorCPU.get(), - devProp, 0); + _devProp, 0); ncvAssertReturn(ncvStat == NCV_SUCCESS, false); NCVMatrixAlloc h_pixelMask_d(*this->allocatorCPU.get(), this->width, this->height); diff --git a/modules/gpu/test/nvidia/main_nvidia.cpp b/modules/gpu/test/nvidia/main_nvidia.cpp index bb61608946..15759e10fb 100644 --- a/modules/gpu/test/nvidia/main_nvidia.cpp +++ b/modules/gpu/test/nvidia/main_nvidia.cpp @@ -1,4 +1,6 @@ -#pragma warning (disable : 4408 4201 4100) +#if defined _MSC_VER && _MSC_VER >= 1200 +# pragma warning (disable : 4408 4201 4100) +#endif #include From 15213401529574ba4f4ae81d04dd01ec61f83991 Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Mon, 20 Aug 2012 03:25:52 +0400 Subject: [PATCH 027/163] updated CascadeClassifier_GPU documentation --- modules/gpu/doc/object_detection.rst | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/modules/gpu/doc/object_detection.rst b/modules/gpu/doc/object_detection.rst index 1f522f3441..133660236a 100644 --- a/modules/gpu/doc/object_detection.rst +++ b/modules/gpu/doc/object_detection.rst @@ -204,7 +204,7 @@ gpu::CascadeClassifier_GPU -------------------------- .. ocv:class:: gpu::CascadeClassifier_GPU -Cascade classifier class used for object detection. :: +Cascade classifier class used for object detection. Supports HAAR and LBP cascades. :: class CV_EXPORTS CascadeClassifier_GPU { @@ -219,6 +219,7 @@ Cascade classifier class used for object detection. :: /* Returns number of detected objects */ int detectMultiScale( const GpuMat& image, GpuMat& objectsBuf, double scaleFactor=1.2, int minNeighbors=4, Size minSize=Size()); + int detectMultiScale( const GpuMat& image, GpuMat& objectsBuf, Size maxObjectSize, Size minSize = Size(), double scaleFactor = 1.1, int minNeighbors = 4); /* Finds only the largest object. Special mode if training is required.*/ bool findLargestObject; @@ -233,11 +234,11 @@ Cascade classifier class used for object detection. :: gpu::CascadeClassifier_GPU::CascadeClassifier_GPU ----------------------------------------------------- -Loads the classifier from a file. +Loads the classifier from a file. Cascade type is detected automatically by constructor parameter. .. ocv:function:: gpu::CascadeClassifier_GPU::CascadeClassifier_GPU(const string& filename) - :param filename: Name of the file from which the classifier is loaded. Only the old ``haar`` classifier (trained by the ``haar`` training application) and NVIDIA's ``nvbin`` are supported. + :param filename: Name of the file from which the classifier is loaded. Only the old ``haar`` classifier (trained by the ``haar`` training application) and NVIDIA's ``nvbin`` are supported for HAAR and only new type of OpenCV XML cascade supported for LBP. @@ -255,8 +256,7 @@ Loads the classifier from a file. The previous content is destroyed. .. ocv:function:: bool gpu::CascadeClassifier_GPU::load(const string& filename) - :param filename: Name of the file from which the classifier is loaded. Only the old ``haar`` classifier (trained by the ``haar`` training application) and NVIDIA's ``nvbin`` are supported. - + :param filename: Name of the file from which the classifier is loaded. Only the old ``haar`` classifier (trained by the ``haar`` training application) and NVIDIA's ``nvbin`` are supported for HAAR and only new type of OpenCV XML cascade supported for LBP. gpu::CascadeClassifier_GPU::release @@ -273,13 +273,17 @@ Detects objects of different sizes in the input image. .. ocv:function:: int gpu::CascadeClassifier_GPU::detectMultiScale(const GpuMat& image, GpuMat& objectsBuf, double scaleFactor=1.2, int minNeighbors=4, Size minSize=Size()) +.. ocv:function:: int gpu::CascadeClassifier_GPU::detectMultiScale(const GpuMat& image, GpuMat& objectsBuf, Size maxObjectSize, Size minSize = Size(), double scaleFactor = 1.1, int minNeighbors = 4) + :param image: Matrix of type ``CV_8U`` containing an image where objects should be detected. :param objectsBuf: Buffer to store detected objects (rectangles). If it is empty, it is allocated with the default size. If not empty, the function searches not more than N objects, where ``N = sizeof(objectsBufer's data)/sizeof(cv::Rect)``. - :param scaleFactor: Value to specify how much the image size is reduced at each image scale. + :param maxObjectSize: Maximum possible object size. Objects larger than that are ignored. Used for second signature and supported only for LBP cascades. - :param minNeighbors: Value to specify how many neighbours each candidate rectangle has to retain. + :param scaleFactor: Parameter specifying how much the image size is reduced at each image scale. + + :param minNeighbors: Parameter specifying how many neighbors each candidate rectangle should have to retain it. :param minSize: Minimum possible object size. Objects smaller than that are ignored. From f17f4bda6026ea02668c1a6ccf8f0726b1ed8682 Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Mon, 20 Aug 2012 03:26:53 +0400 Subject: [PATCH 028/163] more warning fixes for GCC --- modules/gpu/src/brute_force_matcher.cpp | 50 ++++++++++++------------- modules/gpu/src/hog.cpp | 6 +-- modules/gpu/src/video_decoder.cpp | 40 ++++++++++---------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/modules/gpu/src/brute_force_matcher.cpp b/modules/gpu/src/brute_force_matcher.cpp index d70926068c..a1fe066136 100644 --- a/modules/gpu/src/brute_force_matcher.cpp +++ b/modules/gpu/src/brute_force_matcher.cpp @@ -420,16 +420,16 @@ void cv::gpu::BFMatcher_GPU::matchConvert(const Mat& trainIdx, const Mat& imgIdx const float* distance_ptr = distance.ptr(); for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx, ++trainIdx_ptr, ++imgIdx_ptr, ++distance_ptr) { - int trainIdx = *trainIdx_ptr; + int _trainIdx = *trainIdx_ptr; - if (trainIdx == -1) + if (_trainIdx == -1) continue; - int imgIdx = *imgIdx_ptr; + int _imgIdx = *imgIdx_ptr; - float distance = *distance_ptr; + float _distance = *distance_ptr; - DMatch m(queryIdx, trainIdx, imgIdx, distance); + DMatch m(queryIdx, _trainIdx, _imgIdx, _distance); matches.push_back(m); } @@ -558,13 +558,13 @@ void cv::gpu::BFMatcher_GPU::knnMatchConvert(const Mat& trainIdx, const Mat& dis for (int i = 0; i < k; ++i, ++trainIdx_ptr, ++distance_ptr) { - int trainIdx = *trainIdx_ptr; + int _trainIdx = *trainIdx_ptr; - if (trainIdx != -1) + if (_trainIdx != -1) { - float distance = *distance_ptr; + float _distance = *distance_ptr; - DMatch m(queryIdx, trainIdx, 0, distance); + DMatch m(queryIdx, _trainIdx, 0, _distance); curMatches.push_back(m); } @@ -680,15 +680,15 @@ void cv::gpu::BFMatcher_GPU::knnMatch2Convert(const Mat& trainIdx, const Mat& im for (int i = 0; i < 2; ++i, ++trainIdx_ptr, ++imgIdx_ptr, ++distance_ptr) { - int trainIdx = *trainIdx_ptr; + int _trainIdx = *trainIdx_ptr; - if (trainIdx != -1) + if (_trainIdx != -1) { - int imgIdx = *imgIdx_ptr; + int _imgIdx = *imgIdx_ptr; - float distance = *distance_ptr; + float _distance = *distance_ptr; - DMatch m(queryIdx, trainIdx, imgIdx, distance); + DMatch m(queryIdx, _trainIdx, _imgIdx, _distance); curMatches.push_back(m); } @@ -868,25 +868,25 @@ void cv::gpu::BFMatcher_GPU::radiusMatchConvert(const Mat& trainIdx, const Mat& const int* trainIdx_ptr = trainIdx.ptr(queryIdx); const float* distance_ptr = distance.ptr(queryIdx); - const int nMatches = std::min(nMatches_ptr[queryIdx], trainIdx.cols); + const int nMatched = std::min(nMatches_ptr[queryIdx], trainIdx.cols); - if (nMatches == 0) + if (nMatched == 0) { if (!compactResult) matches.push_back(vector()); continue; } - matches.push_back(vector(nMatches)); + matches.push_back(vector(nMatched)); vector& curMatches = matches.back(); - for (int i = 0; i < nMatches; ++i, ++trainIdx_ptr, ++distance_ptr) + for (int i = 0; i < nMatched; ++i, ++trainIdx_ptr, ++distance_ptr) { - int trainIdx = *trainIdx_ptr; + int _trainIdx = *trainIdx_ptr; - float distance = *distance_ptr; + float _distance = *distance_ptr; - DMatch m(queryIdx, trainIdx, 0, distance); + DMatch m(queryIdx, _trainIdx, 0, _distance); curMatches[i] = m; } @@ -1009,9 +1009,9 @@ void cv::gpu::BFMatcher_GPU::radiusMatchConvert(const Mat& trainIdx, const Mat& const int* imgIdx_ptr = imgIdx.ptr(queryIdx); const float* distance_ptr = distance.ptr(queryIdx); - const int nMatches = std::min(nMatches_ptr[queryIdx], trainIdx.cols); + const int nMatched = std::min(nMatches_ptr[queryIdx], trainIdx.cols); - if (nMatches == 0) + if (nMatched == 0) { if (!compactResult) matches.push_back(vector()); @@ -1020,9 +1020,9 @@ void cv::gpu::BFMatcher_GPU::radiusMatchConvert(const Mat& trainIdx, const Mat& matches.push_back(vector()); vector& curMatches = matches.back(); - curMatches.reserve(nMatches); + curMatches.reserve(nMatched); - for (int i = 0; i < nMatches; ++i, ++trainIdx_ptr, ++imgIdx_ptr, ++distance_ptr) + for (int i = 0; i < nMatched; ++i, ++trainIdx_ptr, ++imgIdx_ptr, ++distance_ptr) { int _trainIdx = *trainIdx_ptr; int _imgIdx = *imgIdx_ptr; diff --git a/modules/gpu/src/hog.cpp b/modules/gpu/src/hog.cpp index fafcce784b..5db3be9781 100644 --- a/modules/gpu/src/hog.cpp +++ b/modules/gpu/src/hog.cpp @@ -315,7 +315,7 @@ void cv::gpu::HOGDescriptor::computeConfidenceMultiScale(const GpuMat& img, vect double scale = 1.; int levels = 0; - for (levels = 0; levels < conf_out.size(); levels++) + for (levels = 0; levels < (int)conf_out.size(); levels++) { scale = conf_out[levels].scale; level_scale.push_back(scale); @@ -332,8 +332,8 @@ void cv::gpu::HOGDescriptor::computeConfidenceMultiScale(const GpuMat& img, vect for (size_t i = 0; i < level_scale.size(); i++) { - double scale = level_scale[i]; - Size sz(cvRound(img.cols / scale), cvRound(img.rows / scale)); + double _scale = level_scale[i]; + Size sz(cvRound(img.cols / _scale), cvRound(img.rows / _scale)); GpuMat smaller_img; if (sz == img.size()) diff --git a/modules/gpu/src/video_decoder.cpp b/modules/gpu/src/video_decoder.cpp index 9f06adc9ce..bee5002a88 100644 --- a/modules/gpu/src/video_decoder.cpp +++ b/modules/gpu/src/video_decoder.cpp @@ -49,36 +49,36 @@ void cv::gpu::detail::VideoDecoder::create(const VideoReader_GPU::FormatInfo& vi { release(); - cudaVideoCodec codec = static_cast(videoFormat.codec); - cudaVideoChromaFormat chromaFormat = static_cast(videoFormat.chromaFormat); + cudaVideoCodec _codec = static_cast(videoFormat.codec); + cudaVideoChromaFormat _chromaFormat = static_cast(videoFormat.chromaFormat); - cudaVideoCreateFlags videoCreateFlags = (codec == cudaVideoCodec_JPEG || codec == cudaVideoCodec_MPEG2) ? + cudaVideoCreateFlags videoCreateFlags = (_codec == cudaVideoCodec_JPEG || _codec == cudaVideoCodec_MPEG2) ? cudaVideoCreate_PreferCUDA : cudaVideoCreate_PreferCUVID; // Validate video format. These are the currently supported formats via NVCUVID - CV_Assert(cudaVideoCodec_MPEG1 == codec || - cudaVideoCodec_MPEG2 == codec || - cudaVideoCodec_MPEG4 == codec || - cudaVideoCodec_VC1 == codec || - cudaVideoCodec_H264 == codec || - cudaVideoCodec_JPEG == codec || - cudaVideoCodec_YUV420== codec || - cudaVideoCodec_YV12 == codec || - cudaVideoCodec_NV12 == codec || - cudaVideoCodec_YUYV == codec || - cudaVideoCodec_UYVY == codec ); + CV_Assert(cudaVideoCodec_MPEG1 == _codec || + cudaVideoCodec_MPEG2 == _codec || + cudaVideoCodec_MPEG4 == _codec || + cudaVideoCodec_VC1 == _codec || + cudaVideoCodec_H264 == _codec || + cudaVideoCodec_JPEG == _codec || + cudaVideoCodec_YUV420== _codec || + cudaVideoCodec_YV12 == _codec || + cudaVideoCodec_NV12 == _codec || + cudaVideoCodec_YUYV == _codec || + cudaVideoCodec_UYVY == _codec ); - CV_Assert(cudaVideoChromaFormat_Monochrome == chromaFormat || - cudaVideoChromaFormat_420 == chromaFormat || - cudaVideoChromaFormat_422 == chromaFormat || - cudaVideoChromaFormat_444 == chromaFormat); + CV_Assert(cudaVideoChromaFormat_Monochrome == _chromaFormat || + cudaVideoChromaFormat_420 == _chromaFormat || + cudaVideoChromaFormat_422 == _chromaFormat || + cudaVideoChromaFormat_444 == _chromaFormat); // Fill the decoder-create-info struct from the given video-format struct. std::memset(&createInfo_, 0, sizeof(CUVIDDECODECREATEINFO)); // Create video decoder - createInfo_.CodecType = codec; + createInfo_.CodecType = _codec; createInfo_.ulWidth = videoFormat.width; createInfo_.ulHeight = videoFormat.height; createInfo_.ulNumDecodeSurfaces = FrameQueue::MaximumSize; @@ -87,7 +87,7 @@ void cv::gpu::detail::VideoDecoder::create(const VideoReader_GPU::FormatInfo& vi while (createInfo_.ulNumDecodeSurfaces * videoFormat.width * videoFormat.height > 16 * 1024 * 1024) createInfo_.ulNumDecodeSurfaces--; - createInfo_.ChromaFormat = chromaFormat; + createInfo_.ChromaFormat = _chromaFormat; createInfo_.OutputFormat = cudaVideoSurfaceFormat_NV12; createInfo_.DeinterlaceMode = cudaVideoDeinterlaceMode_Adaptive; From e7f4dd1a2e5d648c242af0151b0a183eb7dcd950 Mon Sep 17 00:00:00 2001 From: niko Date: Mon, 20 Aug 2012 10:06:41 +0800 Subject: [PATCH 029/163] temp build fix because the new core.hpp impact on this project --- modules/ocl/src/initialization.cpp | 6 +++--- modules/ocl/src/threadsafe.cpp | 4 ++-- modules/ocl/src/threadsafe.h | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/ocl/src/initialization.cpp b/modules/ocl/src/initialization.cpp index fab81fd46d..096b9790de 100644 --- a/modules/ocl/src/initialization.cpp +++ b/modules/ocl/src/initialization.cpp @@ -44,9 +44,9 @@ //M*/ #include "precomp.hpp" -#include "Threadsafe.h" +#include "threadsafe.h" #include -#include "binaryCaching.hpp" +#include "binarycaching.hpp" using namespace cv; using namespace cv::ocl; @@ -775,7 +775,7 @@ namespace cv { if(val == 0) { - AutoLock al(&cs); + myAutoLock al(&cs); if( NULL == clCxt.get()) clCxt.reset(new Context); diff --git a/modules/ocl/src/threadsafe.cpp b/modules/ocl/src/threadsafe.cpp index 9d952d328c..25b3773e04 100644 --- a/modules/ocl/src/threadsafe.cpp +++ b/modules/ocl/src/threadsafe.cpp @@ -43,8 +43,8 @@ // //M*/ -#include "precomp.hpp" -#include "Threadsafe.h" +//#include "precomp.hpp" +#include "threadsafe.h" CriticalSection::CriticalSection() { diff --git a/modules/ocl/src/threadsafe.h b/modules/ocl/src/threadsafe.h index b7954fdcdd..5905a55172 100644 --- a/modules/ocl/src/threadsafe.h +++ b/modules/ocl/src/threadsafe.h @@ -65,15 +65,15 @@ protected: #endif }; -class AutoLock +class myAutoLock { public: - explicit AutoLock(CriticalSection *lock) + explicit myAutoLock(CriticalSection *lock) { m_lock = lock; m_lock->Lock(); }; - ~AutoLock() + ~myAutoLock() { m_lock->Unlock(); }; From a0aef244d675afc515397e2df3bd7a5d04312b78 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 20 Aug 2012 09:58:37 +0400 Subject: [PATCH 030/163] removed perf_gpu_cpu from CMake scripts --- cmake/OpenCVModule.cmake | 2 - modules/gpu/CMakeLists.txt | 40 ------------------- modules/gpu/perf/perf_precomp.hpp | 2 +- .../perf/{perf_utility.cpp => utility.cpp} | 0 .../perf/{perf_utility.hpp => utility.hpp} | 0 .../test/{precomp.cpp => test_precomp.cpp} | 0 .../test/{precomp.hpp => test_precomp.hpp} | 0 7 files changed, 1 insertion(+), 43 deletions(-) rename modules/gpu/perf/{perf_utility.cpp => utility.cpp} (100%) rename modules/gpu/perf/{perf_utility.hpp => utility.hpp} (100%) rename modules/gpu/test/{precomp.cpp => test_precomp.cpp} (100%) rename modules/gpu/test/{precomp.hpp => test_precomp.hpp} (100%) diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 543f9970b6..018a467308 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -509,8 +509,6 @@ endmacro() macro(ocv_add_precompiled_headers the_target) if("${the_target}" MATCHES "^opencv_test_.*$") SET(pch_path "test/test_") - elseif("${the_target}" MATCHES "opencv_perf_gpu_cpu") - SET(pch_path "perf_cpu/perf_cpu_") elseif("${the_target}" MATCHES "^opencv_perf_.*$") SET(pch_path "perf/perf_") else() diff --git a/modules/gpu/CMakeLists.txt b/modules/gpu/CMakeLists.txt index e24b73a77d..5d2c440fe5 100644 --- a/modules/gpu/CMakeLists.txt +++ b/modules/gpu/CMakeLists.txt @@ -111,43 +111,3 @@ ocv_add_accuracy_tests(FILES "Include" ${test_hdrs} FILES "Src" ${test_srcs} ${nvidia}) ocv_add_perf_tests() - - - -set(perf_cpu_path "${CMAKE_CURRENT_SOURCE_DIR}/perf_cpu") -if(BUILD_PERF_TESTS AND EXISTS "${perf_cpu_path}") - # opencv_highgui is required for imread/imwrite - set(perf_deps ${the_module} opencv_ts opencv_highgui opencv_imgproc opencv_calib3d opencv_objdetect opencv_video opencv_nonfree) - ocv_check_dependencies(${perf_deps}) - - if(OCV_DEPENDENCIES_FOUND) - set(the_target "opencv_perf_gpu_cpu") - - ocv_module_include_directories(${perf_deps} "${perf_cpu_path}") - - if(NOT OPENCV_PERF_${the_module}_CPU_SOURCES) - file(GLOB perf_srcs "${perf_cpu_path}/*.cpp") - file(GLOB perf_hdrs "${perf_cpu_path}/*.hpp" "${perf_cpu_path}/*.h") - source_group("Src" FILES ${perf_srcs}) - source_group("Include" FILES ${perf_hdrs}) - set(OPENCV_PERF_${the_module}_CPU_SOURCES ${perf_srcs} ${perf_hdrs}) - endif() - - add_executable(${the_target} ${OPENCV_PERF_${the_module}_CPU_SOURCES}) - target_link_libraries(${the_target} ${OPENCV_MODULE_${the_module}_DEPS} ${perf_deps} ${OPENCV_LINKER_LIBS}) - - # Additional target properties - set_target_properties(${the_target} PROPERTIES - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - RUNTIME_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}" - ) - - if(ENABLE_SOLUTION_FOLDERS) - set_target_properties(${the_target} PROPERTIES FOLDER "tests performance") - endif() - - ocv_add_precompiled_headers(${the_target}) - else(OCV_DEPENDENCIES_FOUND) - #TODO: warn about unsatisfied dependencies - endif(OCV_DEPENDENCIES_FOUND) - endif() diff --git a/modules/gpu/perf/perf_precomp.hpp b/modules/gpu/perf/perf_precomp.hpp index be3f234a35..8378599475 100644 --- a/modules/gpu/perf/perf_precomp.hpp +++ b/modules/gpu/perf/perf_precomp.hpp @@ -27,7 +27,7 @@ #include "opencv2/nonfree/nonfree.hpp" #include "opencv2/legacy/legacy.hpp" -#include "perf_utility.hpp" +#include "utility.hpp" #ifdef GTEST_CREATE_SHARED_LIBRARY #error no modules except ts should have GTEST_CREATE_SHARED_LIBRARY defined diff --git a/modules/gpu/perf/perf_utility.cpp b/modules/gpu/perf/utility.cpp similarity index 100% rename from modules/gpu/perf/perf_utility.cpp rename to modules/gpu/perf/utility.cpp diff --git a/modules/gpu/perf/perf_utility.hpp b/modules/gpu/perf/utility.hpp similarity index 100% rename from modules/gpu/perf/perf_utility.hpp rename to modules/gpu/perf/utility.hpp diff --git a/modules/gpu/test/precomp.cpp b/modules/gpu/test/test_precomp.cpp similarity index 100% rename from modules/gpu/test/precomp.cpp rename to modules/gpu/test/test_precomp.cpp diff --git a/modules/gpu/test/precomp.hpp b/modules/gpu/test/test_precomp.hpp similarity index 100% rename from modules/gpu/test/precomp.hpp rename to modules/gpu/test/test_precomp.hpp From ec7f9566e0df2d535d7ac5123026720cb7e80d2d Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 20 Aug 2012 10:15:36 +0400 Subject: [PATCH 031/163] minor gpu tests fix --- modules/gpu/perf/main.cpp | 6 +- modules/gpu/test/main.cpp | 92 ++++++++++--------- modules/gpu/test/main_test_nvidia.h | 4 +- modules/gpu/test/test_calib3d.cpp | 8 +- modules/gpu/test/test_color.cpp | 2 +- modules/gpu/test/test_copy_make_border.cpp | 6 +- modules/gpu/test/test_core.cpp | 6 +- modules/gpu/test/test_features2d.cpp | 6 +- modules/gpu/test/test_filters.cpp | 6 +- modules/gpu/test/test_global_motion.cpp | 8 +- modules/gpu/test/test_gpumat.cpp | 6 +- modules/gpu/test/test_imgproc.cpp | 6 +- modules/gpu/test/test_labeling.cpp | 6 +- modules/gpu/test/test_nvidia.cpp | 14 +-- modules/gpu/test/test_objdetect.cpp | 25 ++--- modules/gpu/test/test_precomp.cpp | 2 +- modules/gpu/test/test_precomp.hpp | 2 + modules/gpu/test/test_pyramids.cpp | 2 +- modules/gpu/test/test_remap.cpp | 2 +- modules/gpu/test/test_resize.cpp | 3 +- modules/gpu/test/test_threshold.cpp | 2 +- modules/gpu/test/test_video.cpp | 6 +- modules/gpu/test/test_warp_affine.cpp | 2 +- modules/gpu/test/test_warp_perspective.cpp | 2 +- modules/gpu/test/utility.cpp | 101 +-------------------- modules/gpu/test/utility.hpp | 4 +- 26 files changed, 134 insertions(+), 195 deletions(-) diff --git a/modules/gpu/perf/main.cpp b/modules/gpu/perf/main.cpp index 865362f880..aadeee955b 100644 --- a/modules/gpu/perf/main.cpp +++ b/modules/gpu/perf/main.cpp @@ -71,9 +71,9 @@ void printCudaInfo() #endif } -int main(int argc, char **argv) +int main(int argc, char** argv) { - CommandLineParser cmd(argc, argv, + CommandLineParser cmd(argc, (const char**) argv, "{ print_info_only | print_info_only | false | Print information about system and exit }" "{ device | device | 0 | Device on which tests will be executed }" "{ cpu | cpu | false | Run tests on cpu }" @@ -119,7 +119,7 @@ int main(int argc, char **argv) cout << "Run tests on device " << device << " [" << info.name() << "] \n" << endl; } - testing::InitGoogleTest(&argc, argv); + InitGoogleTest(&argc, argv); perf::TestBase::Init(argc, argv); return RUN_ALL_TESTS(); } diff --git a/modules/gpu/test/main.cpp b/modules/gpu/test/main.cpp index 6df7db0a1b..8f216c9fea 100644 --- a/modules/gpu/test/main.cpp +++ b/modules/gpu/test/main.cpp @@ -39,7 +39,7 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" #ifdef HAVE_CUDA @@ -49,93 +49,103 @@ using namespace cv::gpu; using namespace cvtest; using namespace testing; -void printInfo() +void printOsInfo() { #if defined _WIN32 # if defined _WIN64 - puts("OS: Windows x64"); + cout << "OS: Windows x64 \n" << endl; # else - puts("OS: Windows x32"); + cout << "OS: Windows x32 \n" << endl; # endif #elif defined linux # if defined _LP64 - puts("OS: Linux x64"); + cout << "OS: Linux x64 \n" << endl; # else - puts("OS: Linux x32"); + cout << "OS: Linux x32 \n" << endl; # endif #elif defined __APPLE__ # if defined _LP64 - puts("OS: Apple x64"); + cout << "OS: Apple x64 \n" << endl; # else - puts("OS: Apple x32"); + cout << "OS: Apple x32 \n" << endl; # endif #endif +} +void printCudaInfo() +{ +#ifndef HAVE_CUDA + cout << "OpenCV was built without CUDA support \n" << endl; +#else int driver; cudaDriverGetVersion(&driver); - printf("CUDA Driver version: %d\n", driver); - printf("CUDA Runtime version: %d\n", CUDART_VERSION); + cout << "CUDA Driver version: " << driver << '\n'; + cout << "CUDA Runtime version: " << CUDART_VERSION << '\n'; - puts("GPU module was compiled for the following GPU archs:"); - printf(" BIN: %s\n", CUDA_ARCH_BIN); - printf(" PTX: %s\n\n", CUDA_ARCH_PTX); + cout << endl; + + cout << "GPU module was compiled for the following GPU archs:" << endl; + cout << " BIN: " << CUDA_ARCH_BIN << '\n'; + cout << " PTX: " << CUDA_ARCH_PTX << '\n'; + + cout << endl; int deviceCount = getCudaEnabledDeviceCount(); - printf("CUDA device count: %d\n\n", deviceCount); + cout << "CUDA device count: " << deviceCount << '\n'; + + cout << endl; for (int i = 0; i < deviceCount; ++i) { DeviceInfo info(i); - printf("Device %d:\n", i); - printf(" Name: %s\n", info.name().c_str()); - printf(" Compute capability version: %d.%d\n", info.majorVersion(), info.minorVersion()); - printf(" Multi Processor Count: %d\n", info.multiProcessorCount()); - printf(" Total memory: %d Mb\n", static_cast(static_cast(info.totalMemory() / 1024.0) / 1024.0)); - printf(" Free memory: %d Mb\n", static_cast(static_cast(info.freeMemory() / 1024.0) / 1024.0)); + cout << "Device [" << i << "] \n"; + cout << "\t Name: " << info.name() << '\n'; + cout << "\t Compute capability: " << info.majorVersion() << '.' << info.minorVersion()<< '\n'; + cout << "\t Multi Processor Count: " << info.multiProcessorCount() << '\n'; + cout << "\t Total memory: " << static_cast(static_cast(info.totalMemory() / 1024.0) / 1024.0) << " Mb \n"; + cout << "\t Free memory: " << static_cast(static_cast(info.freeMemory() / 1024.0) / 1024.0) << " Mb \n"; if (!info.isCompatible()) - puts(" !!! This device is NOT compatible with current GPU module build\n"); - printf("\n"); + cout << "\t !!! This device is NOT compatible with current GPU module build \n"; + + cout << endl; } +#endif } -enum OutputLevel -{ - OutputLevelNone, - OutputLevelCompact, - OutputLevelFull -}; - -extern OutputLevel nvidiaTestOutputLevel; - int main(int argc, char** argv) { try { - CommandLineParser parser(argc, (const char**)argv, - "{ print_info_only | print_info_only | false | Print information about system and exit }" - "{ device | device | -1 | Device on which tests will be executed (-1 means all devices) }" - "{ nvtest_output_level | nvtest_output_level | compact | NVidia test verbosity level }"); + CommandLineParser cmd(argc, (const char**)argv, + "{ print_info_only | print_info_only | false | Print information about system and exit }" + "{ device | device | -1 | Device on which tests will be executed (-1 means all devices) }" + "{ nvtest_output_level | nvtest_output_level | compact | NVidia test verbosity level }" + ); - printInfo(); + printOsInfo(); + printCudaInfo(); - if (parser.get("print_info_only")) + if (cmd.get("print_info_only")) return 0; - int device = parser.get("device"); + int device = cmd.get("device"); if (device < 0) { DeviceManager::instance().loadAll(); - std::cout << "Run tests on all supported devices\n" << std::endl; + + cout << "Run tests on all supported devices \n" << endl; } else { DeviceManager::instance().load(device); - std::cout << "Run tests on device " << device << '\n' << std::endl; + + DeviceInfo info(device); + cout << "Run tests on device " << device << " [" << info.name() << "] \n" << endl; } - string outputLevel = parser.get("nvtest_output_level"); + string outputLevel = cmd.get("nvtest_output_level"); if (outputLevel == "none") nvidiaTestOutputLevel = OutputLevelNone; diff --git a/modules/gpu/test/main_test_nvidia.h b/modules/gpu/test/main_test_nvidia.h index d1c3620128..15016ca64c 100644 --- a/modules/gpu/test/main_test_nvidia.h +++ b/modules/gpu/test/main_test_nvidia.h @@ -1,7 +1,7 @@ #ifndef __main_test_nvidia_h__ #define __main_test_nvidia_h__ -#include +#include enum OutputLevel { @@ -10,6 +10,8 @@ enum OutputLevel OutputLevelFull }; +extern OutputLevel nvidiaTestOutputLevel; + bool nvidia_NPPST_Integral_Image(const std::string& test_data_path, OutputLevel outputLevel); bool nvidia_NPPST_Squared_Integral_Image(const std::string& test_data_path, OutputLevel outputLevel); bool nvidia_NPPST_RectStdDev(const std::string& test_data_path, OutputLevel outputLevel); diff --git a/modules/gpu/test/test_calib3d.cpp b/modules/gpu/test/test_calib3d.cpp index bdc043fc58..5fa1ebb41d 100644 --- a/modules/gpu/test/test_calib3d.cpp +++ b/modules/gpu/test/test_calib3d.cpp @@ -39,7 +39,9 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" + +#ifdef HAVE_CUDA namespace { @@ -329,7 +331,7 @@ TEST_P(ReprojectImageTo3D, Accuracy) cv::gpu::GpuMat dst; cv::gpu::reprojectImageTo3D(loadMat(disp, useRoi), dst, Q, 3); - + cv::Mat dst_gold; cv::reprojectImageTo3D(disp, dst_gold, Q, false); @@ -343,3 +345,5 @@ INSTANTIATE_TEST_CASE_P(GPU_Calib3D, ReprojectImageTo3D, testing::Combine( WHOLE_SUBMAT)); } // namespace + +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_color.cpp b/modules/gpu/test/test_color.cpp index 645967ef27..c2929fbe71 100644 --- a/modules/gpu/test/test_color.cpp +++ b/modules/gpu/test/test_color.cpp @@ -39,7 +39,7 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" #ifdef HAVE_CUDA diff --git a/modules/gpu/test/test_copy_make_border.cpp b/modules/gpu/test/test_copy_make_border.cpp index 45b73d302d..8bd5a66f90 100644 --- a/modules/gpu/test/test_copy_make_border.cpp +++ b/modules/gpu/test/test_copy_make_border.cpp @@ -39,7 +39,9 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" + +#ifdef HAVE_CUDA namespace { @@ -98,3 +100,5 @@ INSTANTIATE_TEST_CASE_P(GPU_ImgProc, CopyMakeBorder, testing::Combine( WHOLE_SUBMAT)); } // namespace + +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_core.cpp b/modules/gpu/test/test_core.cpp index 6502c4a054..09c6be1ac3 100644 --- a/modules/gpu/test/test_core.cpp +++ b/modules/gpu/test/test_core.cpp @@ -39,7 +39,9 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" + +#ifdef HAVE_CUDA namespace { @@ -3396,3 +3398,5 @@ INSTANTIATE_TEST_CASE_P(GPU_Core, Reduce, testing::Combine( WHOLE_SUBMAT)); } // namespace + +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_features2d.cpp b/modules/gpu/test/test_features2d.cpp index d8ed864eb6..b461d4b441 100644 --- a/modules/gpu/test/test_features2d.cpp +++ b/modules/gpu/test/test_features2d.cpp @@ -39,7 +39,9 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" + +#ifdef HAVE_CUDA namespace { @@ -984,3 +986,5 @@ INSTANTIATE_TEST_CASE_P(GPU_Features2D, BruteForceMatcher, testing::Combine( testing::Values(UseMask(false), UseMask(true)))); } // namespace + +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_filters.cpp b/modules/gpu/test/test_filters.cpp index 9df6ee27ca..0781970e49 100644 --- a/modules/gpu/test/test_filters.cpp +++ b/modules/gpu/test/test_filters.cpp @@ -39,7 +39,9 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" + +#ifdef HAVE_CUDA namespace { @@ -552,3 +554,5 @@ INSTANTIATE_TEST_CASE_P(GPU_Filter, Filter2D, testing::Combine( WHOLE_SUBMAT)); } // namespace + +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_global_motion.cpp b/modules/gpu/test/test_global_motion.cpp index eb8b2f7c11..b37d080684 100644 --- a/modules/gpu/test/test_global_motion.cpp +++ b/modules/gpu/test/test_global_motion.cpp @@ -39,11 +39,11 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" + +#ifdef HAVE_CUDA -#include using namespace std; - using namespace cv; struct CompactPoints : testing::TestWithParam @@ -85,3 +85,5 @@ TEST_P(CompactPoints, CanCompactizeSmallInput) } INSTANTIATE_TEST_CASE_P(GPU_GlobalMotion, CompactPoints, ALL_DEVICES); + +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_gpumat.cpp b/modules/gpu/test/test_gpumat.cpp index 4dd419a181..8627957598 100644 --- a/modules/gpu/test/test_gpumat.cpp +++ b/modules/gpu/test/test_gpumat.cpp @@ -40,7 +40,9 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" + +#ifdef HAVE_CUDA namespace { @@ -323,3 +325,5 @@ INSTANTIATE_TEST_CASE_P(GPU_GpuMat, ConvertTo, testing::Combine( WHOLE_SUBMAT)); } // namespace + +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_imgproc.cpp b/modules/gpu/test/test_imgproc.cpp index 4d67de59d3..7a616a2e4b 100644 --- a/modules/gpu/test/test_imgproc.cpp +++ b/modules/gpu/test/test_imgproc.cpp @@ -39,7 +39,9 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" + +#ifdef HAVE_CUDA namespace { @@ -1186,3 +1188,5 @@ INSTANTIATE_TEST_CASE_P(GPU_ImgProc, HoughLines, testing::Combine( std::string("../cv/shared/pic6.png")))); } // namespace + +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_labeling.cpp b/modules/gpu/test/test_labeling.cpp index c88109af19..46f6f4eeba 100644 --- a/modules/gpu/test/test_labeling.cpp +++ b/modules/gpu/test/test_labeling.cpp @@ -39,9 +39,7 @@ // the use of this software, even if advised of the possibility of such damage. //M*/ -#include "precomp.hpp" -#include -#include +#include "test_precomp.hpp" #ifdef HAVE_CUDA @@ -199,4 +197,4 @@ TEST_P(Labeling, ConnectedComponents) INSTANTIATE_TEST_CASE_P(ConnectedComponents, Labeling, ALL_DEVICES); -#endif \ No newline at end of file +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_nvidia.cpp b/modules/gpu/test/test_nvidia.cpp index 386a66cfd7..3de355744c 100644 --- a/modules/gpu/test/test_nvidia.cpp +++ b/modules/gpu/test/test_nvidia.cpp @@ -39,21 +39,15 @@ // //M*/ -#include -#include "precomp.hpp" +#include "test_precomp.hpp" + +OutputLevel nvidiaTestOutputLevel = OutputLevelCompact; #ifdef HAVE_CUDA using namespace cvtest; using namespace testing; -//enum OutputLevel -//{ -// OutputLevelNone, -// OutputLevelCompact, -// OutputLevelFull -//}; - struct NVidiaTest : TestWithParam { cv::gpu::DeviceInfo devInfo; @@ -73,8 +67,6 @@ struct NVidiaTest : TestWithParam struct NPPST : NVidiaTest {}; struct NCV : NVidiaTest {}; -OutputLevel nvidiaTestOutputLevel = OutputLevelCompact; - //TEST_P(NPPST, Integral) //{ // bool res = nvidia_NPPST_Integral_Image(path, nvidiaTestOutputLevel); diff --git a/modules/gpu/test/test_objdetect.cpp b/modules/gpu/test/test_objdetect.cpp index 927762b2b0..957ee11656 100644 --- a/modules/gpu/test/test_objdetect.cpp +++ b/modules/gpu/test/test_objdetect.cpp @@ -39,8 +39,9 @@ // //M*/ -#include "precomp.hpp" -#include +#include "test_precomp.hpp" + +#ifdef HAVE_CUDA namespace { @@ -302,13 +303,13 @@ PARAM_TEST_CASE(LBP_Read_classifier, cv::gpu::DeviceInfo, int) TEST_P(LBP_Read_classifier, Accuracy) { - cv::gpu::CascadeClassifier_GPU classifier; + cv::gpu::CascadeClassifier_GPU classifier; std::string classifierXmlPath = std::string(cvtest::TS::ptr()->get_data_path()) + "lbpcascade/lbpcascade_frontalface.xml"; ASSERT_TRUE(classifier.load(classifierXmlPath)); } -INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, LBP_Read_classifier, - testing::Combine(ALL_DEVICES, testing::Values(0))); +INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, LBP_Read_classifier, + testing::Combine(ALL_DEVICES, testing::Values(0))); PARAM_TEST_CASE(LBP_classify, cv::gpu::DeviceInfo, int) @@ -344,7 +345,7 @@ TEST_P(LBP_classify, Accuracy) for (; it != rects.end(); ++it) cv::rectangle(markedImage, *it, CV_RGB(0, 0, 255)); - cv::gpu::CascadeClassifier_GPU gpuClassifier; + cv::gpu::CascadeClassifier_GPU gpuClassifier; ASSERT_TRUE(gpuClassifier.load(classifierXmlPath)); cv::gpu::GpuMat gpu_rects; @@ -352,23 +353,25 @@ TEST_P(LBP_classify, Accuracy) int count = gpuClassifier.detectMultiScale(tested, gpu_rects); cv::Mat downloaded(gpu_rects); - const cv::Rect* faces = downloaded.ptr(); + const cv::Rect* faces = downloaded.ptr(); for (int i = 0; i < count; i++) { cv::Rect r = faces[i]; #if defined (LOG_CASCADE_STATISTIC) - std::cout << r.x << " " << r.y << " " << r.width << " " << r.height << std::endl; + std::cout << r.x << " " << r.y << " " << r.width << " " << r.height << std::endl; cv::rectangle(markedImage, r , CV_RGB(255, 0, 0)); -#endif +#endif } #if defined (LOG_CASCADE_STATISTIC) - cv::imshow("Res", markedImage); cv::waitKey(); + cv::imshow("Res", markedImage); cv::waitKey(); #endif } INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, LBP_classify, - testing::Combine(ALL_DEVICES, testing::Values(0))); + testing::Combine(ALL_DEVICES, testing::Values(0))); } // namespace + +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_precomp.cpp b/modules/gpu/test/test_precomp.cpp index dfa7246129..34acf2ae91 100644 --- a/modules/gpu/test/test_precomp.cpp +++ b/modules/gpu/test/test_precomp.cpp @@ -39,4 +39,4 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" diff --git a/modules/gpu/test/test_precomp.hpp b/modules/gpu/test/test_precomp.hpp index 753367cce8..f6933d51c6 100644 --- a/modules/gpu/test/test_precomp.hpp +++ b/modules/gpu/test/test_precomp.hpp @@ -59,6 +59,7 @@ #include #include "cvconfig.h" + #include "opencv2/core/core.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/calib3d/calib3d.hpp" @@ -72,6 +73,7 @@ #include "utility.hpp" #include "interpolation.hpp" +#include "main_test_nvidia.h" #ifdef HAVE_CUDA #include diff --git a/modules/gpu/test/test_pyramids.cpp b/modules/gpu/test/test_pyramids.cpp index d0bf37b376..1abd7841ef 100644 --- a/modules/gpu/test/test_pyramids.cpp +++ b/modules/gpu/test/test_pyramids.cpp @@ -39,7 +39,7 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" #ifdef HAVE_CUDA diff --git a/modules/gpu/test/test_remap.cpp b/modules/gpu/test/test_remap.cpp index c61a899142..b83e5db070 100644 --- a/modules/gpu/test/test_remap.cpp +++ b/modules/gpu/test/test_remap.cpp @@ -39,7 +39,7 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" #ifdef HAVE_CUDA diff --git a/modules/gpu/test/test_resize.cpp b/modules/gpu/test/test_resize.cpp index 7a7aacab17..73b8d9fab0 100644 --- a/modules/gpu/test/test_resize.cpp +++ b/modules/gpu/test/test_resize.cpp @@ -39,8 +39,7 @@ // //M*/ -#include "precomp.hpp" -#include +#include "test_precomp.hpp" #ifdef HAVE_CUDA diff --git a/modules/gpu/test/test_threshold.cpp b/modules/gpu/test/test_threshold.cpp index cb31c643b0..e878e6dfa5 100644 --- a/modules/gpu/test/test_threshold.cpp +++ b/modules/gpu/test/test_threshold.cpp @@ -39,7 +39,7 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" #ifdef HAVE_CUDA diff --git a/modules/gpu/test/test_video.cpp b/modules/gpu/test/test_video.cpp index 0ee66ba522..ca9442d697 100644 --- a/modules/gpu/test/test_video.cpp +++ b/modules/gpu/test/test_video.cpp @@ -39,7 +39,9 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" + +#ifdef HAVE_CUDA //#define DUMP @@ -865,3 +867,5 @@ TEST_P(VideoReader, Regression) INSTANTIATE_TEST_CASE_P(GPU_Video, VideoReader, testing::Combine( ALL_DEVICES, testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")))); + +#endif // HAVE_CUDA diff --git a/modules/gpu/test/test_warp_affine.cpp b/modules/gpu/test/test_warp_affine.cpp index 262937fbeb..c81fef354e 100644 --- a/modules/gpu/test/test_warp_affine.cpp +++ b/modules/gpu/test/test_warp_affine.cpp @@ -39,7 +39,7 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" #ifdef HAVE_CUDA diff --git a/modules/gpu/test/test_warp_perspective.cpp b/modules/gpu/test/test_warp_perspective.cpp index f143170150..83c170f2ef 100644 --- a/modules/gpu/test/test_warp_perspective.cpp +++ b/modules/gpu/test/test_warp_perspective.cpp @@ -39,7 +39,7 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" #ifdef HAVE_CUDA diff --git a/modules/gpu/test/utility.cpp b/modules/gpu/test/utility.cpp index 148c9d202b..cf3b0fc8cb 100644 --- a/modules/gpu/test/utility.cpp +++ b/modules/gpu/test/utility.cpp @@ -39,7 +39,7 @@ // //M*/ -#include "precomp.hpp" +#include "test_precomp.hpp" using namespace std; using namespace cv; @@ -182,105 +182,6 @@ void DeviceManager::loadAll() } } -class DevicesGenerator : public ParamGeneratorInterface -{ -public: - ~DevicesGenerator(); - - ParamIteratorInterface* Begin() const; - ParamIteratorInterface* End() const; - -private: - class Iterator : public ParamIteratorInterface - { - public: - Iterator(const ParamGeneratorInterface* base, vector::const_iterator iterator); - - virtual ~Iterator(); - - virtual const ParamGeneratorInterface* BaseGenerator() const; - - virtual void Advance(); - - virtual ParamIteratorInterface* Clone() const; - - virtual const DeviceInfo* Current() const; - - virtual bool Equals(const ParamIteratorInterface& other) const; - - private: - Iterator(const Iterator& other); - - const ParamGeneratorInterface* const base_; - vector::const_iterator iterator_; - - mutable DeviceInfo value_; - }; -}; - -DevicesGenerator::~DevicesGenerator() -{ -} - -ParamIteratorInterface* DevicesGenerator::Begin() const -{ - return new Iterator(this, DeviceManager::instance().values().begin()); -} - -ParamIteratorInterface* DevicesGenerator::End() const -{ - return new Iterator(this, DeviceManager::instance().values().end()); -} - -DevicesGenerator::Iterator::Iterator(const ParamGeneratorInterface* base, vector::const_iterator iterator) - : base_(base), iterator_(iterator) -{ -} - -DevicesGenerator::Iterator::~Iterator() -{ -} - -const ParamGeneratorInterface* DevicesGenerator::Iterator::BaseGenerator() const -{ - return base_; -} - -void DevicesGenerator::Iterator::Advance() -{ - ++iterator_; -} - -ParamIteratorInterface* DevicesGenerator::Iterator::Clone() const -{ - return new Iterator(*this); -} - -const DeviceInfo* DevicesGenerator::Iterator::Current() const -{ - value_ = *iterator_; - return &value_; -} - -bool DevicesGenerator::Iterator::Equals(const ParamIteratorInterface& other) const -{ - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << endl; - - return iterator_ == CheckedDowncastToActualType(&other)->iterator_; -} - -DevicesGenerator::Iterator::Iterator(const Iterator& other) : - ParamIteratorInterface(), base_(other.base_), iterator_(other.iterator_) -{ -} - -ParamGenerator DevicesGenerator_() -{ - return ParamGenerator(new DevicesGenerator); -} - ////////////////////////////////////////////////////////////////////// // Additional assertion diff --git a/modules/gpu/test/utility.hpp b/modules/gpu/test/utility.hpp index b36f177f6e..f509b786ad 100644 --- a/modules/gpu/test/utility.hpp +++ b/modules/gpu/test/utility.hpp @@ -94,9 +94,7 @@ private: std::vector devices_; }; -testing::internal::ParamGenerator DevicesGenerator_(); - -#define ALL_DEVICES DevicesGenerator_() +#define ALL_DEVICES testing::ValuesIn(DeviceManager::instance().values()) ////////////////////////////////////////////////////////////////////// // Additional assertion From 1e4012079d84b5f1742f539f2eae3a85254a1409 Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Mon, 20 Aug 2012 13:26:51 +0400 Subject: [PATCH 032/163] removed logging from test --- modules/gpu/test/test_labeling.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/modules/gpu/test/test_labeling.cpp b/modules/gpu/test/test_labeling.cpp index 46f6f4eeba..d32dbc1a2f 100644 --- a/modules/gpu/test/test_labeling.cpp +++ b/modules/gpu/test/test_labeling.cpp @@ -139,10 +139,9 @@ namespace { if ( (_labels.at(j,i) == gpu.at(j,i + 1)) && (diff.at(j, i) != diff.at(j,i + 1))) { outliers++; - // std::cout << j << " " << i << " " << _labels.at(j,i) << " " << gpu.at(j,i + 1) << " " << diff.at(j, i) << " " << diff.at(j,i + 1) << std::endl; } } - ASSERT_FALSE(outliers); + ASSERT_TRUE(outliers < gpu.cols + gpu.rows); } cv::Mat image; @@ -162,7 +161,7 @@ struct Labeling : testing::TestWithParam cv::Mat loat_image() { - return cv::imread(std::string( cvtest::TS::ptr()->get_data_path() ) + "labeling/IMG_0727.JPG"); + return cv::imread(std::string( cvtest::TS::ptr()->get_data_path() ) + "labeling/label.png"); } }; @@ -189,10 +188,6 @@ TEST_P(Labeling, ConnectedComponents) ASSERT_NO_THROW(cv::gpu::labelComponents(mask, components)); host.checkCorrectness(cv::Mat(components)); - cv::imshow("test", image); - cv::waitKey(0); - cv::imshow("test", host._labels); - cv::waitKey(0); } INSTANTIATE_TEST_CASE_P(ConnectedComponents, Labeling, ALL_DEVICES); From c26d543e1e5007e5566f9fd8d4d3a121c97005d3 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 20 Aug 2012 16:03:01 +0400 Subject: [PATCH 033/163] gpu::HoughLines : minor code improvements --- modules/gpu/include/opencv2/gpu/gpu.hpp | 1 + modules/gpu/perf/perf_imgproc.cpp | 2 +- modules/gpu/src/cuda/hough.cu | 123 ++++++++++++------------ modules/gpu/src/hough.cpp | 44 +++++---- modules/gpu/test/test_imgproc.cpp | 76 ++++++++------- 5 files changed, 129 insertions(+), 117 deletions(-) diff --git a/modules/gpu/include/opencv2/gpu/gpu.hpp b/modules/gpu/include/opencv2/gpu/gpu.hpp index a7f0ab32d9..c6f2e1141e 100644 --- a/modules/gpu/include/opencv2/gpu/gpu.hpp +++ b/modules/gpu/include/opencv2/gpu/gpu.hpp @@ -820,6 +820,7 @@ private: int nLayers_; }; +//! HoughLines CV_EXPORTS void HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096); CV_EXPORTS void HoughLines(const GpuMat& src, GpuMat& lines, GpuMat& accum, GpuMat& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096); CV_EXPORTS void HoughLinesTransform(const GpuMat& src, GpuMat& accum, GpuMat& buf, float rho, float theta); diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index 9104892db4..979aaa3723 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -1626,7 +1626,7 @@ PERF_TEST_P(Sz_DoSort, ImgProc_HoughLines, Combine(GPU_TYPICAL_MAT_SIZES, Bool() cv::Mat src(size, CV_8UC1, cv::Scalar::all(0)); - const int numLines = rng.uniform(500, 2000); + const int numLines = rng.uniform(100, 300); for (int i = 0; i < numLines; ++i) { cv::Point p1(rng.uniform(0, src.cols), rng.uniform(0, src.rows)); diff --git a/modules/gpu/src/cuda/hough.cu b/modules/gpu/src/cuda/hough.cu index 82bd04caad..66433aba7e 100644 --- a/modules/gpu/src/cuda/hough.cu +++ b/modules/gpu/src/cuda/hough.cu @@ -59,7 +59,7 @@ namespace cv { namespace gpu { namespace device { __shared__ int s_queues[4][32 * PIXELS_PER_THREAD]; __shared__ int s_qsize[4]; - __shared__ int s_start[4]; + __shared__ int s_globStart[4]; const int x = blockIdx.x * blockDim.x * PIXELS_PER_THREAD + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -73,9 +73,10 @@ namespace cv { namespace gpu { namespace device __syncthreads(); // fill the queue + const uchar* srcRow = src.ptr(y); for (int i = 0, xx = x; i < PIXELS_PER_THREAD && xx < src.cols; ++i, xx += blockDim.x) { - if (src(y, xx)) + if (srcRow[xx]) { const unsigned int val = (y << 16) | xx; const int qidx = Emulation::smem::atomicAdd(&s_qsize[threadIdx.y], 1); @@ -89,36 +90,34 @@ namespace cv { namespace gpu { namespace device if (threadIdx.x == 0 && threadIdx.y == 0) { // find how many items are stored in each list - int total_size = 0; + int totalSize = 0; for (int i = 0; i < blockDim.y; ++i) { - s_start[i] = total_size; - total_size += s_qsize[i]; + s_globStart[i] = totalSize; + totalSize += s_qsize[i]; } // calculate the offset in the global list - const int global_offset = atomicAdd(&g_counter, total_size); + const int globalOffset = atomicAdd(&g_counter, totalSize); for (int i = 0; i < blockDim.y; ++i) - s_start[i] += global_offset; + s_globStart[i] += globalOffset; } __syncthreads(); // copy local queues to global queue const int qsize = s_qsize[threadIdx.y]; - for(int i = threadIdx.x; i < qsize; i += blockDim.x) - { - const unsigned int val = s_queues[threadIdx.y][i]; - list[s_start[threadIdx.y] + i] = val; - } + int gidx = s_globStart[threadIdx.y] + threadIdx.x; + for(int i = threadIdx.x; i < qsize; i += blockDim.x, gidx += blockDim.x) + list[gidx] = s_queues[threadIdx.y][i]; } int buildPointList_gpu(DevMem2Db src, unsigned int* list) { - void* counter_ptr; - cudaSafeCall( cudaGetSymbolAddress(&counter_ptr, g_counter) ); + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - cudaSafeCall( cudaMemset(counter_ptr, 0, sizeof(int)) ); + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); const dim3 block(32, 4); const dim3 grid(divUp(src.cols, block.x * PIXELS_PER_THREAD), divUp(src.rows, block.y)); @@ -130,10 +129,10 @@ namespace cv { namespace gpu { namespace device cudaSafeCall( cudaDeviceSynchronize() ); - int total_count; - cudaSafeCall( cudaMemcpy(&total_count, counter_ptr, sizeof(int), cudaMemcpyDeviceToHost) ); + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - return total_count; + return totalCount; } //////////////////////////////////////////////////////////////////////// @@ -144,24 +143,26 @@ namespace cv { namespace gpu { namespace device const int n = blockIdx.x; const float ang = n * theta; - float sin_ang; - float cos_ang; - sincosf(ang, &sin_ang, &cos_ang); + float sinVal; + float cosVal; + sincosf(ang, &sinVal, &cosVal); + sinVal *= irho; + cosVal *= irho; - const float tabSin = sin_ang * irho; - const float tabCos = cos_ang * irho; + const int shift = (numrho - 1) / 2; + int* accumRow = accum.ptr(n + 1); for (int i = threadIdx.x; i < count; i += blockDim.x) { - const unsigned int qvalue = list[i]; + const unsigned int val = list[i]; - const int x = (qvalue & 0x0000FFFF); - const int y = (qvalue >> 16) & 0x0000FFFF; + const int x = (val & 0xFFFF); + const int y = (val >> 16) & 0xFFFF; - int r = __float2int_rn(x * tabCos + y * tabSin); - r += (numrho - 1) / 2; + int r = __float2int_rn(x * cosVal + y * sinVal); + r += shift; - ::atomicAdd(accum.ptr(n + 1) + r + 1, 1); + ::atomicAdd(accumRow + r + 1, 1); } } @@ -177,30 +178,32 @@ namespace cv { namespace gpu { namespace device const int n = blockIdx.x; const float ang = n * theta; - float sin_ang; - float cos_ang; - sincosf(ang, &sin_ang, &cos_ang); + float sinVal; + float cosVal; + sincosf(ang, &sinVal, &cosVal); + sinVal *= irho; + cosVal *= irho; - const float tabSin = sin_ang * irho; - const float tabCos = cos_ang * irho; + const int shift = (numrho - 1) / 2; for (int i = threadIdx.x; i < count; i += blockDim.x) { - const unsigned int qvalue = list[i]; + const unsigned int val = list[i]; - const int x = (qvalue & 0x0000FFFF); - const int y = (qvalue >> 16) & 0x0000FFFF; + const int x = (val & 0xFFFF); + const int y = (val >> 16) & 0xFFFF; - int r = __float2int_rn(x * tabCos + y * tabSin); - r += (numrho - 1) / 2; + int r = __float2int_rn(x * cosVal + y * sinVal); + r += shift; Emulation::smem::atomicAdd(&smem[r + 1], 1); } __syncthreads(); - for (int i = threadIdx.x; i < numrho; i += blockDim.x) - accum(n + 1, i) = smem[i]; + int* accumRow = accum.ptr(n + 1); + for (int i = threadIdx.x; i < numrho + 1; i += blockDim.x) + accumRow[i] = smem[i]; } void linesAccum_gpu(const unsigned int* list, int count, DevMem2Di accum, float rho, float theta, size_t sharedMemPerBlock, bool has20) @@ -225,21 +228,21 @@ namespace cv { namespace gpu { namespace device //////////////////////////////////////////////////////////////////////// // linesGetResult - __global__ void linesGetResult(const DevMem2Di accum, float2* out, int* votes, const int maxSize, const float threshold, const float theta, const float rho, const int numrho) + __global__ void linesGetResult(const DevMem2Di accum, float2* out, int* votes, const int maxSize, const float rho, const float theta, const float threshold, const int numrho) { __shared__ int smem[8][32]; - int r = blockIdx.x * (blockDim.x - 2) + threadIdx.x; - int n = blockIdx.y * (blockDim.y - 2) + threadIdx.y; + const int x = blockIdx.x * (blockDim.x - 2) + threadIdx.x; + const int y = blockIdx.y * (blockDim.y - 2) + threadIdx.y; - if (r >= accum.cols || n >= accum.rows) + if (x >= accum.cols || y >= accum.rows) return; - smem[threadIdx.y][threadIdx.x] = accum(n, r); + smem[threadIdx.y][threadIdx.x] = accum(y, x); __syncthreads(); - r -= 1; - n -= 1; + const int r = x - 1; + const int n = y - 1; if (threadIdx.x == 0 || threadIdx.x == blockDim.x - 1 || threadIdx.y == 0 || threadIdx.y == blockDim.y - 1 || r >= accum.cols - 2 || n >= accum.rows - 2) return; @@ -264,32 +267,32 @@ namespace cv { namespace gpu { namespace device int linesGetResult_gpu(DevMem2Di accum, float2* out, int* votes, int maxSize, float rho, float theta, float threshold, bool doSort) { - void* counter_ptr; - cudaSafeCall( cudaGetSymbolAddress(&counter_ptr, g_counter) ); + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - cudaSafeCall( cudaMemset(counter_ptr, 0, sizeof(int)) ); + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); const dim3 block(32, 8); const dim3 grid(divUp(accum.cols, block.x - 2), divUp(accum.rows, block.y - 2)); - linesGetResult<<>>(accum, out, votes, maxSize, threshold, theta, rho, accum.cols - 2); + linesGetResult<<>>(accum, out, votes, maxSize, rho, theta, threshold, accum.cols - 2); cudaSafeCall( cudaGetLastError() ); cudaSafeCall( cudaDeviceSynchronize() ); - int total_count; - cudaSafeCall( cudaMemcpy(&total_count, counter_ptr, sizeof(int), cudaMemcpyDeviceToHost) ); + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - total_count = ::min(total_count, maxSize); + totalCount = ::min(totalCount, maxSize); - if (doSort && total_count > 0) + if (doSort && totalCount > 0) { - thrust::device_ptr out_ptr(out); - thrust::device_ptr votes_ptr(votes); - thrust::sort_by_key(votes_ptr, votes_ptr + total_count, out_ptr, thrust::greater()); + thrust::device_ptr outPtr(out); + thrust::device_ptr votesPtr(votes); + thrust::sort_by_key(votesPtr, votesPtr + totalCount, outPtr, thrust::greater()); } - return total_count; + return totalCount; } } }}} diff --git a/modules/gpu/src/hough.cpp b/modules/gpu/src/hough.cpp index ba61ad78c8..3b683ff40c 100644 --- a/modules/gpu/src/hough.cpp +++ b/modules/gpu/src/hough.cpp @@ -57,11 +57,27 @@ namespace cv { namespace gpu { namespace device namespace hough { int buildPointList_gpu(DevMem2Db src, unsigned int* list); + void linesAccum_gpu(const unsigned int* list, int count, DevMem2Di accum, float rho, float theta, size_t sharedMemPerBlock, bool has20); int linesGetResult_gpu(DevMem2Di accum, float2* out, int* votes, int maxSize, float rho, float theta, float threshold, bool doSort); } }}} +////////////////////////////////////////////////////////// +// HoughLines + +void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort, int maxLines) +{ + GpuMat accum, buf; + HoughLines(src, lines, accum, buf, rho, theta, threshold, doSort, maxLines); +} + +void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, GpuMat& accum, GpuMat& buf, float rho, float theta, int threshold, bool doSort, int maxLines) +{ + HoughLinesTransform(src, accum, buf, rho, theta); + HoughLinesGet(accum, lines, rho, theta, threshold, doSort, maxLines); +} + void cv::gpu::HoughLinesTransform(const GpuMat& src, GpuMat& accum, GpuMat& buf, float rho, float theta) { using namespace cv::gpu::device::hough; @@ -80,23 +96,23 @@ void cv::gpu::HoughLinesTransform(const GpuMat& src, GpuMat& accum, GpuMat& buf, CV_Assert(numangle > 0 && numrho > 0); ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, accum); - accum.setTo(cv::Scalar::all(0)); + accum.setTo(Scalar::all(0)); - cv::gpu::DeviceInfo devInfo; + DeviceInfo devInfo; if (count > 0) - linesAccum_gpu(buf.ptr(), count, accum, rho, theta, devInfo.sharedMemPerBlock(), devInfo.supports(cv::gpu::FEATURE_SET_COMPUTE_20)); + linesAccum_gpu(buf.ptr(), count, accum, rho, theta, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); } void cv::gpu::HoughLinesGet(const GpuMat& accum, GpuMat& lines, float rho, float theta, int threshold, bool doSort, int maxLines) { - using namespace cv::gpu::device; + using namespace cv::gpu::device::hough; CV_Assert(accum.type() == CV_32SC1); ensureSizeIsEnough(2, maxLines, CV_32FC2, lines); - int count = hough::linesGetResult_gpu(accum, lines.ptr(0), lines.ptr(1), maxLines, rho, theta, threshold, doSort); + int count = linesGetResult_gpu(accum, lines.ptr(0), lines.ptr(1), maxLines, rho, theta, threshold, doSort); if (count > 0) lines.cols = count; @@ -104,18 +120,6 @@ void cv::gpu::HoughLinesGet(const GpuMat& accum, GpuMat& lines, float rho, float lines.release(); } -void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort, int maxLines) -{ - cv::gpu::GpuMat accum, buf; - HoughLines(src, lines, accum, buf, rho, theta, threshold, doSort, maxLines); -} - -void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, GpuMat& accum, GpuMat& buf, float rho, float theta, int threshold, bool doSort, int maxLines) -{ - HoughLinesTransform(src, accum, buf, rho, theta); - HoughLinesGet(accum, lines, rho, theta, threshold, doSort, maxLines); -} - void cv::gpu::HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines_, OutputArray h_votes_) { if (d_lines.empty()) @@ -129,14 +133,14 @@ void cv::gpu::HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines_, Ou CV_Assert(d_lines.rows == 2 && d_lines.type() == CV_32FC2); h_lines_.create(1, d_lines.cols, CV_32FC2); - cv::Mat h_lines = h_lines_.getMat(); + Mat h_lines = h_lines_.getMat(); d_lines.row(0).download(h_lines); if (h_votes_.needed()) { h_votes_.create(1, d_lines.cols, CV_32SC1); - cv::Mat h_votes = h_votes_.getMat(); - cv::gpu::GpuMat d_votes(1, d_lines.cols, CV_32SC1, const_cast(d_lines.ptr(1))); + Mat h_votes = h_votes_.getMat(); + GpuMat d_votes(1, d_lines.cols, CV_32SC1, const_cast(d_lines.ptr(1))); d_votes.download(h_votes); } } diff --git a/modules/gpu/test/test_imgproc.cpp b/modules/gpu/test/test_imgproc.cpp index 4f402da16d..06662d8d2e 100644 --- a/modules/gpu/test/test_imgproc.cpp +++ b/modules/gpu/test/test_imgproc.cpp @@ -1129,63 +1129,67 @@ INSTANTIATE_TEST_CASE_P(GPU_ImgProc, CornerMinEigen, testing::Combine( /////////////////////////////////////////////////////////////////////////////////////////////////////// // HoughLines -PARAM_TEST_CASE(HoughLines, cv::gpu::DeviceInfo, std::string) +PARAM_TEST_CASE(HoughLines, cv::gpu::DeviceInfo, cv::Size, UseRoi) { -}; - -void drawLines(cv::Mat& dst, const std::vector& lines) -{ - for (size_t i = 0; i < lines.size(); ++i) + void generateLines(cv::Mat& img) { - float rho = lines[i][0], theta = lines[i][1]; - cv::Point pt1, pt2; - double a = std::cos(theta), b = std::sin(theta); - double x0 = a*rho, y0 = b*rho; - pt1.x = cvRound(x0 + 1000*(-b)); - pt1.y = cvRound(y0 + 1000*(a)); - pt2.x = cvRound(x0 - 1000*(-b)); - pt2.y = cvRound(y0 - 1000*(a)); - cv::line(dst, pt1, pt2, cv::Scalar::all(255)); + img.setTo(cv::Scalar::all(0)); + + cv::line(img, cv::Point(20, 0), cv::Point(20, img.rows), cv::Scalar::all(255)); + cv::line(img, cv::Point(0, 50), cv::Point(img.cols, 50), cv::Scalar::all(255)); + cv::line(img, cv::Point(0, 0), cv::Point(img.cols, img.rows), cv::Scalar::all(255)); + cv::line(img, cv::Point(img.cols, 0), cv::Point(0, img.rows), cv::Scalar::all(255)); } -} + + void drawLines(cv::Mat& dst, const std::vector& lines) + { + dst.setTo(cv::Scalar::all(0)); + + for (size_t i = 0; i < lines.size(); ++i) + { + float rho = lines[i][0], theta = lines[i][1]; + cv::Point pt1, pt2; + double a = std::cos(theta), b = std::sin(theta); + double x0 = a*rho, y0 = b*rho; + pt1.x = cvRound(x0 + 1000*(-b)); + pt1.y = cvRound(y0 + 1000*(a)); + pt2.x = cvRound(x0 - 1000*(-b)); + pt2.y = cvRound(y0 - 1000*(a)); + cv::line(dst, pt1, pt2, cv::Scalar::all(255)); + } + } +}; TEST_P(HoughLines, Accuracy) { const cv::gpu::DeviceInfo devInfo = GET_PARAM(0); cv::gpu::setDevice(devInfo.deviceID()); - const std::string fileName = GET_PARAM(1); + const cv::Size size = GET_PARAM(1); + const bool useRoi = GET_PARAM(2); const float rho = 1.0f; - const float theta = static_cast(CV_PI / 180); - const int threshold = 50; + const float theta = 1.5f * CV_PI / 180.0f; + const int threshold = 100; - cv::Mat img = readImage(fileName, cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - cv::Mat edges; - cv::Canny(img, edges, 50, 200); + cv::Mat src(size, CV_8UC1); + generateLines(src); cv::gpu::GpuMat d_lines; - cv::gpu::HoughLines(loadMat(edges), d_lines, rho, theta, threshold); + cv::gpu::HoughLines(loadMat(src, useRoi), d_lines, rho, theta, threshold); + std::vector lines; cv::gpu::HoughLinesDownload(d_lines, lines); - cv::Mat dst(img.size(), CV_8UC1, cv::Scalar::all(0)); + + cv::Mat dst(size, CV_8UC1); drawLines(dst, lines); - std::vector lines_gold; - cv::HoughLines(edges, lines_gold, rho, theta, threshold); - cv::Mat dst_gold(img.size(), CV_8UC1, cv::Scalar::all(0)); - drawLines(dst_gold, lines_gold); - - ASSERT_MAT_NEAR(dst_gold, dst, 0.0); + ASSERT_MAT_NEAR(src, dst, 0.0); } INSTANTIATE_TEST_CASE_P(GPU_ImgProc, HoughLines, testing::Combine( ALL_DEVICES, - testing::Values(std::string("../cv/shared/pic1.png"), - std::string("../cv/shared/pic3.png"), - std::string("../cv/shared/pic5.png"), - std::string("../cv/shared/pic6.png")))); + DIFFERENT_SIZES, + WHOLE_SUBMAT)); } // namespace From 8efb84b5a4cc98c6e3b1266923e744e6032ed52f Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Mon, 20 Aug 2012 19:36:36 +0400 Subject: [PATCH 034/163] added ios camera support in highgui. turned on optimization in opencv2.framework (ticket #2232) --- ios/cmake/Modules/Platform/iOS.cmake | 2 + modules/core/include/opencv2/core/core.hpp | 2 +- modules/highgui/CMakeLists.txt | 6 + .../highgui/include/opencv2/highgui/cap_ios.h | 160 +++++ .../highgui/src/cap_ios_abstract_camera.mm | 408 +++++++++++ modules/highgui/src/cap_ios_photo_camera.mm | 165 +++++ modules/highgui/src/cap_ios_video_camera.mm | 656 ++++++++++++++++++ 7 files changed, 1398 insertions(+), 1 deletion(-) create mode 100644 modules/highgui/include/opencv2/highgui/cap_ios.h create mode 100644 modules/highgui/src/cap_ios_abstract_camera.mm create mode 100644 modules/highgui/src/cap_ios_photo_camera.mm create mode 100644 modules/highgui/src/cap_ios_video_camera.mm diff --git a/ios/cmake/Modules/Platform/iOS.cmake b/ios/cmake/Modules/Platform/iOS.cmake index c657b800fb..e8389798bb 100644 --- a/ios/cmake/Modules/Platform/iOS.cmake +++ b/ios/cmake/Modules/Platform/iOS.cmake @@ -42,6 +42,8 @@ set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") set (CMAKE_C_FLAGS "") set (CMAKE_CXX_FLAGS "-headerpad_max_install_names -fvisibility=hidden -fvisibility-inlines-hidden") +set (CMAKE_CXX_FLAGS_RELEASE "-O3 -fomit-frame-pointer") + if (HAVE_FLAG_SEARCH_PATHS_FIRST) set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index fbaf13721f..5fd9272135 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -440,7 +440,7 @@ template class CV_EXPORTS Matx { public: typedef _Tp value_type; - typedef Matx<_Tp, MIN(m, n), 1> diag_type; + typedef Matx<_Tp, (m < n ? m : n), 1> diag_type; typedef Matx<_Tp, m, n> mat_type; enum { depth = DataDepth<_Tp>::value, rows = m, cols = n, channels = rows*cols, type = CV_MAKETYPE(depth, channels) }; diff --git a/modules/highgui/CMakeLists.txt b/modules/highgui/CMakeLists.txt index 6b9341b32e..d53c17c40f 100644 --- a/modules/highgui/CMakeLists.txt +++ b/modules/highgui/CMakeLists.txt @@ -193,6 +193,12 @@ elseif(APPLE) endif() endif() +if(IOS) + add_definitions(-DHAVE_IOS=1) + list(APPEND highgui_srcs src/cap_ios_abstract_camera.mm src/cap_ios_photo_camera.mm src/cap_ios_video_camera.mm) + list(APPEND HIGHGUI_LIBRARIES "-framework Accelerate" "-framework AVFoundation" "-framework CoreGraphics" "-framework CoreImage" "-framework CoreMedia" "-framework CoreVideo" "-framework QuartzCore" "-framework AssetsLibrary") +endif() + if(WIN32) link_directories("${OpenCV_SOURCE_DIR}/3rdparty/lib") # for ffmpeg wrapper only include_directories(AFTER SYSTEM "${OpenCV_SOURCE_DIR}/3rdparty/include") # for directshow in VS2005 and multi-monitor support on MinGW diff --git a/modules/highgui/include/opencv2/highgui/cap_ios.h b/modules/highgui/include/opencv2/highgui/cap_ios.h new file mode 100644 index 0000000000..cc6668ace0 --- /dev/null +++ b/modules/highgui/include/opencv2/highgui/cap_ios.h @@ -0,0 +1,160 @@ +/* + * cap_ios.h + * For iOS video I/O + * by Eduard Feicho on 29/07/12 + * Copyright 2012. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import +#import +#import +#import +#include "opencv2/core/core.hpp" + +/////////////////////////////////////// CvAbstractCamera ///////////////////////////////////// + +@class CvAbstractCamera; + +@interface CvAbstractCamera : NSObject +{ + AVCaptureSession* captureSession; + AVCaptureConnection* videoCaptureConnection; + AVCaptureVideoPreviewLayer *captureVideoPreviewLayer; + + UIDeviceOrientation currentDeviceOrientation; + + BOOL cameraAvailable; + BOOL captureSessionLoaded; + BOOL running; + BOOL useAVCaptureVideoPreviewLayer; + + AVCaptureDevicePosition defaultAVCaptureDevicePosition; + AVCaptureVideoOrientation defaultAVCaptureVideoOrientation; + NSString *const defaultAVCaptureSessionPreset; + + int defaultFPS; + + UIView* parentView; + + int imageWidth; + int imageHeight; +} + +@property (nonatomic, retain) AVCaptureSession* captureSession; +@property (nonatomic, retain) AVCaptureConnection* videoCaptureConnection; + +@property (nonatomic, readonly) BOOL running; +@property (nonatomic, readonly) BOOL captureSessionLoaded; + +@property (nonatomic, assign) int defaultFPS; +@property (nonatomic, assign) AVCaptureDevicePosition defaultAVCaptureDevicePosition; +@property (nonatomic, assign) AVCaptureVideoOrientation defaultAVCaptureVideoOrientation; +@property (nonatomic, assign) BOOL useAVCaptureVideoPreviewLayer; +@property (nonatomic, strong) NSString *const defaultAVCaptureSessionPreset; + +@property (nonatomic, assign) int imageWidth; +@property (nonatomic, assign) int imageHeight; + +@property (nonatomic, retain) UIView* parentView; + +- (void)pause; +- (void)start; +- (void)stop; +- (void)switchCameras; + +- (id)initWithParentView:(UIView*)parent; + +- (void)createCaptureOutput; +- (void)createVideoPreviewLayer; +- (void)updateOrientation; + + +@end + +///////////////////////////////// CvVideoCamera /////////////////////////////////////////// + +@class CvVideoCamera; + +@protocol CvVideoCameraDelegate + +#ifdef __cplusplus +// delegate method for processing image frames +- (void)processImage:(cv::Mat&)image; +#endif + +@end + +@interface CvVideoCamera : CvAbstractCamera +{ + AVCaptureVideoDataOutput *videoDataOutput; + + dispatch_queue_t videoDataOutputQueue; + CALayer *customPreviewLayer; + + BOOL grayscaleMode; + + BOOL recordVideo; + AVAssetWriterInput* recordAssetWriterInput; + AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; + AVAssetWriter* recordAssetWriter; + +} + +@property (nonatomic, assign) id delegate; +@property (nonatomic, assign) BOOL grayscaleMode; + +@property (nonatomic, assign) BOOL recordVideo; +@property (nonatomic, retain) AVAssetWriterInput* recordAssetWriterInput; +@property (nonatomic, retain) AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; +@property (nonatomic, retain) AVAssetWriter* recordAssetWriter; + +- (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; +- (void)layoutPreviewLayer; +- (void)saveVideo; + +@end + +///////////////////////////////// CvPhotoCamera /////////////////////////////////////////// + +@class CvPhotoCamera; + +@protocol CvPhotoCameraDelegate + +- (void)photoCamera:(CvPhotoCamera*)photoCamera capturedImage:(UIImage *)image; +- (void)photoCameraCancel:(CvPhotoCamera*)photoCamera; + +@end + +@interface CvPhotoCamera : CvAbstractCamera +{ + AVCaptureStillImageOutput *stillImageOutput; +} + +@property (nonatomic, assign) id delegate; + +- (void)takePicture; + +@end diff --git a/modules/highgui/src/cap_ios_abstract_camera.mm b/modules/highgui/src/cap_ios_abstract_camera.mm new file mode 100644 index 0000000000..45b53b018a --- /dev/null +++ b/modules/highgui/src/cap_ios_abstract_camera.mm @@ -0,0 +1,408 @@ +/* + * cap_ios_abstract_camera.mm + * For iOS video I/O + * by Eduard Feicho on 29/07/12 + * Copyright 2012. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#import "opencv2/highgui/cap_ios.h" +#include "precomp.hpp" + +#pragma mark - Private Interface + +@interface CvAbstractCamera () + +@property (nonatomic, retain) AVCaptureVideoPreviewLayer* captureVideoPreviewLayer; + +- (void)deviceOrientationDidChange:(NSNotification*)notification; +- (void)startCaptureSession; + +- (void)setDesiredCameraPosition:(AVCaptureDevicePosition)desiredPosition; + +- (void)updateSize; + +@end + + +#pragma mark - Implementation + + +@implementation CvAbstractCamera + + + +#pragma mark Public + +@synthesize imageWidth; +@synthesize imageHeight; + + +@synthesize defaultFPS; +@synthesize defaultAVCaptureDevicePosition; +@synthesize defaultAVCaptureVideoOrientation; +@synthesize defaultAVCaptureSessionPreset; + + + +@synthesize captureSession; +@synthesize captureVideoPreviewLayer; +@synthesize videoCaptureConnection; +@synthesize running; +@synthesize captureSessionLoaded; +@synthesize useAVCaptureVideoPreviewLayer; + +@synthesize parentView; + +#pragma mark - Constructors + +- (id)init; +{ + self = [super init]; + if (self) { + // react to device orientation notifications + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(deviceOrientationDidChange:) + name:UIDeviceOrientationDidChangeNotification + object:nil]; + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + currentDeviceOrientation = [[UIDevice currentDevice] orientation]; + + + // check if camera available + cameraAvailable = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]; + NSLog(@"camera available: %@", (cameraAvailable == YES ? @"YES" : @"NO") ); + + running = NO; + + // set camera default configuration + self.defaultAVCaptureDevicePosition = AVCaptureDevicePositionFront; + self.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationLandscapeLeft; + self.defaultFPS = 15; + self.defaultAVCaptureSessionPreset = AVCaptureSessionPreset352x288; + + self.parentView = nil; + self.useAVCaptureVideoPreviewLayer = NO; + } + return self; +} + + + +- (id)initWithParentView:(UIView*)parent; +{ + self = [super init]; + if (self) { + // react to device orientation notifications + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(deviceOrientationDidChange:) + name:UIDeviceOrientationDidChangeNotification + object:nil]; + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + currentDeviceOrientation = [[UIDevice currentDevice] orientation]; + + + // check if camera available + cameraAvailable = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]; + NSLog(@"camera available: %@", (cameraAvailable == YES ? @"YES" : @"NO") ); + + running = NO; + + // set camera default configuration + self.defaultAVCaptureDevicePosition = AVCaptureDevicePositionFront; + self.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationLandscapeLeft; + self.defaultFPS = 15; + self.defaultAVCaptureSessionPreset = AVCaptureSessionPreset640x480; + + self.parentView = parent; + self.useAVCaptureVideoPreviewLayer = YES; + } + return self; +} + + + +- (void)dealloc; +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; +} + + +#pragma mark - Public interface + + +- (void)start; +{ + if (![NSThread isMainThread]) { + NSLog(@"[Camera] Warning: Call start only from main thread"); + [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO]; + return; + } + + if (running == YES) { + return; + } + running = YES; + + // TOOD update image size data before actually starting (needed for recording) + [self updateSize]; + + if (cameraAvailable) { + [self startCaptureSession]; + } +} + + +- (void)pause; +{ + running = NO; + [self.captureSession stopRunning]; +} + + + +- (void)stop; +{ + running = NO; + + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; + + [self.captureSession stopRunning]; + self.captureSession = nil; + self.captureVideoPreviewLayer = nil; + self.videoCaptureConnection = nil; + captureSessionLoaded = NO; +} + + + +// use front/back camera +- (void)switchCameras; +{ + BOOL was_running = self.running; + if (was_running) { + [self stop]; + } + if (self.defaultAVCaptureDevicePosition == AVCaptureDevicePositionFront) { + self.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack; + } else { + self.defaultAVCaptureDevicePosition = AVCaptureDevicePositionFront; + } + if (was_running) { + [self start]; + } +} + + + +#pragma mark - Device Orientation Changes + + +- (void)deviceOrientationDidChange:(NSNotification*)notification +{ + UIDeviceOrientation orientation = [UIDevice currentDevice].orientation; + + switch (orientation) + { + case UIDeviceOrientationPortrait: + case UIDeviceOrientationPortraitUpsideDown: + case UIDeviceOrientationLandscapeLeft: + case UIDeviceOrientationLandscapeRight: + currentDeviceOrientation = orientation; + break; + + case UIDeviceOrientationFaceUp: + case UIDeviceOrientationFaceDown: + default: + break; + } + NSLog(@"deviceOrientationDidChange: %d", orientation); + + [self updateOrientation]; +} + + + +#pragma mark - Private Interface + +- (void)createCaptureSession; +{ + // set a av capture session preset + self.captureSession = [[AVCaptureSession alloc] init]; + if ([self.captureSession canSetSessionPreset:self.defaultAVCaptureSessionPreset]) { + [self.captureSession setSessionPreset:self.defaultAVCaptureSessionPreset]; + } else if ([self.captureSession canSetSessionPreset:AVCaptureSessionPresetLow]) { + [self.captureSession setSessionPreset:AVCaptureSessionPresetLow]; + } else { + NSLog(@"[Camera] Error: could not set session preset"); + } +} + +- (void)createCaptureDevice; +{ + // setup the device + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + [self setDesiredCameraPosition:self.defaultAVCaptureDevicePosition]; + NSLog(@"[Camera] device connected? %@", device.connected ? @"YES" : @"NO"); + NSLog(@"[Camera] device position %@", (device.position == AVCaptureDevicePositionBack) ? @"back" : @"front"); +} + + +- (void)createVideoPreviewLayer; +{ + self.captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession]; + + if ([self.captureVideoPreviewLayer isOrientationSupported]) { + [self.captureVideoPreviewLayer setOrientation:self.defaultAVCaptureVideoOrientation]; + } + + if (parentView != nil) { + self.captureVideoPreviewLayer.frame = self.parentView.bounds; + self.captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; + [self.parentView.layer addSublayer:self.captureVideoPreviewLayer]; + } + NSLog(@"[Camera] created AVCaptureVideoPreviewLayer"); +} + + + + +- (void)setDesiredCameraPosition:(AVCaptureDevicePosition)desiredPosition; +{ + for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { + if ([device position] == desiredPosition) { + [self.captureSession beginConfiguration]; + + NSError* error; + AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error]; + if (!input) { + NSLog(@"error creating input %@", [error localizedDescription]); + } + + // support for autofocus + if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) { + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + device.focusMode = AVCaptureFocusModeContinuousAutoFocus; + [device unlockForConfiguration]; + } else { + NSLog(@"unable to lock device for autofocos configuration %@", [error localizedDescription]); + } + } + [self.captureSession addInput:input]; + + for (AVCaptureInput *oldInput in self.captureSession.inputs) { + [self.captureSession removeInput:oldInput]; + } + [self.captureSession addInput:input]; + [self.captureSession commitConfiguration]; + + break; + } + } +} + + + +- (void)startCaptureSession +{ + if (!cameraAvailable) { + return; + } + + if (self.captureSessionLoaded == NO) { + [self createCaptureSession]; + [self createCaptureDevice]; + [self createCaptureOutput]; + + // setup preview layer + if (self.useAVCaptureVideoPreviewLayer) { + [self createVideoPreviewLayer]; + } else { + [self createCustomVideoPreview]; + } + + captureSessionLoaded = YES; + } + + [self.captureSession startRunning]; +} + + +- (void)createCaptureOutput; +{ + [NSException raise:NSInternalInconsistencyException + format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]; +} + +- (void)createCustomVideoPreview; +{ + [NSException raise:NSInternalInconsistencyException + format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]; +} + +- (void)updateOrientation; +{ + // nothing to do here +} + + +- (void)updateSize; +{ + if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPresetPhoto]) { + //TODO: find the correct resolution + self.imageWidth = 640; + self.imageHeight = 480; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPresetHigh]) { + //TODO: find the correct resolution + self.imageWidth = 640; + self.imageHeight = 480; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPresetMedium]) { + //TODO: find the correct resolution + self.imageWidth = 640; + self.imageHeight = 480; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPresetLow]) { + //TODO: find the correct resolution + self.imageWidth = 640; + self.imageHeight = 480; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPreset352x288]) { + self.imageWidth = 352; + self.imageHeight = 288; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPreset640x480]) { + self.imageWidth = 640; + self.imageHeight = 480; + } else if ([self.defaultAVCaptureSessionPreset isEqualToString:AVCaptureSessionPreset1280x720]) { + self.imageWidth = 1280; + self.imageHeight = 720; + } else { + self.imageWidth = 640; + self.imageHeight = 480; + } +} + +@end diff --git a/modules/highgui/src/cap_ios_photo_camera.mm b/modules/highgui/src/cap_ios_photo_camera.mm new file mode 100644 index 0000000000..51e5ce2299 --- /dev/null +++ b/modules/highgui/src/cap_ios_photo_camera.mm @@ -0,0 +1,165 @@ +/* + * cap_ios_photo_camera.mm + * For iOS video I/O + * by Eduard Feicho on 29/07/12 + * Copyright 2012. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#import "opencv2/highgui/cap_ios.h" +#include "precomp.hpp" + +#pragma mark - Private Interface + + +@interface CvPhotoCamera () + +@property (nonatomic, retain) AVCaptureStillImageOutput* stillImageOutput; + +@end + + + +#pragma mark - Implementation + + +@implementation CvPhotoCamera + + + +#pragma mark Public + +@synthesize stillImageOutput; +@synthesize delegate; + + +#pragma mark - Public interface + + +- (void)takePicture +{ + if (cameraAvailable == NO) { + return; + } + cameraAvailable = NO; + + + [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:self.videoCaptureConnection + completionHandler: + ^(CMSampleBufferRef imageSampleBuffer, NSError *error) + { + if (error == nil && imageSampleBuffer != NULL) + { + // TODO check + // NSNumber* imageOrientation = [UIImage cgImageOrientationForUIDeviceOrientation:currentDeviceOrientation]; + // CMSetAttachment(imageSampleBuffer, kCGImagePropertyOrientation, imageOrientation, 1); + + NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.captureSession stopRunning]; + + // Make sure we create objects on the main thread in the main context + UIImage* newImage = [UIImage imageWithData:jpegData]; + + //UIImageOrientation orientation = [newImage imageOrientation]; + + // TODO: only apply rotation, don't scale, since we can set this directly in the camera + /* + switch (orientation) { + case UIImageOrientationUp: + case UIImageOrientationDown: + newImage = [newImage imageWithAppliedRotationAndMaxSize:CGSizeMake(640.0, 480.0)]; + break; + case UIImageOrientationLeft: + case UIImageOrientationRight: + newImage = [newImage imageWithMaxSize:CGSizeMake(640.0, 480.0)]; + default: + break; + } + */ + + // We have captured the image, we can allow the user to take another picture + cameraAvailable = YES; + + NSLog(@"CvPhotoCamera captured image"); + if (self.delegate) { + [self.delegate photoCamera:self capturedImage:newImage]; + } + + [self.captureSession startRunning]; + }); + } + }]; + + +} + +- (void)stop; +{ + [super stop]; + self.stillImageOutput = nil; +} + + +#pragma mark - Private Interface + + +- (void)createStillImageOutput; +{ + // setup still image output with jpeg codec + self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; + NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil]; + [self.stillImageOutput setOutputSettings:outputSettings]; + [self.captureSession addOutput:self.stillImageOutput]; + + for (AVCaptureConnection *connection in self.stillImageOutput.connections) { + for (AVCaptureInputPort *port in [connection inputPorts]) { + if ([port.mediaType isEqual:AVMediaTypeVideo]) { + self.videoCaptureConnection = connection; + break; + } + } + if (self.videoCaptureConnection) { + break; + } + } + NSLog(@"[Camera] still image output created"); +} + + +- (void)createCaptureOutput; +{ + [self createStillImageOutput]; +} + +- (void)createCustomVideoPreview; +{ + //do nothing, always use AVCaptureVideoPreviewLayer +} + + +@end diff --git a/modules/highgui/src/cap_ios_video_camera.mm b/modules/highgui/src/cap_ios_video_camera.mm new file mode 100644 index 0000000000..bed17e1882 --- /dev/null +++ b/modules/highgui/src/cap_ios_video_camera.mm @@ -0,0 +1,656 @@ +/* + * cap_ios_video_camera.mm + * For iOS video I/O + * by Eduard Feicho on 29/07/12 + * Copyright 2012. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "opencv2/highgui/cap_ios.h" +#include "precomp.hpp" + +#import + + +static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; + +#pragma mark - Private Interface + + + + +@interface CvVideoCamera () + +- (void)createVideoDataOutput; +- (void)createVideoFileOutput; + + +@property (nonatomic, retain) CALayer *customPreviewLayer; +@property (nonatomic, retain) AVCaptureVideoDataOutput *videoDataOutput; + +@end + + + +#pragma mark - Implementation + + + +@implementation CvVideoCamera + + + + +@synthesize delegate; +@synthesize grayscaleMode; + +@synthesize customPreviewLayer; +@synthesize videoDataOutput; + +@synthesize recordVideo; +//@synthesize videoFileOutput; +@synthesize recordAssetWriterInput; +@synthesize recordPixelBufferAdaptor; +@synthesize recordAssetWriter; + + + +#pragma mark - Constructors + +- (id)initWithParentView:(UIView*)parent; +{ + self = [super initWithParentView:parent]; + if (self) { + self.useAVCaptureVideoPreviewLayer = NO; + self.recordVideo = NO; + } + return self; +} + + + +#pragma mark - Public interface + + +- (void)start; +{ + [super start]; + + if (self.recordVideo == YES) { +// [self.videoFileOutput startRecordingToOutputFileURL:[self tempFileURL] recordingDelegate:self]; + + NSError* error; + if ([[NSFileManager defaultManager] fileExistsAtPath:[self tempFileString]]) [[NSFileManager defaultManager] removeItemAtPath:[self tempFileString] error:&error]; + if (error == nil) { + NSLog(@"[Camera] Delete file %@", [self tempFileString]); + } + + + BOOL started = [self.recordAssetWriter startWriting]; + [self.recordAssetWriter startSessionAtSourceTime:kCMTimeZero]; + + NSLog(@"[Camera] Session started? %d", started); + + if (self.recordAssetWriter.status == AVAssetWriterStatusUnknown) { + NSLog(@"AVAssetWriter status: unknown"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { + NSLog(@"AVAssetWriter status: writing"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusCompleted) { + NSLog(@"AVAssetWriter status: completed"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusFailed) { + NSLog(@"AVAssetWriter status: failed"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusCancelled) { + NSLog(@"AVAssetWriter status: cancelled"); + } + + if (self.recordAssetWriter.status != AVAssetWriterStatusWriting) { + NSLog(@"[Camera] Recording Error: asset writer status is not writing: %@", self.recordAssetWriter.error); + } else { + NSLog(@"[Camera] Recording started"); + } + } +} + + + +- (void)pause; +{ + [super pause]; + if (self.recordVideo == YES) { +// [self.videoFileOutput stopRecording]; + + + if (self.recordAssetWriter.status == AVAssetWriterStatusUnknown) { + NSLog(@"AVAssetWriter status: unknown"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { + NSLog(@"AVAssetWriter status: writing"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusCompleted) { + NSLog(@"AVAssetWriter status: completed"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusFailed) { + NSLog(@"AVAssetWriter status: failed"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusCancelled) { + NSLog(@"AVAssetWriter status: cancelled"); + } + + if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { + [self.recordAssetWriter finishWriting]; + NSLog(@"[Camera] recording stopped"); + } else { + NSLog(@"[Camera] Recording Error: asset writer status is not writing"); + } + } +} + + +- (void)stop; +{ + [super stop]; + + if (self.recordVideo == YES) { + NSLog(@"recording stop"); + if (self.recordAssetWriter.status == AVAssetWriterStatusUnknown) { + NSLog(@"AVAssetWriter status: unknown"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { + NSLog(@"AVAssetWriter status: writing"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusCompleted) { + NSLog(@"AVAssetWriter status: completed"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusFailed) { + NSLog(@"AVAssetWriter status: failed"); + } else if (self.recordAssetWriter.status == AVAssetWriterStatusCancelled) { + NSLog(@"AVAssetWriter status: cancelled"); + } + + + if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { + [self.recordAssetWriter finishWriting]; + NSLog(@"[Camera] recording stopped"); + } else { + NSLog(@"[Camera] Recording Error: asset writer status is not writing"); + } + + self.recordAssetWriter = nil; + self.recordAssetWriterInput = nil; + self.recordPixelBufferAdaptor = nil; + } + + self.videoDataOutput = nil; + if (videoDataOutputQueue) { + dispatch_release(videoDataOutputQueue); + } + + [self.customPreviewLayer removeFromSuperlayer]; + self.customPreviewLayer = nil; +} + +// TODO fix +- (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; +{ + + NSLog(@"layout preview layer"); + if (self.parentView != nil) { + + CALayer* layer = self.customPreviewLayer; + CGRect bounds = self.customPreviewLayer.bounds; + int rotation_angle = 0; + bool flip_bounds = false; + + switch (interfaceOrientation) { + case UIInterfaceOrientationPortrait: + NSLog(@"to Portrait"); + rotation_angle = 270; + break; + case UIInterfaceOrientationPortraitUpsideDown: + rotation_angle = 90; + NSLog(@"to UpsideDown"); + break; + case UIInterfaceOrientationLandscapeLeft: + rotation_angle = 0; + NSLog(@"to LandscapeLeft"); + break; + case UIInterfaceOrientationLandscapeRight: + rotation_angle = 180; + NSLog(@"to LandscapeRight"); + break; + default: + break; // leave the layer in its last known orientation + } + + switch (defaultAVCaptureVideoOrientation) { + case AVCaptureVideoOrientationLandscapeRight: + rotation_angle += 180; + break; + case AVCaptureVideoOrientationPortraitUpsideDown: + rotation_angle += 270; + break; + case AVCaptureVideoOrientationPortrait: + rotation_angle += 90; + case AVCaptureVideoOrientationLandscapeLeft: + break; + default: + break; + } + rotation_angle = rotation_angle % 360; + + if (rotation_angle == 90 || rotation_angle == 270) { + flip_bounds = true; + } + + if (flip_bounds) { + NSLog(@"flip bounds"); + bounds = CGRectMake(0, 0, bounds.size.height, bounds.size.width); + } + + layer.position = CGPointMake(self.parentView.frame.size.width/2., self.parentView.frame.size.height/2.); + self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height); + + layer.affineTransform = CGAffineTransformMakeRotation( DegreesToRadians(rotation_angle) ); + layer.bounds = bounds; + } + +} + +// TODO fix +- (void)layoutPreviewLayer; +{ + NSLog(@"layout preview layer"); + if (self.parentView != nil) { + + CALayer* layer = self.customPreviewLayer; + CGRect bounds = self.customPreviewLayer.bounds; + int rotation_angle = 0; + bool flip_bounds = false; + + switch (currentDeviceOrientation) { + case UIDeviceOrientationPortrait: + rotation_angle = 270; + break; + case UIDeviceOrientationPortraitUpsideDown: + rotation_angle = 90; + break; + case UIDeviceOrientationLandscapeLeft: + NSLog(@"left"); + rotation_angle = 180; + break; + case UIDeviceOrientationLandscapeRight: + NSLog(@"right"); + rotation_angle = 0; + break; + case UIDeviceOrientationFaceUp: + case UIDeviceOrientationFaceDown: + default: + break; // leave the layer in its last known orientation + } + + switch (defaultAVCaptureVideoOrientation) { + case AVCaptureVideoOrientationLandscapeRight: + rotation_angle += 180; + break; + case AVCaptureVideoOrientationPortraitUpsideDown: + rotation_angle += 270; + break; + case AVCaptureVideoOrientationPortrait: + rotation_angle += 90; + case AVCaptureVideoOrientationLandscapeLeft: + break; + default: + break; + } + rotation_angle = rotation_angle % 360; + + if (rotation_angle == 90 || rotation_angle == 270) { + flip_bounds = true; + } + + if (flip_bounds) { + NSLog(@"flip bounds"); + bounds = CGRectMake(0, 0, bounds.size.height, bounds.size.width); + } + + layer.position = CGPointMake(self.parentView.frame.size.width/2., self.parentView.frame.size.height/2.); + layer.affineTransform = CGAffineTransformMakeRotation( DegreesToRadians(rotation_angle) ); + layer.bounds = bounds; + } + +} + + + + +#pragma mark - Private Interface + + + +- (void)createVideoDataOutput; +{ + // Make a video data output + self.videoDataOutput = [AVCaptureVideoDataOutput new]; + + // In grayscale mode we want YUV (YpCbCr 4:2:0) so we can directly access the graylevel intensity values (Y component) + // In color mode we, BGRA format is used + OSType format = self.grayscaleMode ? kCVPixelFormatType_420YpCbCr8BiPlanarFullRange : kCVPixelFormatType_32BGRA; + + self.videoDataOutput.videoSettings = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:format] + forKey:(id)kCVPixelBufferPixelFormatTypeKey]; + + // discard if the data output queue is blocked (as we process the still image) + [self.videoDataOutput setAlwaysDiscardsLateVideoFrames:YES]; + + if ( [self.captureSession canAddOutput:self.videoDataOutput] ) { + [self.captureSession addOutput:self.videoDataOutput]; + } + [[self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo] setEnabled:YES]; + + + // set default FPS + if ([self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].supportsVideoMinFrameDuration) { + [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoMinFrameDuration = CMTimeMake(1, self.defaultFPS); + } + if ([self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].supportsVideoMaxFrameDuration) { + [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoMaxFrameDuration = CMTimeMake(1, self.defaultFPS); + } + + // set video mirroring for front camera (more intuitive) + if ([self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].supportsVideoMirroring) { + if (self.defaultAVCaptureDevicePosition == AVCaptureDevicePositionFront) { + [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoMirrored = YES; + } else { + [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoMirrored = NO; + } + } + + // set default video orientation + if ([self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].supportsVideoOrientation) { + [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoOrientation = self.defaultAVCaptureVideoOrientation; + } + + + // create a custom preview layer + self.customPreviewLayer = [CALayer layer]; + self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height); + [self layoutPreviewLayer]; + + // create a serial dispatch queue used for the sample buffer delegate as well as when a still image is captured + // a serial dispatch queue must be used to guarantee that video frames will be delivered in order + // see the header doc for setSampleBufferDelegate:queue: for more information + videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL); + [self.videoDataOutput setSampleBufferDelegate:self queue:videoDataOutputQueue]; + + + NSLog(@"[Camera] created AVCaptureVideoDataOutput at %d FPS", self.defaultFPS); +} + + + +- (void)createVideoFileOutput; +{ + /* + if (self.recordVideo == YES) { + self.videoFileOutput = [[AVCaptureMovieFileOutput alloc] init]; + if ( [self.captureSession canAddOutput:self.videoFileOutput] ) { + [self.captureSession addOutput:self.videoFileOutput]; + } + } + */ + + /* Video File Output in H.264, via AVAsserWriter */ + NSLog(@"Create Video with dimensions %dx%d", self.imageWidth, self.imageHeight); + + NSDictionary *outputSettings + = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:self.imageWidth], AVVideoWidthKey, + [NSNumber numberWithInt:self.imageHeight], AVVideoHeightKey, + AVVideoCodecH264, AVVideoCodecKey, + nil + ]; + + + self.recordAssetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings]; + + + /* I'm going to push pixel buffers to it, so will need a + AVAssetWriterPixelBufferAdaptor, to expect the same 32BGRA input as I've + asked the AVCaptureVideDataOutput to supply */ + int pixelBufferFormat = (self.grayscaleMode == YES) ? kCVPixelFormatType_420YpCbCr8BiPlanarFullRange : kCVPixelFormatType_32BGRA; + + self.recordPixelBufferAdaptor = + [[AVAssetWriterInputPixelBufferAdaptor alloc] + initWithAssetWriterInput:self.recordAssetWriterInput + sourcePixelBufferAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:pixelBufferFormat], kCVPixelBufferPixelFormatTypeKey,nil]]; + + NSError* error = nil; + NSLog(@"Create AVAssetWriter with url: %@", [self tempFileURL]); + self.recordAssetWriter = [AVAssetWriter assetWriterWithURL:[self tempFileURL] + fileType:AVFileTypeMPEG4 + error:&error]; + if (error != nil) { + NSLog(@"[Camera] Unable to create AVAssetWriter: %@", error); + } + + [self.recordAssetWriter addInput:self.recordAssetWriterInput]; + self.recordAssetWriterInput.expectsMediaDataInRealTime = NO; + + NSLog(@"[Camera] created AVAssetWriter"); + +} + + +- (void)createCaptureOutput; +{ + [self createVideoDataOutput]; + if (self.recordVideo == YES) { + [self createVideoFileOutput]; + } +} + +- (void)createCustomVideoPreview; +{ + [self.parentView.layer addSublayer:self.customPreviewLayer]; +} + + +#pragma mark - Protocol AVCaptureVideoDataOutputSampleBufferDelegate + + +- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection +{ + if (self.delegate) { + + // convert from Core Media to Core Video + CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); + CVPixelBufferLockBaseAddress(imageBuffer, 0); + + void* bufferAddress; + size_t width; + size_t height; + size_t bytesPerRow; + + CGColorSpaceRef colorSpace; + CGContextRef context; + + int format_opencv; + + OSType format = CVPixelBufferGetPixelFormatType(imageBuffer); + if (format == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { + + format_opencv = CV_8UC1; + + bufferAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0); + width = CVPixelBufferGetWidthOfPlane(imageBuffer, 0); + height = CVPixelBufferGetHeightOfPlane(imageBuffer, 0); + bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0); + + } else { // expect kCVPixelFormatType_32BGRA + + format_opencv = CV_8UC4; + + bufferAddress = CVPixelBufferGetBaseAddress(imageBuffer); + width = CVPixelBufferGetWidth(imageBuffer); + height = CVPixelBufferGetHeight(imageBuffer); + bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); + + } + + // delegate image processing to the delegate + cv::Mat image(height, width, format_opencv, bufferAddress, bytesPerRow); + + cv::Mat* result = NULL; + CGImage* dstImage; + + if ([self.delegate respondsToSelector:@selector(processImage:)]) { + [self.delegate processImage:image]; + } + + // check if matrix data pointer or dimensions were changed by the delegate + bool iOSimage = true; + if (height == image.rows && width == image.cols && format_opencv == image.type() && bufferAddress == image.data && bytesPerRow == image.step) { + iOSimage = false; + } + + + // (create color space, create graphics context, render buffer) + CGBitmapInfo bitmapInfo; + + // basically we decide if it's a grayscale, rgb or rgba image + if (image.channels() == 1) { + colorSpace = CGColorSpaceCreateDeviceGray(); + bitmapInfo = kCGImageAlphaNone; + } else if (image.channels() == 3) { + colorSpace = CGColorSpaceCreateDeviceRGB(); + bitmapInfo = kCGImageAlphaNone; + if (iOSimage) { + bitmapInfo |= kCGBitmapByteOrder32Little; + } else { + bitmapInfo |= kCGBitmapByteOrder32Big; + } + } else { + colorSpace = CGColorSpaceCreateDeviceRGB(); + bitmapInfo = kCGImageAlphaPremultipliedFirst; + if (iOSimage) { + bitmapInfo |= kCGBitmapByteOrder32Little; + } else { + bitmapInfo |= kCGBitmapByteOrder32Big; + } + } + + if (iOSimage) { + context = CGBitmapContextCreate(bufferAddress, width, height, 8, bytesPerRow, colorSpace, bitmapInfo); + dstImage = CGBitmapContextCreateImage(context); + CGContextRelease(context); + } else { + + NSData *data = [NSData dataWithBytes:image.data length:image.elemSize()*image.total()]; + CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); + + // Creating CGImage from cv::Mat + dstImage = CGImageCreate(image.cols, // width + image.rows, // height + 8, // bits per component + 8 * image.elemSize(), // bits per pixel + image.step, // bytesPerRow + colorSpace, // colorspace + bitmapInfo, // bitmap info + provider, // CGDataProviderRef + NULL, // decode + false, // should interpolate + kCGRenderingIntentDefault // intent + ); + + CGDataProviderRelease(provider); + } + + + + + // render buffer + dispatch_sync(dispatch_get_main_queue(), ^{ + self.customPreviewLayer.contents = (__bridge id)dstImage; + }); + + + if (self.recordVideo == YES) { + // a very dense way to keep track of the time at which this frame + // occurs relative to the output stream, but it's just an example! + + // TODO reset frame number + static int64_t frameNumber = 0; + if (self.recordAssetWriterInput.readyForMoreMediaData) { + [self.recordPixelBufferAdaptor appendPixelBuffer:imageBuffer + withPresentationTime:CMTimeMake(frameNumber, self.defaultFPS)]; + } + frameNumber++; + } + + + // cleanup + CGImageRelease(dstImage); + + CGColorSpaceRelease(colorSpace); + + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + } +} + + +- (void)updateOrientation; +{ + NSLog(@"rotate.."); + self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height); + [self layoutPreviewLayer]; +} + + +- (void)saveVideo; +{ + if (self.recordVideo == NO) { + return; + } + + ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; + if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:[self tempFileURL]]) { + [library writeVideoAtPathToSavedPhotosAlbum:[self tempFileURL] + completionBlock:^(NSURL *assetURL, NSError *error){}]; + } +} + + +- (NSURL *)tempFileURL; +{ + NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"]; + NSURL *outputURL = [NSURL fileURLWithPath:outputPath]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:outputPath]) { + NSLog(@"file exists"); + } + return outputURL; +} + + + +- (NSString *)tempFileString; +{ + NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"]; + return outputPath; +} + +@end From d8b69d750df06ddbb1c4de1b884f8d3938b86079 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Mon, 20 Aug 2012 19:46:52 +0400 Subject: [PATCH 035/163] some tweaks in optimization flags for opencv2.framework --- ios/cmake/Modules/Platform/iOS.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/cmake/Modules/Platform/iOS.cmake b/ios/cmake/Modules/Platform/iOS.cmake index e8389798bb..4ef75e7f15 100644 --- a/ios/cmake/Modules/Platform/iOS.cmake +++ b/ios/cmake/Modules/Platform/iOS.cmake @@ -42,7 +42,7 @@ set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") set (CMAKE_C_FLAGS "") set (CMAKE_CXX_FLAGS "-headerpad_max_install_names -fvisibility=hidden -fvisibility-inlines-hidden") -set (CMAKE_CXX_FLAGS_RELEASE "-O3 -fomit-frame-pointer") +set (CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 -fomit-frame-pointer -ffast-math") if (HAVE_FLAG_SEARCH_PATHS_FIRST) set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") From 4a1ef53deb6f64ae88ec25efd8ac262553eecf07 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Mon, 20 Aug 2012 19:51:19 +0400 Subject: [PATCH 036/163] Fixed gcc build warning --- modules/objdetect/src/hog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/objdetect/src/hog.cpp b/modules/objdetect/src/hog.cpp index 19decfb536..21bda2411c 100644 --- a/modules/objdetect/src/hog.cpp +++ b/modules/objdetect/src/hog.cpp @@ -2601,7 +2601,7 @@ void HOGDescriptor::readALTModel(std::string modelfile) double *linearwt = new double[totwords+1]; int length = totwords; nread = fread(linearwt, sizeof(double), totwords + 1, modelfl); - if(nread != length + 1) + if(nread != static_cast(length) + 1) throw Exception(); for(int i = 0; i < length; i++) From 682dede87e9b2d52ef3725608e1438a4ab8f202f Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Mon, 20 Aug 2012 19:52:24 +0400 Subject: [PATCH 037/163] #2215 Fix dependencies escaping in generated OpenCVConfig.cmake --- cmake/OpenCVGenConfig.cmake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmake/OpenCVGenConfig.cmake b/cmake/OpenCVGenConfig.cmake index 7a38e4b4e1..fcca310ceb 100644 --- a/cmake/OpenCVGenConfig.cmake +++ b/cmake/OpenCVGenConfig.cmake @@ -64,9 +64,14 @@ macro(ocv_generate_dependencies_map_configcmake suffix configuration) string(REGEX REPLACE "${CMAKE_SHARED_LIBRARY_SUFFIX}$" "${OPENCV_LINK_LIBRARY_SUFFIX}" __libname "${__libname}") endif() + string(REPLACE " " "\\ " __mod_deps "${${__ocv_lib}_MODULE_DEPS_${suffix}}") + string(REPLACE " " "\\ " __ext_deps "${${__ocv_lib}_EXTRA_DEPS_${suffix}}") + string(REPLACE "\"" "\\\"" __mod_deps "${__mod_deps}") + string(REPLACE "\"" "\\\"" __ext_deps "${__ext_deps}") + set(OPENCV_DEPENDENCIES_MAP_${suffix} "${OPENCV_DEPENDENCIES_MAP_${suffix}}set(OpenCV_${__ocv_lib}_LIBNAME_${suffix} \"${__libname}\")\n") - set(OPENCV_DEPENDENCIES_MAP_${suffix} "${OPENCV_DEPENDENCIES_MAP_${suffix}}set(OpenCV_${__ocv_lib}_DEPS_${suffix} ${${__ocv_lib}_MODULE_DEPS_${suffix}})\n") - set(OPENCV_DEPENDENCIES_MAP_${suffix} "${OPENCV_DEPENDENCIES_MAP_${suffix}}set(OpenCV_${__ocv_lib}_EXTRA_DEPS_${suffix} ${${__ocv_lib}_EXTRA_DEPS_${suffix}})\n") + set(OPENCV_DEPENDENCIES_MAP_${suffix} "${OPENCV_DEPENDENCIES_MAP_${suffix}}set(OpenCV_${__ocv_lib}_DEPS_${suffix} ${__mod_deps})\n") + set(OPENCV_DEPENDENCIES_MAP_${suffix} "${OPENCV_DEPENDENCIES_MAP_${suffix}}set(OpenCV_${__ocv_lib}_EXTRA_DEPS_${suffix} ${__ext_deps})\n") list(APPEND OPENCV_PROCESSED_LIBS ${__ocv_lib}) list(APPEND OPENCV_LIBS_TO_PROCESS ${${__ocv_lib}_MODULE_DEPS_${suffix}}) From ee0dd4d4967082c6bf3e4ba8d8bb3871720a7ec8 Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Mon, 20 Aug 2012 23:35:29 +0400 Subject: [PATCH 038/163] disabled -Wunused-but-set-variable because of multiple warnings during building nvcc auto generated files (GCC 4.6) --- cmake/OpenCVDetectCUDA.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake index 60d800547d..43e9c819af 100644 --- a/cmake/OpenCVDetectCUDA.cmake +++ b/cmake/OpenCVDetectCUDA.cmake @@ -88,7 +88,11 @@ if(CUDA_FOUND) if(APPLE) set (CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler -fno-finite-math-only) endif() - string(REPLACE "-Wsign-promo" "" CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS}") + + # disabled because of multiple warnings during building nvcc auto generated files + if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_GCC_REGEX_VERSION VERSION_GREATER "4.6.0") + ocv_warnings_disable(CMAKE_CXX_FLAGS -Wunused-but-set-variable) + endif() # we remove -ggdb3 flag as it leads to preprocessor errors when compiling CUDA files (CUDA 4.1) set(CMAKE_CXX_FLAGS_DEBUG_ ${CMAKE_CXX_FLAGS_DEBUG}) From 94f7c3c5923888caf14acb4ea86355888e3040fc Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Tue, 21 Aug 2012 01:03:52 +0400 Subject: [PATCH 039/163] Fixed FAST algorithm initializer --- modules/features2d/src/features2d_init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/features2d/src/features2d_init.cpp b/modules/features2d/src/features2d_init.cpp index 6ecffebd40..e21b8d8021 100644 --- a/modules/features2d/src/features2d_init.cpp +++ b/modules/features2d/src/features2d_init.cpp @@ -59,7 +59,7 @@ CV_INIT_ALGORITHM(BriefDescriptorExtractor, "Feature2D.BRIEF", CV_INIT_ALGORITHM(FastFeatureDetector, "Feature2D.FAST", obj.info()->addParam(obj, "threshold", obj.threshold); obj.info()->addParam(obj, "nonmaxSuppression", obj.nonmaxSuppression); - obj.info()->addParam(obj, "type", obj.type, FastFeatureDetector::TYPE_9_16)); + obj.info()->addParam(obj, "type", obj.type, static_cast(FastFeatureDetector::TYPE_9_16))); /////////////////////////////////////////////////////////////////////////////////////////////////////////// From 81d6400f45796f701c4f01057ee8216af01fba56 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 21 Aug 2012 14:28:40 +0400 Subject: [PATCH 040/163] fixed compilation under windows --- modules/ts/include/opencv2/ts/ts_perf.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ts/include/opencv2/ts/ts_perf.hpp b/modules/ts/include/opencv2/ts/ts_perf.hpp index d2a0b996e9..f730b2ce7a 100644 --- a/modules/ts/include/opencv2/ts/ts_perf.hpp +++ b/modules/ts/include/opencv2/ts/ts_perf.hpp @@ -442,7 +442,7 @@ CV_EXPORTS void PrintTo(const Size& sz, ::std::ostream* os); // SANITY_CHECK(c); // } #define PERF_TEST_P(fixture, name, params) \ - class fixture##_##name : public ::fixture {\ + class fixture##_##name : public fixture {\ public:\ fixture##_##name() {}\ protected:\ From 017ab51bf4edc45d0da2ccb0ca889c206f6735a1 Mon Sep 17 00:00:00 2001 From: Victor Passichenko Date: Tue, 21 Aug 2012 15:38:38 +0400 Subject: [PATCH 041/163] Fix wrong memory deallocation --- modules/photo/src/arrays.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/photo/src/arrays.hpp b/modules/photo/src/arrays.hpp index c1c4e5f971..0d86cb6e3a 100644 --- a/modules/photo/src/arrays.hpp +++ b/modules/photo/src/arrays.hpp @@ -67,7 +67,7 @@ template struct Array2d { ~Array2d() { if (needToDeallocArray) { - delete a; + delete[] a; } } @@ -96,7 +96,7 @@ template struct Array3d { ~Array3d() { if (needToDeallocArray) { - delete a; + delete[] a; } } @@ -138,7 +138,7 @@ template struct Array4d { ~Array4d() { if (needToDeallocArray) { - delete a; + delete[] a; } } From 0d2b8f4ba11651306cf59dfaf4c0c29a0822b881 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 21 Aug 2012 15:41:05 +0400 Subject: [PATCH 042/163] fixed the channel ordering of rgba images (by Eduard) --- modules/highgui/src/cap_ios_video_camera.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/highgui/src/cap_ios_video_camera.mm b/modules/highgui/src/cap_ios_video_camera.mm index bed17e1882..6f7bfa20fc 100644 --- a/modules/highgui/src/cap_ios_video_camera.mm +++ b/modules/highgui/src/cap_ios_video_camera.mm @@ -522,9 +522,9 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; } // check if matrix data pointer or dimensions were changed by the delegate - bool iOSimage = true; + bool iOSimage = false; if (height == image.rows && width == image.cols && format_opencv == image.type() && bufferAddress == image.data && bytesPerRow == image.step) { - iOSimage = false; + iOSimage = true; } From 92edd4fc6e15bc98f6cd8903bd49ecd06a736253 Mon Sep 17 00:00:00 2001 From: Victor Passichenko Date: Tue, 21 Aug 2012 15:41:51 +0400 Subject: [PATCH 043/163] Fix building for MS VS C++: remove allocation of arrays of dynamic size in stack --- modules/photo/src/denoising.cpp | 4 ++-- .../src/fast_nlmeans_denoising_invoker.hpp | 14 +++++++------- .../fast_nlmeans_multi_denoising_invoker.hpp | 17 ++++++++--------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/modules/photo/src/denoising.cpp b/modules/photo/src/denoising.cpp index 39643e33dc..b980b407b7 100644 --- a/modules/photo/src/denoising.cpp +++ b/modules/photo/src/denoising.cpp @@ -103,7 +103,7 @@ static void fastNlMeansDenoisingMultiCheckPreconditions( int imgToDenoiseIndex, int temporalWindowSize, int templateWindowSize, int searchWindowSize) { - int src_imgs_size = srcImgs.size(); + int src_imgs_size = (int)srcImgs.size(); if (src_imgs_size == 0) { CV_Error(CV_StsBadArg, "Input images vector should not be empty!"); } @@ -176,7 +176,7 @@ void cv::fastNlMeansDenoisingColoredMulti( const std::vector& srcImgs, temporalWindowSize, templateWindowSize, searchWindowSize ); - int src_imgs_size = srcImgs.size(); + int src_imgs_size = (int)srcImgs.size(); if (srcImgs[0].type() != CV_8UC3) { CV_Error(CV_StsBadArg, "Type of input images should be CV_8UC3!"); diff --git a/modules/photo/src/fast_nlmeans_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_denoising_invoker.hpp index 58e4a45e17..a45cb15d8a 100644 --- a/modules/photo/src/fast_nlmeans_denoising_invoker.hpp +++ b/modules/photo/src/fast_nlmeans_denoising_invoker.hpp @@ -62,6 +62,10 @@ struct FastNlMeansDenoisingInvoker { void operator() (const BlockedRange& range) const; + void operator= (const FastNlMeansDenoisingInvoker& invoker) { + CV_Error(CV_StsNotImplemented, "Assigment operator is not implemented"); + } + private: const Mat& src_; Mat& dst_; @@ -153,16 +157,12 @@ void FastNlMeansDenoisingInvoker::operator() (const BlockedRange& range) cons int row_from = range.begin(); int row_to = range.end() - 1; - int dist_sums_array[search_window_size_ * search_window_size_]; - Array2d dist_sums(dist_sums_array, search_window_size_, search_window_size_); + Array2d dist_sums(search_window_size_, search_window_size_); // for lazy calc optimization - int col_dist_sums_array[template_window_size_ * search_window_size_ * search_window_size_]; - Array3d col_dist_sums(&col_dist_sums_array[0], - template_window_size_, search_window_size_, search_window_size_); + Array3d col_dist_sums(template_window_size_, search_window_size_, search_window_size_); int first_col_num = -1; - Array3d up_col_dist_sums(src_.cols, search_window_size_, search_window_size_); for (int i = row_from; i <= row_to; i++) { @@ -233,7 +233,7 @@ void FastNlMeansDenoisingInvoker::operator() (const BlockedRange& range) cons // calc weights int weights_sum = 0; - int estimation[src_.channels()]; + int estimation[3]; for (int channel_num = 0; channel_num < src_.channels(); channel_num++) { estimation[channel_num] = 0; } diff --git a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp index cb08c7e434..8a6a81979b 100644 --- a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp +++ b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp @@ -63,6 +63,10 @@ struct FastNlMeansMultiDenoisingInvoker { void operator() (const BlockedRange& range) const; + void operator= (const FastNlMeansMultiDenoisingInvoker& invoker) { + CV_Error(CV_StsNotImplemented, "Assigment operator is not implemented"); + } + private: int rows_; int cols_; @@ -175,16 +179,11 @@ void FastNlMeansMultiDenoisingInvoker::operator() (const BlockedRange& range) int row_from = range.begin(); int row_to = range.end() - 1; - int dist_sums_array[temporal_window_size_ * search_window_size_ * search_window_size_]; - Array3d dist_sums(dist_sums_array, - temporal_window_size_, search_window_size_, search_window_size_); + Array3d dist_sums(temporal_window_size_, search_window_size_, search_window_size_); // for lazy calc optimization - int col_dist_sums_array[ - template_window_size_ * temporal_window_size_ * search_window_size_ * search_window_size_]; - - Array4d col_dist_sums(col_dist_sums_array, - template_window_size_, temporal_window_size_, search_window_size_, search_window_size_); + Array4d col_dist_sums( + template_window_size_, temporal_window_size_, search_window_size_, search_window_size_); int first_col_num = -1; @@ -263,7 +262,7 @@ void FastNlMeansMultiDenoisingInvoker::operator() (const BlockedRange& range) // calc weights int weights_sum = 0; - int estimation[channels_count_]; + int estimation[3]; for (int channel_num = 0; channel_num < channels_count_; channel_num++) { estimation[channel_num] = 0; } From 18de45f7bcda86e453156f3d18e1cdb8ded5ec42 Mon Sep 17 00:00:00 2001 From: Victor Passichenko Date: Tue, 21 Aug 2012 16:05:18 +0400 Subject: [PATCH 044/163] Add CV_Asserts for channels count --- modules/photo/src/fast_nlmeans_denoising_invoker.hpp | 2 ++ modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/modules/photo/src/fast_nlmeans_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_denoising_invoker.hpp index a45cb15d8a..6724e8272f 100644 --- a/modules/photo/src/fast_nlmeans_denoising_invoker.hpp +++ b/modules/photo/src/fast_nlmeans_denoising_invoker.hpp @@ -106,6 +106,8 @@ FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker( int search_window_size, const double h) : src_(src), dst_(dst) { + CV_Assert(src.channels() <= 3); + template_window_half_size_ = template_window_size / 2; search_window_half_size_ = search_window_size / 2; template_window_size_ = template_window_half_size_ * 2 + 1; diff --git a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp index 8a6a81979b..02185d13d2 100644 --- a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp +++ b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp @@ -115,6 +115,9 @@ FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker( int search_window_size, const double h) : dst_(dst), extended_srcs_(srcImgs.size()) { + CV_Assert(srcImgs.size() > 0); + CV_Assert(srcImgs[0].channels() <= 3); + rows_ = srcImgs[0].rows; cols_ = srcImgs[0].cols; channels_count_ = srcImgs[0].channels(); From 2f1cc018c9be148ebe55976e41ab70faafeee45d Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 21 Aug 2012 17:16:06 +0400 Subject: [PATCH 045/163] enabled SSE3 by default; integrated SSE3-optimized bilateral filter (by Grigoriy Frolov); modified API of non-local means (use Input/OutputArrays) --- CMakeLists.txt | 2 +- modules/imgproc/src/smooth.cpp | 237 ++++++++++++++++-- .../photo/include/opencv2/photo/denoising.hpp | 28 +-- modules/photo/src/denoising.cpp | 35 ++- .../fast_nlmeans_multi_denoising_invoker.hpp | 7 +- 5 files changed, 261 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80cf798ee6..c81cbd9dee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,7 +191,7 @@ OCV_OPTION(ENABLE_POWERPC "Enable PowerPC for GCC" OCV_OPTION(ENABLE_FAST_MATH "Enable -ffast-math (not recommended for GCC 4.6.x)" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_SSE "Enable SSE instructions" ON IF (MSVC OR CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_SSE2 "Enable SSE2 instructions" ON IF (MSVC OR CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSE3 "Enable SSE3 instructions" OFF IF (CV_ICC OR CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) +OCV_OPTION(ENABLE_SSE3 "Enable SSE3 instructions" ON IF (MSVC OR CV_ICC OR CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_SSSE3 "Enable SSSE3 instructions" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_SSE41 "Enable SSE4.1 instructions" OFF IF (CV_ICC OR CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_SSE42 "Enable SSE4.2 instructions" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) diff --git a/modules/imgproc/src/smooth.cpp b/modules/imgproc/src/smooth.cpp index 058768551e..0fe1b6be44 100644 --- a/modules/imgproc/src/smooth.cpp +++ b/modules/imgproc/src/smooth.cpp @@ -1294,28 +1294,64 @@ class BilateralFilter_8u_Invoker : public: BilateralFilter_8u_Invoker(Mat& _dest, const Mat& _temp, int _radius, int _maxk, int* _space_ofs, float *_space_weight, float *_color_weight) : - ParallelLoopBody(), dest(&_dest), temp(&_temp), radius(_radius), + temp(&_temp), dest(&_dest), radius(_radius), maxk(_maxk), space_ofs(_space_ofs), space_weight(_space_weight), color_weight(_color_weight) { } - + virtual void operator() (const Range& range) const { int i, j, cn = dest->channels(), k; Size size = dest->size(); - + #if CV_SSE3 + int CV_DECL_ALIGNED(16) buf[4]; + float CV_DECL_ALIGNED(16) bufSum[4]; + static const int CV_DECL_ALIGNED(16) bufSignMask[] = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; + bool haveSSE3 = checkHardwareSupport(CV_CPU_SSE3); + #endif + for( i = range.start; i < range.end; i++ ) { const uchar* sptr = temp->ptr(i+radius) + radius*cn; uchar* dptr = dest->ptr(i); - + if( cn == 1 ) { for( j = 0; j < size.width; j++ ) { float sum = 0, wsum = 0; int val0 = sptr[j]; - for( k = 0; k < maxk; k++ ) + k = 0; + #if CV_SSE3 + if( haveSSE3 ) + { + __m128 _val0 = _mm_set1_ps(val0); + const __m128 _signMask = _mm_load_ps((const float*)bufSignMask); + + for( ; k <= maxk - 4; k += 4 ) + { + __m128 _valF = _mm_set_ps(sptr[j + space_ofs[k+3]], sptr[j + space_ofs[k+2]], + sptr[j + space_ofs[k+1]], sptr[j + space_ofs[k]]); + + __m128 _val = _mm_andnot_ps(_signMask, _mm_sub_ps(_valF, _val0)); + _mm_store_si128((__m128i*)buf, _mm_cvtps_epi32(_val)); + + __m128 _cw = _mm_set_ps(color_weight[buf[3]],color_weight[buf[2]], + color_weight[buf[1]],color_weight[buf[0]]); + __m128 _sw = _mm_loadu_ps(space_weight+k); + __m128 _w = _mm_mul_ps(_cw, _sw); + _cw = _mm_mul_ps(_w, _valF); + + _sw = _mm_hadd_ps(_w, _cw); + _sw = _mm_hadd_ps(_sw, _sw); + _mm_storel_pi((__m64*)bufSum, _sw); + + sum += bufSum[1]; + wsum += bufSum[0]; + } + } + #endif + for( ; k < maxk; k++ ) { int val = sptr[j + space_ofs[k]]; float w = space_weight[k]*color_weight[std::abs(val - val0)]; @@ -1333,7 +1369,57 @@ public: { float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0; int b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2]; - for( k = 0; k < maxk; k++ ) + k = 0; + #if CV_SSE3 + if( haveSSE3 ) + { + const __m128 _b0 = _mm_set1_ps(b0); + const __m128 _g0 = _mm_set1_ps(g0); + const __m128 _r0 = _mm_set1_ps(r0); + const __m128 _signMask = _mm_load_ps((const float*)bufSignMask); + + for( ; k <= maxk - 4; k += 4 ) + { + const uchar* sptr_k = sptr + j + space_ofs[k]; + const uchar* sptr_k1 = sptr + j + space_ofs[k+1]; + const uchar* sptr_k2 = sptr + j + space_ofs[k+2]; + const uchar* sptr_k3 = sptr + j + space_ofs[k+3]; + + __m128 _b = _mm_set_ps(sptr_k3[0],sptr_k2[0],sptr_k1[0],sptr_k[0]); + __m128 _g = _mm_set_ps(sptr_k3[1],sptr_k2[1],sptr_k1[1],sptr_k[1]); + __m128 _r = _mm_set_ps(sptr_k3[2],sptr_k2[2],sptr_k1[2],sptr_k[2]); + + __m128 bt = _mm_andnot_ps(_signMask, _mm_sub_ps(_b,_b0)); + __m128 gt = _mm_andnot_ps(_signMask, _mm_sub_ps(_g,_g0)); + __m128 rt = _mm_andnot_ps(_signMask, _mm_sub_ps(_r,_r0)); + + bt =_mm_add_ps(rt, _mm_add_ps(bt, gt)); + _mm_store_si128((__m128i*)buf, _mm_cvtps_epi32(bt)); + + __m128 _w = _mm_set_ps(color_weight[buf[3]],color_weight[buf[2]], + color_weight[buf[1]],color_weight[buf[0]]); + __m128 _sw = _mm_loadu_ps(space_weight+k); + + _w = _mm_mul_ps(_w,_sw); + _b = _mm_mul_ps(_b, _w); + _g = _mm_mul_ps(_g, _w); + _r = _mm_mul_ps(_r, _w); + + _w = _mm_hadd_ps(_w, _b); + _g = _mm_hadd_ps(_g, _r); + + _w = _mm_hadd_ps(_w, _g); + _mm_store_ps(bufSum, _w); + + wsum += bufSum[0]; + sum_b += bufSum[1]; + sum_g += bufSum[2]; + sum_r += bufSum[3]; + } + } + #endif + + for( ; k < maxk; k++ ) { const uchar* sptr_k = sptr + j + space_ofs[k]; int b = sptr_k[0], g = sptr_k[1], r = sptr_k[2]; @@ -1351,10 +1437,10 @@ public: } } } - + private: - Mat *dest; const Mat *temp; + Mat *dest; int radius, maxk, *space_ofs; float *space_weight, *color_weight; }; @@ -1364,46 +1450,51 @@ bilateralFilter_8u( const Mat& src, Mat& dst, int d, double sigma_color, double sigma_space, int borderType ) { + int cn = src.channels(); int i, j, maxk, radius; Size size = src.size(); - + CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) && src.type() == dst.type() && src.size() == dst.size() && src.data != dst.data ); - + if( sigma_color <= 0 ) sigma_color = 1; if( sigma_space <= 0 ) sigma_space = 1; - + double gauss_color_coeff = -0.5/(sigma_color*sigma_color); double gauss_space_coeff = -0.5/(sigma_space*sigma_space); - + if( d <= 0 ) radius = cvRound(sigma_space*1.5); else radius = d/2; radius = MAX(radius, 1); d = radius*2 + 1; - + Mat temp; copyMakeBorder( src, temp, radius, radius, radius, radius, borderType ); - + vector _color_weight(cn*256); vector _space_weight(d*d); vector _space_ofs(d*d); float* color_weight = &_color_weight[0]; float* space_weight = &_space_weight[0]; int* space_ofs = &_space_ofs[0]; - + // initialize color-related bilateral filter coefficients + for( i = 0; i < 256*cn; i++ ) color_weight[i] = (float)std::exp(i*i*gauss_color_coeff); - + // initialize space-related bilateral filter coefficients for( i = -radius, maxk = 0; i <= radius; i++ ) - for( j = -radius; j <= radius; j++ ) + { + j = -radius; + + for( ;j <= radius; j++ ) { double r = std::sqrt((double)i*i + (double)j*j); if( r > radius ) @@ -1411,7 +1502,8 @@ bilateralFilter_8u( const Mat& src, Mat& dst, int d, space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff); space_ofs[maxk++] = (int)(i*temp.step + j*cn); } - + } + BilateralFilter_8u_Invoker body(dst, temp, radius, maxk, space_ofs, space_weight, color_weight); parallel_for_(Range(0, size.height), body); } @@ -1424,7 +1516,7 @@ public: BilateralFilter_32f_Invoker(int _cn, int _radius, int _maxk, int *_space_ofs, const Mat& _temp, Mat& _dest, float _scale_index, float *_space_weight, float *_expLUT) : - ParallelLoopBody(), cn(_cn), radius(_radius), maxk(_maxk), space_ofs(_space_ofs), + cn(_cn), radius(_radius), maxk(_maxk), space_ofs(_space_ofs), temp(&_temp), dest(&_dest), scale_index(_scale_index), space_weight(_space_weight), expLUT(_expLUT) { } @@ -1433,6 +1525,12 @@ public: { int i, j, k; Size size = dest->size(); + #if CV_SSE3 + int CV_DECL_ALIGNED(16) idxBuf[4]; + float CV_DECL_ALIGNED(16) bufSum32[4]; + static const int CV_DECL_ALIGNED(16) bufSignMask[] = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; + bool haveSSE3 = checkHardwareSupport(CV_CPU_SSE3); + #endif for( i = range.start; i < range.end; i++ ) { @@ -1445,7 +1543,44 @@ public: { float sum = 0, wsum = 0; float val0 = sptr[j]; - for( k = 0; k < maxk; k++ ) + k = 0; + #if CV_SSE3 + if( haveSSE3 ) + { + const __m128 _val0 = _mm_set1_ps(sptr[j]); + const __m128 _scale_index = _mm_set1_ps(scale_index); + const __m128 _signMask = _mm_load_ps((const float*)bufSignMask); + + for( ; k <= maxk - 4 ; k += 4 ) + { + __m128 _sw = _mm_loadu_ps(space_weight + k); + __m128 _val = _mm_set_ps(sptr[j + space_ofs[k+3]], sptr[j + space_ofs[k+2]], + sptr[j + space_ofs[k+1]], sptr[j + space_ofs[k]]); + __m128 _alpha = _mm_mul_ps(_mm_andnot_ps( _signMask, _mm_sub_ps(_val,_val0)), _scale_index); + + __m128i _idx = _mm_cvtps_epi32(_alpha); + _mm_store_si128((__m128i*)idxBuf, _idx); + _alpha = _mm_sub_ps(_alpha, _mm_cvtepi32_ps(_idx)); + + __m128 _explut = _mm_set_ps(expLUT[idxBuf[3]], expLUT[idxBuf[2]], + expLUT[idxBuf[1]], expLUT[idxBuf[0]]); + __m128 _explut1 = _mm_set_ps(expLUT[idxBuf[3]+1], expLUT[idxBuf[2]+1], + expLUT[idxBuf[1]+1], expLUT[idxBuf[0]+1]); + + __m128 _w = _mm_mul_ps(_sw, _mm_add_ps(_explut, _mm_mul_ps(_alpha, _mm_sub_ps(_explut1, _explut)))); + _val = _mm_mul_ps(_w, _val); + + _sw = _mm_hadd_ps(_w, _val); + _sw = _mm_hadd_ps(_sw, _sw); + _mm_storel_pi((__m64*)bufSum32, _sw); + + sum += bufSum32[1]; + wsum += bufSum32[0]; + } + } + #endif + + for( ; k < maxk; k++ ) { float val = sptr[j + space_ofs[k]]; float alpha = (float)(std::abs(val - val0)*scale_index); @@ -1465,7 +1600,64 @@ public: { float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0; float b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2]; - for( k = 0; k < maxk; k++ ) + k = 0; + #if CV_SSE3 + if( haveSSE3 ) + { + const __m128 _b0 = _mm_set1_ps(b0); + const __m128 _g0 = _mm_set1_ps(g0); + const __m128 _r0 = _mm_set1_ps(r0); + const __m128 _scale_index = _mm_set1_ps(scale_index); + const __m128 _signMask = _mm_load_ps((const float*)bufSignMask); + + for( ; k <= maxk-4; k += 4 ) + { + __m128 _sw = _mm_loadu_ps(space_weight + k); + + const float* sptr_k = sptr + j + space_ofs[k]; + const float* sptr_k1 = sptr + j + space_ofs[k+1]; + const float* sptr_k2 = sptr + j + space_ofs[k+2]; + const float* sptr_k3 = sptr + j + space_ofs[k+3]; + + __m128 _b = _mm_set_ps(sptr_k3[0], sptr_k2[0], sptr_k1[0], sptr_k[0]); + __m128 _g = _mm_set_ps(sptr_k3[1], sptr_k2[1], sptr_k1[1], sptr_k[1]); + __m128 _r = _mm_set_ps(sptr_k3[2], sptr_k2[2], sptr_k1[2], sptr_k[2]); + + __m128 _bt = _mm_andnot_ps(_signMask,_mm_sub_ps(_b,_b0)); + __m128 _gt = _mm_andnot_ps(_signMask,_mm_sub_ps(_g,_g0)); + __m128 _rt = _mm_andnot_ps(_signMask,_mm_sub_ps(_r,_r0)); + + __m128 _alpha = _mm_mul_ps(_scale_index, _mm_add_ps(_rt,_mm_add_ps(_bt, _gt))); + + __m128i _idx = _mm_cvtps_epi32(_alpha); + _mm_store_si128((__m128i*)idxBuf, _idx); + _alpha = _mm_sub_ps(_alpha, _mm_cvtepi32_ps(_idx)); + + __m128 _explut = _mm_set_ps(expLUT[idxBuf[3]], expLUT[idxBuf[2]], expLUT[idxBuf[1]], expLUT[idxBuf[0]]); + __m128 _explut1 = _mm_set_ps(expLUT[idxBuf[3]+1], expLUT[idxBuf[2]+1], expLUT[idxBuf[1]+1], expLUT[idxBuf[0]+1]); + + __m128 _w = _mm_mul_ps(_sw, _mm_add_ps(_explut, _mm_mul_ps(_alpha, _mm_sub_ps(_explut1, _explut)))); + + _b = _mm_mul_ps(_b, _w); + _g = _mm_mul_ps(_g, _w); + _r = _mm_mul_ps(_r, _w); + + _w = _mm_hadd_ps(_w, _b); + _g = _mm_hadd_ps(_g, _r); + + _w = _mm_hadd_ps(_w, _g); + _mm_store_ps(bufSum32, _w); + + wsum += bufSum32[0]; + sum_b += bufSum32[1]; + sum_g += bufSum32[2]; + sum_r += bufSum32[3]; + } + + } + #endif + + for(; k < maxk; k++ ) { const float* sptr_k = sptr + j + space_ofs[k]; float b = sptr_k[0], g = sptr_k[1], r = sptr_k[2]; @@ -1493,6 +1685,7 @@ private: Mat *dest; float scale_index, *space_weight, *expLUT; }; + static void bilateralFilter_32f( const Mat& src, Mat& dst, int d, @@ -1569,7 +1762,7 @@ bilateralFilter_32f( const Mat& src, Mat& dst, int d, } // initialize space-related bilateral filter coefficients - for( i = -radius, maxk = 0; i <= radius; i++ ) + for( i = -radius, maxk = 0; i <= radius; i++ ) for( j = -radius; j <= radius; j++ ) { double r = std::sqrt((double)i*i + (double)j*j); diff --git a/modules/photo/include/opencv2/photo/denoising.hpp b/modules/photo/include/opencv2/photo/denoising.hpp index b322c31755..1fc35a674b 100644 --- a/modules/photo/include/opencv2/photo/denoising.hpp +++ b/modules/photo/include/opencv2/photo/denoising.hpp @@ -55,23 +55,23 @@ namespace cv { -CV_EXPORTS void fastNlMeansDenoising( const Mat& src, Mat& dst, - int templateWindowSize, int searchWindowSize, int h); +CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, + int templateWindowSize, int searchWindowSize, int h); -CV_EXPORTS void fastNlMeansDenoisingColored( const Mat& src, Mat& dst, - int templateWindowSize, int searchWindowSize, - int h, int hForColorComponents); +CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, + int templateWindowSize, int searchWindowSize, + int h, int hForColorComponents); -CV_EXPORTS void fastNlMeansDenoisingMulti( const std::vector& srcImgs, - int imgToDenoiseIndex, int temporalWindowSize, - Mat& dst, - int templateWindowSize, int searchWindowSize, int h); +CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + OutputArray dst, + int templateWindowSize, int searchWindowSize, int h); -CV_EXPORTS void fastNlMeansDenoisingColoredMulti( const std::vector& srcImgs, - int imgToDenoiseIndex, int temporalWindowSize, - Mat& dst, - int templateWindowSize, int searchWindowSize, - int h, int hForColorComponents); +CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + OutputArray dst, + int templateWindowSize, int searchWindowSize, + int h, int hForColorComponents); } #endif diff --git a/modules/photo/src/denoising.cpp b/modules/photo/src/denoising.cpp index b980b407b7..7452d0d3ce 100644 --- a/modules/photo/src/denoising.cpp +++ b/modules/photo/src/denoising.cpp @@ -45,9 +45,13 @@ #include "fast_nlmeans_denoising_invoker.hpp" #include "fast_nlmeans_multi_denoising_invoker.hpp" -void cv::fastNlMeansDenoising( const cv::Mat& src, cv::Mat& dst, +void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, int templateWindowSize, int searchWindowSize, int h) -{ +{ + Mat src = _src.getMat(); + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + switch (src.type()) { case CV_8U: parallel_for(cv::BlockedRange(0, src.rows), @@ -70,10 +74,14 @@ void cv::fastNlMeansDenoising( const cv::Mat& src, cv::Mat& dst, } } -void cv::fastNlMeansDenoisingColored( const cv::Mat& src, cv::Mat& dst, +void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst, int templateWindowSize, int searchWindowSize, int h, int hForColorComponents) { + Mat src = _src.getMat(); + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + if (src.type() != CV_8UC3) { CV_Error(CV_StsBadArg, "Type of input image should be CV_8UC3!"); return; @@ -130,15 +138,20 @@ static void fastNlMeansDenoisingMultiCheckPreconditions( } } -void cv::fastNlMeansDenoisingMulti( const std::vector& srcImgs, +void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, int imgToDenoiseIndex, int temporalWindowSize, - cv::Mat& dst, + OutputArray _dst, int templateWindowSize, int searchWindowSize, int h) -{ +{ + vector srcImgs; + _srcImgs.getMatVector(srcImgs); + fastNlMeansDenoisingMultiCheckPreconditions( srcImgs, imgToDenoiseIndex, temporalWindowSize, templateWindowSize, searchWindowSize ); + _dst.create(srcImgs[0].size(), srcImgs[0].type()); + Mat dst = _dst.getMat(); switch (srcImgs[0].type()) { case CV_8U: @@ -165,16 +178,22 @@ void cv::fastNlMeansDenoisingMulti( const std::vector& srcImgs, } } -void cv::fastNlMeansDenoisingColoredMulti( const std::vector& srcImgs, +void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs, int imgToDenoiseIndex, int temporalWindowSize, - cv::Mat& dst, + OutputArray _dst, int templateWindowSize, int searchWindowSize, int h, int hForColorComponents) { + vector srcImgs; + _srcImgs.getMatVector(srcImgs); + fastNlMeansDenoisingMultiCheckPreconditions( srcImgs, imgToDenoiseIndex, temporalWindowSize, templateWindowSize, searchWindowSize ); + + _dst.create(srcImgs[0].size(), srcImgs[0].type()); + Mat dst = _dst.getMat(); int src_imgs_size = (int)srcImgs.size(); diff --git a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp index 02185d13d2..602007e326 100644 --- a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp +++ b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp @@ -270,9 +270,9 @@ void FastNlMeansMultiDenoisingInvoker::operator() (const BlockedRange& range) estimation[channel_num] = 0; } for (int d = 0; d < temporal_window_size_; d++) { + const Mat& esrc_d = extended_srcs_[d]; for (int y = 0; y < search_window_size_; y++) { - const T* cur_row_ptr = - extended_srcs_[d].ptr(border_size_ + search_window_y + y); + const T* cur_row_ptr = esrc_d.ptr(border_size_ + search_window_y + y); int* dist_sums_row = dist_sums.row_ptr(d, y); @@ -298,7 +298,8 @@ void FastNlMeansMultiDenoisingInvoker::operator() (const BlockedRange& range) dst_.at(i,j) = saturateCastFromArray(estimation); } else { // weights_sum == 0 - dst_.at(i,j) = extended_srcs_[temporal_window_half_size_].at(i,j); + const Mat& esrc = extended_srcs_[temporal_window_half_size_]; + dst_.at(i,j) = esrc.at(i,j); } } } From 10dcf9ea39999a26f5b1d49cf7f742be9899f53d Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Tue, 21 Aug 2012 18:34:02 +0400 Subject: [PATCH 046/163] Fix Java API build --- modules/photo/include/opencv2/photo/denoising.hpp | 8 ++++---- modules/photo/include/opencv2/photo/photo.hpp | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/photo/include/opencv2/photo/denoising.hpp b/modules/photo/include/opencv2/photo/denoising.hpp index 1fc35a674b..718c3b73e8 100644 --- a/modules/photo/include/opencv2/photo/denoising.hpp +++ b/modules/photo/include/opencv2/photo/denoising.hpp @@ -59,18 +59,18 @@ CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, int templateWindowSize, int searchWindowSize, int h); CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, - int templateWindowSize, int searchWindowSize, + int templateWindowSize, int searchWindowSize, int h, int hForColorComponents); -CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, +CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, int imgToDenoiseIndex, int temporalWindowSize, OutputArray dst, int templateWindowSize, int searchWindowSize, int h); -CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, +CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, int imgToDenoiseIndex, int temporalWindowSize, OutputArray dst, - int templateWindowSize, int searchWindowSize, + int templateWindowSize, int searchWindowSize, int h, int hForColorComponents); } diff --git a/modules/photo/include/opencv2/photo/photo.hpp b/modules/photo/include/opencv2/photo/photo.hpp index 40a0924327..f771b8fbd9 100644 --- a/modules/photo/include/opencv2/photo/photo.hpp +++ b/modules/photo/include/opencv2/photo/photo.hpp @@ -47,6 +47,7 @@ #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/photo/photo_c.h" +#include "opencv2/photo/denoising.hpp" #ifdef __cplusplus From a840d929aca2ffc6429882e92570b69850e88784 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Tue, 21 Aug 2012 18:59:51 +0400 Subject: [PATCH 047/163] #2170 fix warning of undefined GTEST_HAS_DEATH_TEST --- modules/ts/include/opencv2/ts/ts_gtest.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/ts/include/opencv2/ts/ts_gtest.h b/modules/ts/include/opencv2/ts/ts_gtest.h index 1300ff2d6f..f98f71b28c 100644 --- a/modules/ts/include/opencv2/ts/ts_gtest.h +++ b/modules/ts/include/opencv2/ts/ts_gtest.h @@ -1702,6 +1702,8 @@ inline bool operator!=(const GTEST_10_TUPLE_(T)& t, GTEST_OS_OPENBSD || GTEST_OS_QNX) # define GTEST_HAS_DEATH_TEST 1 # include // NOLINT +#else +# define GTEST_HAS_DEATH_TEST 0 #endif // We don't support MSVC 7.1 with exceptions disabled now. Therefore From 64661ea9cd2cdd97b43740f07565a6f64abbb810 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 21 Aug 2012 23:00:50 +0400 Subject: [PATCH 048/163] added SSE2-optimized resizeAreaFast for 8-bit images by Grigoriy Frolov --- modules/imgproc/src/imgwarp.cpp | 117 ++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index a311d5be67..b09588879c 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -1328,6 +1328,123 @@ static void resizeArea_( const Mat& src, Mat& dst, const DecimateAlpha* xofs, in } } } + + +template <> static void +resizeAreaFast_( const Mat& src, Mat& dst, const int* ofs, const int* xofs, + int scale_x, int scale_y ) +{ +#if CV_SSE2 + bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2); +#endif + + Size ssize = src.size(), dsize = dst.size(); + int cn = src.channels(); + int dy, dx, k = 0; + int area = scale_x*scale_y; + float scale = 1.f/(scale_x*scale_y); + int dwidth1 = (ssize.width/scale_x)*cn; + dsize.width *= cn; + ssize.width *= cn; + //avg values + for( dy = 0; dy < dsize.height; dy++ ) + { + uchar* D = (uchar*)(dst.data + dst.step*dy); + int sy0 = dy*scale_y, w = sy0 + scale_y <= ssize.height ? dwidth1 : 0; + if( sy0 >= ssize.height ) + { + for( dx = 0; dx < dsize.width; dx++ ) //memset(D,0, dsize.width);//warning, never executed -> not tested + D[dx] = 0; + continue; + } + dx = 0; + + #if CV_SSE2 + if( haveSSE2 ) + { + const __m128 _scale = _mm_set1_ps(scale); + const __m128i _ucMAXs = _mm_set1_epi16(UCHAR_MAX); + const uchar* _S[8]; + + for(; dx < w-8; dx+=8 ) + { + __m128i _sum = _mm_setzero_si128(); + __m128i _sum1 = _mm_setzero_si128(); + _S[0] = (const uchar*)(src.data + src.step*sy0) + xofs[dx]; + _S[1] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+1]; + _S[2] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+2]; + _S[3] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+3]; + + _S[4] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+4]; + _S[5] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+5]; + _S[6] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+6]; + _S[7] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+7]; + + for( k = 0; k < area; k++ ) + { + int ofsk = ofs[k]; + __m128i _temp = _mm_set_epi32(_S[3][ofsk],_S[2][ofsk],_S[1][ofsk],_S[0][ofsk]); + _sum = _mm_add_epi32(_sum, _temp); + + __m128i _temp1 = _mm_set_epi32(_S[7][ofsk],_S[6][ofsk],_S[5][ofsk],_S[4][ofsk]); + _sum1 = _mm_add_epi32(_sum1, _temp1); + } + + __m128i _tempSum = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(_sum), _scale)); + __m128i _tempSum1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(_sum1), _scale)); + + _tempSum = _mm_packs_epi32(_tempSum, _tempSum1); + _tempSum = _mm_min_epi16(_ucMAXs, _tempSum); + _tempSum = _mm_packus_epi16(_tempSum, _tempSum); + _mm_storel_epi64((__m128i*)(D+dx),_tempSum); + } + } + #endif + + for(; dx < w; dx++ ) + { + const uchar* S = (const uchar*)(src.data + src.step*sy0) + xofs[dx]; + int sum = 0; + k=0; + + #if CV_ENABLE_UNROLLED + for( ; k <= area - 4; k += 4 ) + sum += S[ofs[k]] + S[ofs[k+1]] + S[ofs[k+2]] + S[ofs[k+3]]; + #endif + + for( ; k < area; k++ ) + sum += S[ofs[k]]; + + + D[dx] = saturate_cast(sum*scale); + } + + for( ; dx < dsize.width; dx++ ) + { + int sum = 0; + int count = 0, sx0 = xofs[dx]; + if( sx0 >= ssize.width ) + D[dx] = 0; + + for( int sy = 0; sy < scale_y; sy++ ) + { + if( sy0 + sy >= ssize.height ) + break; + const uchar* S = (const uchar*)(src.data + src.step*(sy0 + sy)) + sx0; + int sx = 0; + for( ; sx < scale_x*cn; sx += cn ) + { + if( sx0 + sx >= ssize.width ) + break; + sum += S[sx]; + count++; + } + } + + D[dx] = saturate_cast((float)sum/count); + } + } +} typedef void (*ResizeFunc)( const Mat& src, Mat& dst, From 793e8b546d060a6ad032a794afd4cbd351ed87ed Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 21 Aug 2012 23:11:49 +0400 Subject: [PATCH 049/163] fixed build on Ubuntu --- modules/imgproc/src/imgwarp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index b09588879c..e5a47e1a2d 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -1330,9 +1330,9 @@ static void resizeArea_( const Mat& src, Mat& dst, const DecimateAlpha* xofs, in } -template <> static void -resizeAreaFast_( const Mat& src, Mat& dst, const int* ofs, const int* xofs, - int scale_x, int scale_y ) +static void resizeAreaFast_8u( const Mat& src, Mat& dst, + const int* ofs, const int* xofs, + int scale_x, int scale_y ) { #if CV_SSE2 bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2); @@ -1553,7 +1553,7 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize, static ResizeAreaFastFunc areafast_tab[] = { - resizeAreaFast_, 0, + resizeAreaFast_8u, 0, resizeAreaFast_, resizeAreaFast_, 0, From f2a02feffa582a850800174e9a520e2a4d730777 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Wed, 22 Aug 2012 03:59:05 +0400 Subject: [PATCH 050/163] Fix Windows build issues * No /arch:SSE3 in MSVC * Warnings fixed or suppressed --- 3rdparty/libtiff/CMakeLists.txt | 2 +- CMakeLists.txt | 8 ++--- modules/features2d/src/features2d_init.cpp | 2 +- modules/features2d/test/test_fast.cpp | 4 +-- .../features2d/test/test_nearestneighbors.cpp | 6 ++-- .../test_rotation_and_scale_invariance.cpp | 30 +++++++++---------- modules/gpu/perf/perf_imgproc.cpp | 18 +++++------ modules/gpu/perf/perf_labeling.cpp | 9 ++++-- modules/gpu/perf/perf_video.cpp | 2 +- samples/cpp/bagofwords_classification.cpp | 1 + samples/gpu/bgfg_segm.cpp | 6 ++-- samples/gpu/performance/tests.cpp | 4 +-- 12 files changed, 49 insertions(+), 43 deletions(-) diff --git a/3rdparty/libtiff/CMakeLists.txt b/3rdparty/libtiff/CMakeLists.txt index ed9d1c86b7..6dd7956f58 100644 --- a/3rdparty/libtiff/CMakeLists.txt +++ b/3rdparty/libtiff/CMakeLists.txt @@ -89,7 +89,7 @@ endif(WIN32) ocv_warnings_disable(CMAKE_C_FLAGS -Wno-unused-but-set-variable -Wmissing-prototypes -Wmissing-declarations -Wundef -Wunused -Wsign-compare -Wcast-align -Wshadow -Wno-maybe-uninitialized -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast) -ocv_warnings_disable(CMAKE_CXX_FLAGS -Wmissing-declarations -Wunused-parameter /wd4100 /wd4244 /wd4706 /wd4127 /wd4701 /wd4018 /wd4267 /wd4306 /wd4305 /wd4312 /wd4311) +ocv_warnings_disable(CMAKE_CXX_FLAGS -Wmissing-declarations -Wunused-parameter /wd4100 /wd4244 /wd4706 /wd4127 /wd4701 /wd4018 /wd4267 /wd4306 /wd4305 /wd4312 /wd4311 /wd4703) if(UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR CV_ICC)) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") diff --git a/CMakeLists.txt b/CMakeLists.txt index c81cbd9dee..d893f1c74d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,11 +189,11 @@ OCV_OPTION(ENABLE_PROFILING "Enable profiling in the GCC compiler (Add OCV_OPTION(ENABLE_OMIT_FRAME_POINTER "Enable -fomit-frame-pointer for GCC" ON IF CMAKE_COMPILER_IS_GNUCXX ) OCV_OPTION(ENABLE_POWERPC "Enable PowerPC for GCC" ON IF (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR MATCHES powerpc.*) ) OCV_OPTION(ENABLE_FAST_MATH "Enable -ffast-math (not recommended for GCC 4.6.x)" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSE "Enable SSE instructions" ON IF (MSVC OR CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSE2 "Enable SSE2 instructions" ON IF (MSVC OR CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSE3 "Enable SSE3 instructions" ON IF (MSVC OR CV_ICC OR CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) +OCV_OPTION(ENABLE_SSE "Enable SSE instructions" ON IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) +OCV_OPTION(ENABLE_SSE2 "Enable SSE2 instructions" ON IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) +OCV_OPTION(ENABLE_SSE3 "Enable SSE3 instructions" ON IF ((CV_ICC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_SSSE3 "Enable SSSE3 instructions" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) -OCV_OPTION(ENABLE_SSE41 "Enable SSE4.1 instructions" OFF IF (CV_ICC OR CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) +OCV_OPTION(ENABLE_SSE41 "Enable SSE4.1 instructions" OFF IF ((CV_ICC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_SSE42 "Enable SSE4.2 instructions" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_NOISY_WARNINGS "Show all warnings even if they are too noisy" OFF ) OCV_OPTION(OPENCV_WARNINGS_ARE_ERRORS "Treat warnings as errors" OFF ) diff --git a/modules/features2d/src/features2d_init.cpp b/modules/features2d/src/features2d_init.cpp index e21b8d8021..c9abfefa9f 100644 --- a/modules/features2d/src/features2d_init.cpp +++ b/modules/features2d/src/features2d_init.cpp @@ -59,7 +59,7 @@ CV_INIT_ALGORITHM(BriefDescriptorExtractor, "Feature2D.BRIEF", CV_INIT_ALGORITHM(FastFeatureDetector, "Feature2D.FAST", obj.info()->addParam(obj, "threshold", obj.threshold); obj.info()->addParam(obj, "nonmaxSuppression", obj.nonmaxSuppression); - obj.info()->addParam(obj, "type", obj.type, static_cast(FastFeatureDetector::TYPE_9_16))); + obj.info()->addParam(obj, "type", obj.type)); /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/modules/features2d/test/test_fast.cpp b/modules/features2d/test/test_fast.cpp index 671e66d5f4..761abfcca3 100644 --- a/modules/features2d/test/test_fast.cpp +++ b/modules/features2d/test/test_fast.cpp @@ -75,8 +75,8 @@ void CV_FastTest::run( int ) vector keypoints1; vector keypoints2; - FAST(gray1, keypoints1, 30, type); - FAST(gray2, keypoints2, 30, type); + FAST(gray1, keypoints1, 30, true, type); + FAST(gray2, keypoints2, 30, true, type); for(size_t i = 0; i < keypoints1.size(); ++i) { diff --git a/modules/features2d/test/test_nearestneighbors.cpp b/modules/features2d/test/test_nearestneighbors.cpp index 8a0482218f..45131eff2e 100644 --- a/modules/features2d/test/test_nearestneighbors.cpp +++ b/modules/features2d/test/test_nearestneighbors.cpp @@ -200,7 +200,7 @@ int CV_KDTreeTest_CPP::checkGetPoins( const Mat& data ) int CV_KDTreeTest_CPP::checkFindBoxed() { - vector min( dims, minValue), max(dims, maxValue); + vector min( dims, static_cast(minValue)), max(dims, static_cast(maxValue)); vector indices; tr->findOrthoRange( min, max, indices ); // TODO check indices @@ -214,8 +214,8 @@ int CV_KDTreeTest_CPP::findNeighbors( Mat& points, Mat& neighbors ) const int emax = 20; Mat neighbors2( neighbors.size(), CV_32SC1 ); int j; - vector min(points.cols, minValue); - vector max(points.cols, maxValue); + vector min(points.cols, static_cast(minValue)); + vector max(points.cols, static_cast(maxValue)); for( int pi = 0; pi < points.rows; pi++ ) { // 1st way diff --git a/modules/features2d/test/test_rotation_and_scale_invariance.cpp b/modules/features2d/test/test_rotation_and_scale_invariance.cpp index d98431ba57..48dddd3eee 100644 --- a/modules/features2d/test/test_rotation_and_scale_invariance.cpp +++ b/modules/features2d/test/test_rotation_and_scale_invariance.cpp @@ -54,7 +54,7 @@ static Mat generateHomography(float angle) { // angle - rotation around Oz in degrees - float angleRadian = angle * CV_PI / 180.; + float angleRadian = static_cast(angle * CV_PI / 180); Mat H = Mat::eye(3, 3, CV_32FC1); H.at(0,0) = H.at(1,1) = std::cos(angleRadian); H.at(0,1) = -std::sin(angleRadian); @@ -69,8 +69,8 @@ Mat rotateImage(const Mat& srcImage, float angle, Mat& dstImage, Mat& dstMask) // angle - rotation around Oz in degrees float diag = std::sqrt(static_cast(srcImage.cols * srcImage.cols + srcImage.rows * srcImage.rows)); Mat LUShift = Mat::eye(3, 3, CV_32FC1); // left up - LUShift.at(0,2) = -srcImage.cols/2; - LUShift.at(1,2) = -srcImage.rows/2; + LUShift.at(0,2) = static_cast(-srcImage.cols/2); + LUShift.at(1,2) = static_cast(-srcImage.rows/2); Mat RDShift = Mat::eye(3, 3, CV_32FC1); // right down RDShift.at(0,2) = diag/2; RDShift.at(1,2) = diag/2; @@ -114,7 +114,7 @@ void scaleKeyPoints(const vector& src, vector& dst, float sc static float calcCirclesIntersectArea(const Point2f& p0, float r0, const Point2f& p1, float r1) { - float c = norm(p0 - p1), sqr_c = c * c; + float c = static_cast(norm(p0 - p1)), sqr_c = c * c; float sqr_r0 = r0 * r0; float sqr_r1 = r1 * r1; @@ -125,7 +125,7 @@ float calcCirclesIntersectArea(const Point2f& p0, float r0, const Point2f& p1, f float minR = std::min(r0, r1); float maxR = std::max(r0, r1); if(c + minR <= maxR) - return CV_PI * minR * minR; + return static_cast(CV_PI * minR * minR); float cos_halfA0 = (sqr_r0 + sqr_c - sqr_r1) / (2 * r0 * c); float cos_halfA1 = (sqr_r1 + sqr_c - sqr_r0) / (2 * r1 * c); @@ -133,15 +133,15 @@ float calcCirclesIntersectArea(const Point2f& p0, float r0, const Point2f& p1, f float A0 = 2 * acos(cos_halfA0); float A1 = 2 * acos(cos_halfA1); - return 0.5 * sqr_r0 * (A0 - sin(A0)) + - 0.5 * sqr_r1 * (A1 - sin(A1)); + return 0.5f * sqr_r0 * (A0 - sin(A0)) + + 0.5f * sqr_r1 * (A1 - sin(A1)); } static float calcIntersectRatio(const Point2f& p0, float r0, const Point2f& p1, float r1) { float intersectArea = calcCirclesIntersectArea(p0, r0, p1, r1); - float unionArea = CV_PI * (r0 * r0 + r1 * r1) - intersectArea; + float unionArea = static_cast(CV_PI) * (r0 * r0 + r1 * r1) - intersectArea; return intersectArea / unionArea; } @@ -160,7 +160,7 @@ void matchKeyPoints(const vector& keypoints0, const Mat& H, matches.clear(); vector usedMask(keypoints1.size(), 0); - for(size_t i0 = 0; i0 < keypoints0.size(); i0++) + for(int i0 = 0; i0 < static_cast(keypoints0.size()); i0++) { int nearestPointIndex = -1; float maxIntersectRatio = 0.f; @@ -176,7 +176,7 @@ void matchKeyPoints(const vector& keypoints0, const Mat& H, if(intersectRatio > maxIntersectRatio) { maxIntersectRatio = intersectRatio; - nearestPointIndex = i1; + nearestPointIndex = static_cast(i1); } } @@ -222,7 +222,7 @@ protected: const int maxAngle = 360, angleStep = 15; for(int angle = 0; angle < maxAngle; angle += angleStep) { - Mat H = rotateImage(image0, angle, image1, mask1); + Mat H = rotateImage(image0, static_cast(angle), image1, mask1); vector keypoints1; featureDetector->detect(image1, keypoints1, mask1); @@ -339,10 +339,10 @@ protected: const int maxAngle = 360, angleStep = 15; for(int angle = 0; angle < maxAngle; angle += angleStep) { - Mat H = rotateImage(image0, angle, image1, mask1); + Mat H = rotateImage(image0, static_cast(angle), image1, mask1); vector keypoints1; - rotateKeyPoints(keypoints0, H, angle, keypoints1); + rotateKeyPoints(keypoints0, H, static_cast(angle), keypoints1); Mat descriptors1; descriptorExtractor->compute(image1, keypoints1, descriptors1); @@ -457,7 +457,7 @@ protected: keyPointMatchesCount++; // Check does this inlier have consistent sizes - const float maxSizeDiff = 0.8;//0.9f; // grad + const float maxSizeDiff = 0.8f;//0.9f; // grad float size0 = keypoints0[matches[m].trainIdx].size; float size1 = osiKeypoints1[matches[m].queryIdx].size; CV_Assert(size0 > 0 && size1 > 0); @@ -545,7 +545,7 @@ protected: resize(image0, image1, Size(), 1./scale, 1./scale); vector keypoints1; - scaleKeyPoints(keypoints0, keypoints1, 1./scale); + scaleKeyPoints(keypoints0, keypoints1, 1.0f/scale); Mat descriptors1; descriptorExtractor->compute(image1, keypoints1, descriptors1); diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index 979aaa3723..f938ca239e 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -23,8 +23,8 @@ void generateMap(cv::Mat& map_x, cv::Mat& map_y, int remapMode) case HALF_SIZE: if (i > map_x.cols*0.25 && i < map_x.cols*0.75 && j > map_x.rows*0.25 && j < map_x.rows*0.75) { - map_x.at(j,i) = 2 * (i - map_x.cols * 0.25) + 0.5; - map_y.at(j,i) = 2 * (j - map_x.rows * 0.25) + 0.5; + map_x.at(j,i) = 2 * (i - map_x.cols * 0.25f) + 0.5f; + map_y.at(j,i) = 2 * (j - map_x.rows * 0.25f) + 0.5f; } else { @@ -33,16 +33,16 @@ void generateMap(cv::Mat& map_x, cv::Mat& map_y, int remapMode) } break; case UPSIDE_DOWN: - map_x.at(j,i) = i; - map_y.at(j,i) = map_x.rows - j; + map_x.at(j,i) = static_cast(i); + map_y.at(j,i) = static_cast(map_x.rows - j); break; case REFLECTION_X: - map_x.at(j,i) = map_x.cols - i; - map_y.at(j,i) = j; + map_x.at(j,i) = static_cast(map_x.cols - i); + map_y.at(j,i) = static_cast(j); break; case REFLECTION_BOTH: - map_x.at(j,i) = map_x.cols - i; - map_y.at(j,i) = map_x.rows - j; + map_x.at(j,i) = static_cast(map_x.cols - i); + map_y.at(j,i) = static_cast(map_x.rows - j); break; } // end of switch } @@ -1619,7 +1619,7 @@ PERF_TEST_P(Sz_DoSort, ImgProc_HoughLines, Combine(GPU_TYPICAL_MAT_SIZES, Bool() const bool doSort = GET_PARAM(1); const float rho = 1.0f; - const float theta = CV_PI / 180.0f; + const float theta = static_cast(CV_PI / 180.0); const int threshold = 300; cv::RNG rng(123456789); diff --git a/modules/gpu/perf/perf_labeling.cpp b/modules/gpu/perf/perf_labeling.cpp index f17dd7d0af..bbab5ecfa4 100644 --- a/modules/gpu/perf/perf_labeling.cpp +++ b/modules/gpu/perf/perf_labeling.cpp @@ -31,6 +31,11 @@ struct GreedyLabeling int d = a - b; return lo <= d && d <= hi; } + + private: + InInterval& operator=(const InInterval&); + + }; GreedyLabeling(cv::Mat img) @@ -45,7 +50,7 @@ struct GreedyLabeling int cc = -1; int* dist_labels = (int*)labels.data; - int pitch = labels.step1(); + int pitch = static_cast(labels.step1()); unsigned char* source = (unsigned char*)image.data; int width = image.cols; @@ -82,7 +87,7 @@ struct GreedyLabeling *top++ = dot::make(p.x, p.y + 1); //top - if( p.y > 0 && dl[-pitch] == -1 && inInt(sp[0], sp[-image.step1()])) + if( p.y > 0 && dl[-pitch] == -1 && inInt(sp[0], sp[-static_cast(image.step1())])) *top++ = dot::make(p.x, p.y - 1); p = *--top; diff --git a/modules/gpu/perf/perf_video.cpp b/modules/gpu/perf/perf_video.cpp index 7faea0b880..8346d25f42 100644 --- a/modules/gpu/perf/perf_video.cpp +++ b/modules/gpu/perf/perf_video.cpp @@ -427,7 +427,7 @@ PERF_TEST_P(Video_Cn_LearningRate, Video_MOG, Combine(Values("gpu/video/768x576. { string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); int cn = GET_PARAM(1); - double learningRate = GET_PARAM(2); + float learningRate = static_cast(GET_PARAM(2)); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); diff --git a/samples/cpp/bagofwords_classification.cpp b/samples/cpp/bagofwords_classification.cpp index 559e77bfcf..071c2a1733 100644 --- a/samples/cpp/bagofwords_classification.cpp +++ b/samples/cpp/bagofwords_classification.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #if defined WIN32 || defined _WIN32 #define WIN32_LEAN_AND_MEAN diff --git a/samples/gpu/bgfg_segm.cpp b/samples/gpu/bgfg_segm.cpp index 7c5e148f77..4e4c52096c 100644 --- a/samples/gpu/bgfg_segm.cpp +++ b/samples/gpu/bgfg_segm.cpp @@ -86,7 +86,7 @@ int main(int argc, const char** argv) break; case MOG: - mog(d_frame, d_fgmask, 0.01); + mog(d_frame, d_fgmask, 0.01f); break; case MOG2: @@ -127,7 +127,7 @@ int main(int argc, const char** argv) break; case MOG: - mog(d_frame, d_fgmask, 0.01); + mog(d_frame, d_fgmask, 0.01f); mog.getBackgroundImage(d_bgimg); break; @@ -162,7 +162,7 @@ int main(int argc, const char** argv) if (!bgimg.empty()) imshow("mean background image", bgimg); - char key = waitKey(30); + int key = waitKey(30); if (key == 27) break; } diff --git a/samples/gpu/performance/tests.cpp b/samples/gpu/performance/tests.cpp index aefd9572f6..e117202838 100644 --- a/samples/gpu/performance/tests.cpp +++ b/samples/gpu/performance/tests.cpp @@ -1341,7 +1341,7 @@ TEST(MOG) cv::gpu::MOG_GPU d_mog; cv::gpu::GpuMat d_foreground; - d_mog(d_frame, d_foreground, 0.01); + d_mog(d_frame, d_foreground, 0.01f); while (!TestSystem::instance().stop()) { @@ -1350,7 +1350,7 @@ TEST(MOG) TestSystem::instance().gpuOn(); - d_mog(d_frame, d_foreground, 0.01); + d_mog(d_frame, d_foreground, 0.01f); TestSystem::instance().gpuOff(); } From 92795ba4769e77a9833a06fcd67c444f3c9c2122 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Wed, 22 Aug 2012 11:49:21 +0400 Subject: [PATCH 051/163] parallel version of remap, resize, warpaffine, warpPerspective. Some optimization for 2x decimation in resize algorithm --- modules/imgproc/perf/perf_remap.cpp | 68 + modules/imgproc/perf/perf_resize.cpp | 32 +- modules/imgproc/src/imgwarp.cpp | 1873 +++++++++++++++----------- 3 files changed, 1192 insertions(+), 781 deletions(-) create mode 100644 modules/imgproc/perf/perf_remap.cpp diff --git a/modules/imgproc/perf/perf_remap.cpp b/modules/imgproc/perf/perf_remap.cpp new file mode 100644 index 0000000000..e789296735 --- /dev/null +++ b/modules/imgproc/perf/perf_remap.cpp @@ -0,0 +1,68 @@ +#include "perf_precomp.hpp" + +using namespace std; +using namespace cv; +using namespace perf; +using namespace testing; +using std::tr1::make_tuple; +using std::tr1::get; + +CV_ENUM(MatrixType, CV_16UC1, CV_16SC1, CV_32FC1) +CV_ENUM(MapType, CV_16SC2, CV_32FC1, CV_32FC2) +CV_ENUM(InterType, INTER_LINEAR, INTER_CUBIC, INTER_LANCZOS4, INTER_NEAREST) + +typedef TestBaseWithParam< tr1::tuple > TestRemap; + +PERF_TEST_P( TestRemap, Remap, + Combine( + Values( szVGA, sz1080p ), + ValuesIn( MatrixType::all() ), + ValuesIn( MapType::all() ), + ValuesIn( InterType::all() ) + ) +) +{ + Size sz; + int src_type, map1_type, inter_type; + + sz = get<0>(GetParam()); + src_type = get<1>(GetParam()); + map1_type = get<2>(GetParam()); + inter_type = get<3>(GetParam()); + + Mat src(sz, src_type); + Mat map1(sz, map1_type); + Mat dst(sz, src_type); + + Mat map2(map1_type == CV_32FC1 ? sz : Size(), CV_32FC1); + + RNG rng; + rng.fill(src, RNG::UNIFORM, 0, 256); + + for (int j = 0; j < map1.rows; ++j) + for (int i = 0; i < map1.cols; ++i) + switch (map1_type) + { + case CV_32FC1: + map1.at(j, i) = src.cols - i; + map2.at(j, i) = j; + break; + case CV_32FC2: + map1.at(j, i)[0] = src.cols - i; + map1.at(j, i)[1] = j; + break; + case CV_16SC2: + map1.at(j, i)[0] = src.cols - i; + map1.at(j, i)[1] = j; + break; + default: + CV_Assert(0); + } + + + declare.in(src, WARMUP_RNG).out(dst).time(20); + + TEST_CYCLE() remap(src, dst, map1, map2, inter_type); + + SANITY_CHECK(dst); +} diff --git a/modules/imgproc/perf/perf_resize.cpp b/modules/imgproc/perf/perf_resize.cpp index fba12942f2..15be0eae17 100644 --- a/modules/imgproc/perf/perf_resize.cpp +++ b/modules/imgproc/perf/perf_resize.cpp @@ -59,11 +59,11 @@ PERF_TEST_P(MatInfo_Size_Size, resizeDownLinear, typedef tr1::tuple MatInfo_Size_Scale_t; typedef TestBaseWithParam MatInfo_Size_Scale; -PERF_TEST_P(MatInfo_Size_Scale, resizeAreaFast, +PERF_TEST_P(MatInfo_Size_Scale, ResizeAreaFast, testing::Combine( testing::Values(CV_8UC1, CV_8UC4), testing::Values(szVGA, szqHD, sz720p, sz1080p), - testing::Values(2, 4) + testing::Values(2) ) ) { @@ -84,3 +84,31 @@ PERF_TEST_P(MatInfo_Size_Scale, resizeAreaFast, //difference equal to 1 is allowed because of different possible rounding modes: round-to-nearest vs bankers' rounding SANITY_CHECK(dst, 1); } + + +typedef TestBaseWithParam > MatInfo_Size_Scale_Area; + +PERF_TEST_P(MatInfo_Size_Scale_Area, ResizeArea, + testing::Combine( + testing::Values(CV_8UC1, CV_8UC4), + testing::Values(szVGA, szqHD, sz720p, sz1080p), + testing::Values(2.4, 3.4, 1.3) + ) + ) +{ + int matType = get<0>(GetParam()); + Size from = get<1>(GetParam()); + double scale = get<2>(GetParam()); + + cv::Mat src(from, matType); + + Size to(cvRound(from.width * scale), cvRound(from.height * scale)); + cv::Mat dst(to, matType); + + declare.in(src, WARMUP_RNG).out(dst); + + TEST_CYCLE() resize(src, dst, dst.size(), 0, 0, INTER_AREA); + + //difference equal to 1 is allowed because of different possible rounding modes: round-to-nearest vs bankers' rounding + SANITY_CHECK(dst, 1); +} diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index e5a47e1a2d..1e45fadf26 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -240,6 +240,99 @@ template struct FixedPtCast * Resize * \****************************************************************************************/ +class resizeNNInvoker : + public ParallelLoopBody +{ +public: + resizeNNInvoker(const Mat& _src, Mat &_dst, int *_x_ofs, int _pix_size4, double _ify) : + ParallelLoopBody(), src(_src), dst(_dst), x_ofs(_x_ofs), pix_size4(_pix_size4), + ify(_ify) + { + } + + virtual void operator() (const Range& range) const + { + Size ssize = src.size(), dsize = dst.size(); + int y, x, pix_size = (int)src.elemSize(); + + for( y = range.start; y < range.end; y++ ) + { + uchar* D = dst.data + dst.step*y; + int sy = std::min(cvFloor(y*ify), ssize.height-1); + const uchar* S = src.data + src.step*sy; + + switch( pix_size ) + { + case 1: + for( x = 0; x <= dsize.width - 2; x += 2 ) + { + uchar t0 = S[x_ofs[x]]; + uchar t1 = S[x_ofs[x+1]]; + D[x] = t0; + D[x+1] = t1; + } + + for( ; x < dsize.width; x++ ) + D[x] = S[x_ofs[x]]; + break; + case 2: + for( x = 0; x < dsize.width; x++ ) + *(ushort*)(D + x*2) = *(ushort*)(S + x_ofs[x]); + break; + case 3: + for( x = 0; x < dsize.width; x++, D += 3 ) + { + const uchar* _tS = S + x_ofs[x]; + D[0] = _tS[0]; D[1] = _tS[1]; D[2] = _tS[2]; + } + break; + case 4: + for( x = 0; x < dsize.width; x++ ) + *(int*)(D + x*4) = *(int*)(S + x_ofs[x]); + break; + case 6: + for( x = 0; x < dsize.width; x++, D += 6 ) + { + const ushort* _tS = (const ushort*)(S + x_ofs[x]); + ushort* _tD = (ushort*)D; + _tD[0] = _tS[0]; _tD[1] = _tS[1]; _tD[2] = _tS[2]; + } + break; + case 8: + for( x = 0; x < dsize.width; x++, D += 8 ) + { + const int* _tS = (const int*)(S + x_ofs[x]); + int* _tD = (int*)D; + _tD[0] = _tS[0]; _tD[1] = _tS[1]; + } + break; + case 12: + for( x = 0; x < dsize.width; x++, D += 12 ) + { + const int* _tS = (const int*)(S + x_ofs[x]); + int* _tD = (int*)D; + _tD[0] = _tS[0]; _tD[1] = _tS[1]; _tD[2] = _tS[2]; + } + break; + default: + for( x = 0; x < dsize.width; x++, D += pix_size ) + { + const int* _tS = (const int*)(S + x_ofs[x]); + int* _tD = (int*)D; + for( int k = 0; k < pix_size4; k++ ) + _tD[k] = _tS[k]; + } + } + } + } + +private: + const Mat src; + Mat dst; + int* x_ofs, pix_size4; + double ify; +}; + static void resizeNN( const Mat& src, Mat& dst, double fx, double fy ) { @@ -249,83 +342,17 @@ resizeNN( const Mat& src, Mat& dst, double fx, double fy ) int pix_size = (int)src.elemSize(); int pix_size4 = (int)(pix_size / sizeof(int)); double ifx = 1./fx, ify = 1./fy; - int x, y; + int x; for( x = 0; x < dsize.width; x++ ) { int sx = cvFloor(x*ifx); x_ofs[x] = std::min(sx, ssize.width-1)*pix_size; } - - for( y = 0; y < dsize.height; y++ ) - { - uchar* D = dst.data + dst.step*y; - int sy = std::min(cvFloor(y*ify), ssize.height-1); - const uchar* S = src.data + src.step*sy; - - switch( pix_size ) - { - case 1: - for( x = 0; x <= dsize.width - 2; x += 2 ) - { - uchar t0 = S[x_ofs[x]]; - uchar t1 = S[x_ofs[x+1]]; - D[x] = t0; - D[x+1] = t1; - } - - for( ; x < dsize.width; x++ ) - D[x] = S[x_ofs[x]]; - break; - case 2: - for( x = 0; x < dsize.width; x++ ) - *(ushort*)(D + x*2) = *(ushort*)(S + x_ofs[x]); - break; - case 3: - for( x = 0; x < dsize.width; x++, D += 3 ) - { - const uchar* _tS = S + x_ofs[x]; - D[0] = _tS[0]; D[1] = _tS[1]; D[2] = _tS[2]; - } - break; - case 4: - for( x = 0; x < dsize.width; x++ ) - *(int*)(D + x*4) = *(int*)(S + x_ofs[x]); - break; - case 6: - for( x = 0; x < dsize.width; x++, D += 6 ) - { - const ushort* _tS = (const ushort*)(S + x_ofs[x]); - ushort* _tD = (ushort*)D; - _tD[0] = _tS[0]; _tD[1] = _tS[1]; _tD[2] = _tS[2]; - } - break; - case 8: - for( x = 0; x < dsize.width; x++, D += 8 ) - { - const int* _tS = (const int*)(S + x_ofs[x]); - int* _tD = (int*)D; - _tD[0] = _tS[0]; _tD[1] = _tS[1]; - } - break; - case 12: - for( x = 0; x < dsize.width; x++, D += 12 ) - { - const int* _tS = (const int*)(S + x_ofs[x]); - int* _tD = (int*)D; - _tD[0] = _tS[0]; _tD[1] = _tS[1]; _tD[2] = _tS[2]; - } - break; - default: - for( x = 0; x < dsize.width; x++, D += pix_size ) - { - const int* _tS = (const int*)(S + x_ofs[x]); - int* _tD = (int*)D; - for( int k = 0; k < pix_size4; k++ ) - _tD[k] = _tS[k]; - } - } - } + + Range range(0, dsize.height); + resizeNNInvoker invoker(src, dst, x_ofs, pix_size4, ify); + parallel_for_(range, invoker); } @@ -1092,6 +1119,82 @@ static inline int clip(int x, int a, int b) static const int MAX_ESIZE=16; +template +class resizeGeneric_Invoker : + public ParallelLoopBody +{ +public: + typedef typename HResize::value_type T; + typedef typename HResize::buf_type WT; + typedef typename HResize::alpha_type AT; + + resizeGeneric_Invoker(const Mat& _src, Mat &_dst, const int *_xofs, const int *_yofs, + const AT* _alpha, const AT* __beta, const Size& _ssize, const Size &_dsize, + int _ksize, int _xmin, int _xmax) : + ParallelLoopBody(), src(_src), dst(_dst), xofs(_xofs), yofs(_yofs), + alpha(_alpha), _beta(__beta), ssize(_ssize), dsize(_dsize), + ksize(_ksize), xmin(_xmin), xmax(_xmax) + { + } + + virtual void operator() (const Range& range) const + { + int dy, cn = src.channels(); + HResize hresize; + VResize vresize; + + int bufstep = (int)alignSize(dsize.width, 16); + AutoBuffer _buffer(bufstep*ksize); + const T* srows[MAX_ESIZE]={0}; + WT* rows[MAX_ESIZE]={0}; + int prev_sy[MAX_ESIZE]; + + for(int k = 0; k < ksize; k++ ) + { + prev_sy[k] = -1; + rows[k] = (WT*)_buffer + bufstep*k; + } + + const AT* beta = _beta + ksize * range.start; + + for( dy = range.start; dy < range.end; dy++, beta += ksize ) + { + int sy0 = yofs[dy], k0=ksize, k1=0, ksize2 = ksize/2; + + for(int k = 0; k < ksize; k++ ) + { + int sy = clip(sy0 - ksize2 + 1 + k, 0, ssize.height); + for( k1 = std::max(k1, k); k1 < ksize; k1++ ) + { + if( sy == prev_sy[k1] ) // if the sy-th row has been computed already, reuse it. + { + if( k1 > k ) + memcpy( rows[k], rows[k1], bufstep*sizeof(rows[0][0]) ); + break; + } + } + if( k1 == ksize ) + k0 = std::min(k0, k); // remember the first row that needs to be computed + srows[k] = (T*)(src.data + src.step*sy); + prev_sy[k] = sy; + } + + if( k0 < ksize ) + hresize( (const T**)(srows + k0), (WT**)(rows + k0), ksize - k0, xofs, (const AT*)(alpha), + ssize.width, dsize.width, cn, xmin, xmax ); + vresize( (const WT**)rows, (T*)(dst.data + dst.step*dy), beta, dsize.width ); + } + } + +private: + const Mat src; + Mat dst; + const int* xofs, *yofs; + const AT* alpha, *_beta; + const Size ssize, dsize; + const int ksize, xmin, xmax; +}; + template static void resizeGeneric_( const Mat& src, Mat& dst, const int* xofs, const void* _alpha, @@ -1102,124 +1205,178 @@ static void resizeGeneric_( const Mat& src, Mat& dst, typedef typename HResize::buf_type WT; typedef typename HResize::alpha_type AT; - const AT* alpha = (const AT*)_alpha; const AT* beta = (const AT*)_beta; Size ssize = src.size(), dsize = dst.size(); int cn = src.channels(); ssize.width *= cn; dsize.width *= cn; - int bufstep = (int)alignSize(dsize.width, 16); - AutoBuffer _buffer(bufstep*ksize); - const T* srows[MAX_ESIZE]={0}; - WT* rows[MAX_ESIZE]={0}; - int prev_sy[MAX_ESIZE]; - int dy; xmin *= cn; xmax *= cn; - - HResize hresize; - VResize vresize; - - for(int k = 0; k < ksize; k++ ) - { - prev_sy[k] = -1; - rows[k] = (WT*)_buffer + bufstep*k; - } - // image resize is a separable operation. In case of not too strong - for( dy = 0; dy < dsize.height; dy++, beta += ksize ) - { - int sy0 = yofs[dy], k0=ksize, k1=0, ksize2 = ksize/2; - - for(int k = 0; k < ksize; k++ ) - { - int sy = clip(sy0 - ksize2 + 1 + k, 0, ssize.height); - for( k1 = std::max(k1, k); k1 < ksize; k1++ ) - { - if( sy == prev_sy[k1] ) // if the sy-th row has been computed already, reuse it. - { - if( k1 > k ) - memcpy( rows[k], rows[k1], bufstep*sizeof(rows[0][0]) ); - break; - } - } - if( k1 == ksize ) - k0 = std::min(k0, k); // remember the first row that needs to be computed - srows[k] = (const T*)(src.data + src.step*sy); - prev_sy[k] = sy; - } - - if( k0 < ksize ) - hresize( srows + k0, rows + k0, ksize - k0, xofs, alpha, - ssize.width, dsize.width, cn, xmin, xmax ); - vresize( (const WT**)rows, (T*)(dst.data + dst.step*dy), beta, dsize.width ); - } + + Range range(0, dsize.height); + resizeGeneric_Invoker invoker(src, dst, xofs, yofs, (const AT*)_alpha, beta, + ssize, dsize, ksize, xmin, xmax); + parallel_for_(range, invoker); } +template +struct ResizeAreaFastNoVec +{ + ResizeAreaFastNoVec(int /*_scale_x*/, int /*_scale_y*/, + int /*_cn*/, int /*_step*//*, const int**/ /*_ofs*/) { } + int operator() (const T* /*S*/, T* /*D*/, int /*w*/) const { return 0; } +}; -template +template +struct ResizeAreaFast_2x2_8u +{ + ResizeAreaFast_2x2_8u(int _scale_x, int _scale_y, int _cn, int _step/*, const int* _ofs*/) : + scale_x(_scale_x), scale_y(_scale_y), cn(_cn), step(_step)/*, ofs(_ofs)*/ + { + fast_mode = scale_x == 2 && scale_y == 2 && (cn == 1 || cn == 3 || cn == 4); + } + + int operator() (const T* S, T* D, int w) const + { + if( !fast_mode ) + return 0; + + const T* nextS = S + step; + int dx = 0; + + if (cn == 1) + for( ; dx < w; ++dx ) + { + int index = dx*2; + D[dx] = (S[index] + S[index+1] + nextS[index] + nextS[index+1] + 2) >> 2; + } + else if (cn == 3) + for( ; dx < w; dx += 3 ) + { + int index = dx*2; + D[dx] = (S[index] + S[index+3] + nextS[index] + nextS[index+3] + 2) >> 2; + D[dx+1] = (S[index+1] + S[index+4] + nextS[index+1] + nextS[index+4] + 2) >> 2; + D[dx+2] = (S[index+2] + S[index+5] + nextS[index+2] + nextS[index+5] + 2) >> 2; + } + else + { + assert(cn == 4); + for( ; dx < w; dx += 4 ) + { + int index = dx*2; + D[dx] = (S[index] + S[index+3] + nextS[index] + nextS[index+3] + 2) >> 2; + D[dx+1] = (S[index+1] + S[index+4] + nextS[index+1] + nextS[index+4] + 2) >> 2; + D[dx+2] = (S[index+2] + S[index+5] + nextS[index+2] + nextS[index+5] + 2) >> 2; + D[dx+3] = (S[index+3] + S[index+6] + nextS[index+3] + nextS[index+6] + 2) >> 2; + } + } + + return dx; + } + +private: + const int scale_x, scale_y; + const int cn; + bool fast_mode; + const int step; +}; + +template +class resizeAreaFast_Invoker : + public ParallelLoopBody +{ +public: + resizeAreaFast_Invoker(const Mat &_src, Mat &_dst, + int _scale_x, int _scale_y, const int* _ofs, const int* _xofs) : + ParallelLoopBody(), src(_src), dst(_dst), scale_x(_scale_x), + scale_y(_scale_y), ofs(_ofs), xofs(_xofs) + { + } + + virtual void operator() (const Range& range) const + { + Size ssize = src.size(), dsize = dst.size(); + int cn = src.channels(); + int area = scale_x*scale_y; + float scale = 1.f/(area); + int dwidth1 = (ssize.width/scale_x)*cn; + dsize.width *= cn; + ssize.width *= cn; + int dy, dx, k = 0; + + VecOp vop(scale_x, scale_y, src.channels(), src.step/*, area_ofs*/); + + for( dy = range.start; dy < range.end; dy++ ) + { + T* D = (T*)(dst.data + dst.step*dy); + int sy0 = dy*scale_y; + int w = sy0 + scale_y <= ssize.height ? dwidth1 : 0; + + if( sy0 >= ssize.height ) + { + for( dx = 0; dx < dsize.width; dx++ ) + D[dx] = 0; + continue; + } + + dx = vop((const T*)(src.data + src.step * sy0), D, w); + for( ; dx < w; dx++ ) + { + const T* S = (const T*)(src.data + src.step * sy0) + xofs[dx]; + WT sum = 0; + k = 0; + #if CV_ENABLE_UNROLLED + for( ; k <= area - 4; k += 4 ) + sum += S[ofs[k]] + S[ofs[k+1]] + S[ofs[k+2]] + S[ofs[k+3]]; + #endif + for( ; k < area; k++ ) + sum += S[ofs[k]]; + + D[dx] = saturate_cast(sum * scale); + } + + for( ; dx < dsize.width; dx++ ) + { + WT sum = 0; + int count = 0, sx0 = xofs[dx]; + if( sx0 >= ssize.width ) + D[dx] = 0; + + for( int sy = 0; sy < scale_y; sy++ ) + { + if( sy0 + sy >= ssize.height ) + break; + const T* S = (const T*)(src.data + src.step*(sy0 + sy)) + sx0; + for( int sx = 0; sx < scale_x*cn; sx += cn ) + { + if( sx0 + sx >= ssize.width ) + break; + sum += S[sx]; + count++; + } + } + + D[dx] = saturate_cast((float)sum/count); + } + } + } + +private: + const Mat src; + Mat dst; + const int scale_x, scale_y; + const int *ofs, *xofs; +}; + +template static void resizeAreaFast_( const Mat& src, Mat& dst, const int* ofs, const int* xofs, int scale_x, int scale_y ) { - Size ssize = src.size(), dsize = dst.size(); - int cn = src.channels(); - int dy, dx, k = 0; - int area = scale_x*scale_y; - float scale = 1.f/(scale_x*scale_y); - int dwidth1 = (ssize.width/scale_x)*cn; - dsize.width *= cn; - ssize.width *= cn; - - for( dy = 0; dy < dsize.height; dy++ ) - { - T* D = (T*)(dst.data + dst.step*dy); - int sy0 = dy*scale_y, w = sy0 + scale_y <= ssize.height ? dwidth1 : 0; - if( sy0 >= ssize.height ) - { - for( dx = 0; dx < dsize.width; dx++ ) - D[dx] = 0; - continue; - } - - for( dx = 0; dx < w; dx++ ) - { - const T* S = (const T*)(src.data + src.step*sy0) + xofs[dx]; - WT sum = 0; - k=0; - #if CV_ENABLE_UNROLLED - for( ; k <= area - 4; k += 4 ) - sum += S[ofs[k]] + S[ofs[k+1]] + S[ofs[k+2]] + S[ofs[k+3]]; - #endif - for( ; k < area; k++ ) - sum += S[ofs[k]]; - - D[dx] = saturate_cast(sum*scale); - } - - for( ; dx < dsize.width; dx++ ) - { - WT sum = 0; - int count = 0, sx0 = xofs[dx]; - if( sx0 >= ssize.width ) - D[dx] = 0; - - for( int sy = 0; sy < scale_y; sy++ ) - { - if( sy0 + sy >= ssize.height ) - break; - const T* S = (const T*)(src.data + src.step*(sy0 + sy)) + sx0; - for( int sx = 0; sx < scale_x*cn; sx += cn ) - { - if( sx0 + sx >= ssize.width ) - break; - sum += S[sx]; - count++; - } - } - - D[dx] = saturate_cast((float)sum/count); - } - } + Range range(0, dst.rows); + resizeAreaFast_Invoker invoker(src, dst, scale_x, + scale_y, ofs, xofs); + parallel_for_(range, invoker); } struct DecimateAlpha @@ -1228,222 +1385,260 @@ struct DecimateAlpha float alpha; }; +template +class resizeArea_Invoker : + public ParallelLoopBody +{ +public: + resizeArea_Invoker(const Mat& _src, Mat& _dst, const DecimateAlpha* _xofs, + int _xofs_count, double _scale_y_ +#ifdef HAVE_TBB + , const int* _yofs, const int* _cur_dy_ofs +#endif + ) : + ParallelLoopBody(), src(_src), dst(_dst), xofs(_xofs), + xofs_count(_xofs_count), scale_y_(_scale_y_) +#ifdef HAVE_TBB + , yofs(_yofs), cur_dy_ofs(_cur_dy_ofs) +#endif + { + } + + virtual void operator() (const Range& range) const + { + Size ssize = src.size(), dsize = dst.size(); + int cn = src.channels(); + dsize.width *= cn; + AutoBuffer _buffer(dsize.width*2); + WT *buf = _buffer, *sum = buf + dsize.width; + int k, sy, dx, cur_dy = 0, num = sizeof(WT) * dsize.width; + WT scale_y = (WT)scale_y_; + + CV_Assert( cn <= 4 ); + memset(buf, 0, num * 2); + +#ifdef HAVE_TBB + sy = yofs[range.start]; + cur_dy = cur_dy_ofs[sy]; + for( ; sy < range.start; sy++ ) + { + const T* S = (const T*)(src.data + src.step * sy); + memset(buf, 0, num); + + if( cn == 1 ) + for( k = 0; k < xofs_count; k++ ) + { + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + buf[dxn] += S[xofs[k].si]*alpha; + } + else if( cn == 2 ) + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + buf[dxn] = t0; buf[dxn+1] = t1; + } + else if( cn == 3 ) + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + WT t2 = buf[dxn+2] + S[sxn+2]*alpha; + + buf[dxn] = t0; buf[dxn+1] = t1; buf[dxn+2] = t2; + } + else + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + + buf[dxn] = t0; buf[dxn+1] = t1; + + t0 = buf[dxn+2] + S[sxn+2]*alpha; + t1 = buf[dxn+3] + S[sxn+3]*alpha; + + buf[dxn+2] = t0; buf[dxn+3] = t1; + } + + if( (cur_dy + 1)*scale_y <= sy + 1 || sy == ssize.height - 1 ) + { + WT beta = std::max(sy + 1 - (cur_dy + 1) * scale_y, (WT)0); + if( fabs(beta) < 1e-3 ) + { + if(cur_dy >= dsize.height) + break; + memset(sum, 0, num); + } + else + for( dx = 0; dx < dsize.width; dx++ ) + sum[dx] = buf[dx] * beta; + cur_dy++; + } + else + { + for( dx = 0; dx <= dsize.width - 2; dx += 2 ) + { + WT t0 = sum[dx] + buf[dx]; + WT t1 = sum[dx+1] + buf[dx+1]; + sum[dx] = t0; sum[dx+1] = t1; + } + for( ; dx < dsize.width; dx++ ) + sum[dx] += buf[dx]; + } + } +#endif + + for( sy = range.start; sy < range.end; sy++ ) + { + const T* S = (const T*)(src.data + src.step * sy); + memset(buf, 0, num); + + if( cn == 1 ) + for( k = 0; k < xofs_count; k++ ) + { + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + buf[dxn] += S[xofs[k].si]*alpha; + } + else if( cn == 2 ) + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + buf[dxn] = t0; buf[dxn+1] = t1; + } + else if( cn == 3 ) + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + WT t2 = buf[dxn+2] + S[sxn+2]*alpha; + + buf[dxn] = t0; buf[dxn+1] = t1; buf[dxn+2] = t2; + } + else + for( k = 0; k < xofs_count; k++ ) + { + int sxn = xofs[k].si; + int dxn = xofs[k].di; + WT alpha = xofs[k].alpha; + + WT t0 = buf[dxn] + S[sxn]*alpha; + WT t1 = buf[dxn+1] + S[sxn+1]*alpha; + + buf[dxn] = t0; buf[dxn+1] = t1; + + t0 = buf[dxn+2] + S[sxn+2]*alpha; + t1 = buf[dxn+3] + S[sxn+3]*alpha; + + buf[dxn+2] = t0; buf[dxn+3] = t1; + } + + if( (cur_dy + 1)*scale_y <= sy + 1 || sy == ssize.height - 1 ) + { + WT beta = std::max(sy + 1 - (cur_dy + 1) * scale_y, (WT)0); + T* D = (T*)(dst.data + dst.step*cur_dy); + if( fabs(beta) < 1e-3 ) + { + if(cur_dy >= dsize.height) + return; + for( dx = 0; dx < dsize.width; dx++ ) + D[dx] = saturate_cast((sum[dx] + buf[dx]) / min(scale_y, src.rows - cur_dy * scale_y)); + memset(sum, 0, num); + } + else + { + WT beta1 = 1 - beta; + for( dx = 0; dx < dsize.width; dx++ ) + { + D[dx] = saturate_cast((sum[dx] + buf[dx] * beta1)/ min(scale_y, src.rows - cur_dy * scale_y)); + sum[dx] = buf[dx] * beta; + } + } + cur_dy++; + } + else + { + for( dx = 0; dx <= dsize.width - 2; dx += 2 ) + { + WT t0 = sum[dx] + buf[dx]; + WT t1 = sum[dx+1] + buf[dx+1]; + sum[dx] = t0; sum[dx+1] = t1; + } + for( ; dx < dsize.width; dx++ ) + sum[dx] += buf[dx]; + } + } + } + +private: + const Mat src; + Mat dst; + const DecimateAlpha* xofs; + const int xofs_count; + const double scale_y_; +#ifdef HAVE_TBB + const int *yofs, *cur_dy_ofs; +#endif +}; + template static void resizeArea_( const Mat& src, Mat& dst, const DecimateAlpha* xofs, int xofs_count, double scale_y_) { +#ifdef HAVE_TBB Size ssize = src.size(), dsize = dst.size(); - int cn = src.channels(); - dsize.width *= cn; - AutoBuffer _buffer(dsize.width*2); - WT *buf = _buffer, *sum = buf + dsize.width; - int k, sy, dx, cur_dy = 0; - WT scale_y = (WT)scale_y_; - - CV_Assert( cn <= 4 ); - for( dx = 0; dx < dsize.width; dx++ ) - buf[dx] = sum[dx] = 0; - + AutoBuffer _yofs(2 * ssize.height); + int *yofs = _yofs, *cur_dy_ofs = _yofs + ssize.height; + int index = 0, cur_dy = 0, sy; + for( sy = 0; sy < ssize.height; sy++ ) { - const T* S = (const T*)(src.data + src.step*sy); - if( cn == 1 ) - for( k = 0; k < xofs_count; k++ ) - { - int dxn = xofs[k].di; - WT alpha = xofs[k].alpha; - buf[dxn] += S[xofs[k].si]*alpha; - } - else if( cn == 2 ) - for( k = 0; k < xofs_count; k++ ) - { - int sxn = xofs[k].si; - int dxn = xofs[k].di; - WT alpha = xofs[k].alpha; - WT t0 = buf[dxn] + S[sxn]*alpha; - WT t1 = buf[dxn+1] + S[sxn+1]*alpha; - buf[dxn] = t0; buf[dxn+1] = t1; - } - else if( cn == 3 ) - for( k = 0; k < xofs_count; k++ ) - { - int sxn = xofs[k].si; - int dxn = xofs[k].di; - WT alpha = xofs[k].alpha; - WT t0 = buf[dxn] + S[sxn]*alpha; - WT t1 = buf[dxn+1] + S[sxn+1]*alpha; - WT t2 = buf[dxn+2] + S[sxn+2]*alpha; - buf[dxn] = t0; buf[dxn+1] = t1; buf[dxn+2] = t2; - } - else - for( k = 0; k < xofs_count; k++ ) - { - int sxn = xofs[k].si; - int dxn = xofs[k].di; - WT alpha = xofs[k].alpha; - WT t0 = buf[dxn] + S[sxn]*alpha; - WT t1 = buf[dxn+1] + S[sxn+1]*alpha; - buf[dxn] = t0; buf[dxn+1] = t1; - t0 = buf[dxn+2] + S[sxn+2]*alpha; - t1 = buf[dxn+3] + S[sxn+3]*alpha; - buf[dxn+2] = t0; buf[dxn+3] = t1; - } - - if( (cur_dy + 1)*scale_y <= sy + 1 || sy == ssize.height - 1 ) + bool reset = false; + cur_dy_ofs[sy] = cur_dy; + if( (cur_dy + 1)*scale_y_ <= sy + 1 || sy == ssize.height - 1 ) { - WT beta = std::max(sy + 1 - (cur_dy+1)*scale_y, (WT)0); - WT beta1 = 1 - beta; - T* D = (T*)(dst.data + dst.step*cur_dy); + WT beta = std::max(sy + 1 - (cur_dy+1)*scale_y_, 0.); if( fabs(beta) < 1e-3 ) { - if(cur_dy >= dsize.height) return; - for( dx = 0; dx < dsize.width; dx++ ) - { - D[dx] = saturate_cast((sum[dx] + buf[dx]) / min(scale_y, src.rows - cur_dy * scale_y)); - sum[dx] = buf[dx] = 0; - } + if(cur_dy >= dsize.height) + break; + reset = true; } - else - for( dx = 0; dx < dsize.width; dx++ ) - { - D[dx] = saturate_cast((sum[dx] + buf[dx]* beta1)/ min(scale_y, src.rows - cur_dy*scale_y)); - sum[dx] = buf[dx]*beta; - buf[dx] = 0; - } cur_dy++; } - else - { - for( dx = 0; dx <= dsize.width - 2; dx += 2 ) - { - WT t0 = sum[dx] + buf[dx]; - WT t1 = sum[dx+1] + buf[dx+1]; - sum[dx] = t0; sum[dx+1] = t1; - buf[dx] = buf[dx+1] = 0; - } - for( ; dx < dsize.width; dx++ ) - { - sum[dx] += buf[dx]; - buf[dx] = 0; - } - } + yofs[sy] = index; + if (reset) + index = sy + 1; } -} - - -static void resizeAreaFast_8u( const Mat& src, Mat& dst, - const int* ofs, const int* xofs, - int scale_x, int scale_y ) -{ -#if CV_SSE2 - bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2); #endif - Size ssize = src.size(), dsize = dst.size(); - int cn = src.channels(); - int dy, dx, k = 0; - int area = scale_x*scale_y; - float scale = 1.f/(scale_x*scale_y); - int dwidth1 = (ssize.width/scale_x)*cn; - dsize.width *= cn; - ssize.width *= cn; - //avg values - for( dy = 0; dy < dsize.height; dy++ ) - { - uchar* D = (uchar*)(dst.data + dst.step*dy); - int sy0 = dy*scale_y, w = sy0 + scale_y <= ssize.height ? dwidth1 : 0; - if( sy0 >= ssize.height ) - { - for( dx = 0; dx < dsize.width; dx++ ) //memset(D,0, dsize.width);//warning, never executed -> not tested - D[dx] = 0; - continue; - } - dx = 0; - - #if CV_SSE2 - if( haveSSE2 ) - { - const __m128 _scale = _mm_set1_ps(scale); - const __m128i _ucMAXs = _mm_set1_epi16(UCHAR_MAX); - const uchar* _S[8]; - - for(; dx < w-8; dx+=8 ) - { - __m128i _sum = _mm_setzero_si128(); - __m128i _sum1 = _mm_setzero_si128(); - _S[0] = (const uchar*)(src.data + src.step*sy0) + xofs[dx]; - _S[1] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+1]; - _S[2] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+2]; - _S[3] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+3]; - - _S[4] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+4]; - _S[5] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+5]; - _S[6] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+6]; - _S[7] = (const uchar*)(src.data + src.step*sy0) + xofs[dx+7]; - - for( k = 0; k < area; k++ ) - { - int ofsk = ofs[k]; - __m128i _temp = _mm_set_epi32(_S[3][ofsk],_S[2][ofsk],_S[1][ofsk],_S[0][ofsk]); - _sum = _mm_add_epi32(_sum, _temp); - - __m128i _temp1 = _mm_set_epi32(_S[7][ofsk],_S[6][ofsk],_S[5][ofsk],_S[4][ofsk]); - _sum1 = _mm_add_epi32(_sum1, _temp1); - } - - __m128i _tempSum = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(_sum), _scale)); - __m128i _tempSum1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(_sum1), _scale)); - - _tempSum = _mm_packs_epi32(_tempSum, _tempSum1); - _tempSum = _mm_min_epi16(_ucMAXs, _tempSum); - _tempSum = _mm_packus_epi16(_tempSum, _tempSum); - _mm_storel_epi64((__m128i*)(D+dx),_tempSum); - } - } - #endif - - for(; dx < w; dx++ ) - { - const uchar* S = (const uchar*)(src.data + src.step*sy0) + xofs[dx]; - int sum = 0; - k=0; - - #if CV_ENABLE_UNROLLED - for( ; k <= area - 4; k += 4 ) - sum += S[ofs[k]] + S[ofs[k+1]] + S[ofs[k+2]] + S[ofs[k+3]]; - #endif - - for( ; k < area; k++ ) - sum += S[ofs[k]]; - - - D[dx] = saturate_cast(sum*scale); - } - - for( ; dx < dsize.width; dx++ ) - { - int sum = 0; - int count = 0, sx0 = xofs[dx]; - if( sx0 >= ssize.width ) - D[dx] = 0; - - for( int sy = 0; sy < scale_y; sy++ ) - { - if( sy0 + sy >= ssize.height ) - break; - const uchar* S = (const uchar*)(src.data + src.step*(sy0 + sy)) + sx0; - int sx = 0; - for( ; sx < scale_x*cn; sx += cn ) - { - if( sx0 + sx >= ssize.width ) - break; - sum += S[sx]; - count++; - } - } - - D[dx] = saturate_cast((float)sum/count); - } - } + Range range(0, src.rows); + resizeArea_Invoker invoker(src, dst, xofs, xofs_count, scale_y_ +#ifdef HAVE_TBB + , yofs, cur_dy_ofs +#endif + ); + parallel_for_(range, invoker); } @@ -1457,10 +1652,12 @@ typedef void (*ResizeAreaFastFunc)( const Mat& src, Mat& dst, int scale_x, int scale_y ); typedef void (*ResizeAreaFunc)( const Mat& src, Mat& dst, - const DecimateAlpha* xofs, int xofs_count, double scale_y_); + const DecimateAlpha* xofs, int xofs_count, + double scale_y_); } + ////////////////////////////////////////////////////////////////////////////////////////// void cv::resize( InputArray _src, OutputArray _dst, Size dsize, @@ -1553,30 +1750,33 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize, static ResizeAreaFastFunc areafast_tab[] = { - resizeAreaFast_8u, 0, - resizeAreaFast_, - resizeAreaFast_, + resizeAreaFast_ >, 0, - resizeAreaFast_, - resizeAreaFast_, + resizeAreaFast_ >, + resizeAreaFast_ >, + 0, + resizeAreaFast_ >, + resizeAreaFast_ >, 0 }; static ResizeAreaFunc area_tab[] = { - resizeArea_, 0, resizeArea_, resizeArea_, - 0, resizeArea_, resizeArea_, 0 + resizeArea_, 0, resizeArea_, + resizeArea_, 0, resizeArea_, + resizeArea_, 0 }; Mat src = _src.getMat(); Size ssize = src.size(); CV_Assert( ssize.area() > 0 ); - CV_Assert( !(dsize == Size()) || (inv_scale_x > 0 && inv_scale_y > 0) ); - if( dsize == Size() ) + CV_Assert( dsize.area() || (inv_scale_x > 0 && inv_scale_y > 0) ); + if( !dsize.area() ) { dsize = Size(saturate_cast(src.cols*inv_scale_x), saturate_cast(src.rows*inv_scale_y)); + CV_Assert( dsize.area() ); } else { @@ -1601,79 +1801,92 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize, resizeNN( src, dst, inv_scale_x, inv_scale_y ); return; } - - // true "area" interpolation is only implemented for the case (scale_x <= 1 && scale_y <= 1). - // In other cases it is emulated using some variant of bilinear interpolation - if( interpolation == INTER_AREA && scale_x >= 1 && scale_y >= 1 ) + { int iscale_x = saturate_cast(scale_x); int iscale_y = saturate_cast(scale_y); + + bool is_area_fast = std::abs(scale_x - iscale_x) < DBL_EPSILON && + std::abs(scale_y - iscale_y) < DBL_EPSILON; + + // in case of scale_x && scale_y is equal to 2 + // INTER_AREA (fast) also is equal to INTER_LINEAR + if ( interpolation == INTER_LINEAR && + scale_x >= 1 && scale_y >= 1 && is_area_fast) + interpolation = INTER_AREA; - if( std::abs(scale_x - iscale_x) < DBL_EPSILON && - std::abs(scale_y - iscale_y) < DBL_EPSILON ) + // true "area" interpolation is only implemented for the case (scale_x <= 1 && scale_y <= 1). + // In other cases it is emulated using some variant of bilinear interpolation + if( interpolation == INTER_AREA && scale_x >= 1 && scale_y >= 1 ) { - int area = iscale_x*iscale_y; - size_t srcstep = src.step / src.elemSize1(); - AutoBuffer _ofs(area + dsize.width*cn); - int* ofs = _ofs; - int* xofs = ofs + area; - ResizeAreaFastFunc func = areafast_tab[depth]; - CV_Assert( func != 0 ); - - for( sy = 0, k = 0; sy < iscale_y; sy++ ) - for( sx = 0; sx < iscale_x; sx++ ) - ofs[k++] = (int)(sy*srcstep + sx*cn); - - for( dx = 0; dx < dsize.width; dx++ ) + if( is_area_fast ) { - sx = dx*iscale_x*cn; - for( k = 0; k < cn; k++ ) - xofs[dx*cn + k] = sx + k; + int area = iscale_x*iscale_y; + size_t srcstep = src.step / src.elemSize1(); + AutoBuffer _ofs(area + dsize.width*cn); + int* ofs = _ofs; + int* xofs = ofs + area; + ResizeAreaFastFunc func = areafast_tab[depth]; + CV_Assert( func != 0 ); + + for( sy = 0, k = 0; sy < iscale_y; sy++ ) + for( sx = 0; sx < iscale_x; sx++ ) + ofs[k++] = (int)(sy*srcstep + sx*cn); + + for( dx = 0; dx < dsize.width; dx++ ) + { + int j = dx * cn; + sx = iscale_x * j; + for( k = 0; k < cn; k++ ) + xofs[j + k] = sx + k; + } + + func( src, dst, ofs, xofs, iscale_x, iscale_y ); + return; } - func( src, dst, ofs, xofs, iscale_x, iscale_y ); + ResizeAreaFunc func = area_tab[depth]; + CV_Assert( func != 0 && cn <= 4 ); + + AutoBuffer _xofs(ssize.width*2); + DecimateAlpha* xofs = _xofs; + + for( dx = 0, k = 0; dx < dsize.width; dx++ ) + { + double fsx1 = dx*scale_x; + double fsx2 = fsx1 + scale_x; + int sx1 = cvCeil(fsx1), sx2 = cvFloor(fsx2); + sx1 = std::min(sx1, ssize.width-1); + sx2 = std::min(sx2, ssize.width-1); + + if( sx1 > fsx1 ) + { + assert( k < ssize.width*2 ); + xofs[k].di = dx*cn; + xofs[k].si = (sx1-1)*cn; + xofs[k++].alpha = (float)((sx1 - fsx1) / min(scale_x, src.cols - fsx1)); + } + + for( sx = sx1; sx < sx2; sx++ ) + { + assert( k < ssize.width*2 ); + xofs[k].di = dx*cn; + xofs[k].si = sx*cn; + xofs[k++].alpha = float(1.0 / min(scale_x, src.cols - fsx1)); + } + + if( fsx2 - sx2 > 1e-3 ) + { + assert( k < ssize.width*2 ); + xofs[k].di = dx*cn; + xofs[k].si = sx2*cn; + xofs[k++].alpha = (float)(min(fsx2 - sx2, 1.) / min(scale_x, src.cols - fsx1)); + } + } + + func( src, dst, xofs, k, scale_y); return; } - - ResizeAreaFunc func = area_tab[depth]; - CV_Assert( func != 0 && cn <= 4 ); - - AutoBuffer _xofs(ssize.width*2); - DecimateAlpha* xofs = _xofs; - - for( dx = 0, k = 0; dx < dsize.width; dx++ ) - { - double fsx1 = dx*scale_x, fsx2 = fsx1 + scale_x; - int sx1 = cvCeil(fsx1), sx2 = cvFloor(fsx2); - sx1 = std::min(sx1, ssize.width-1); - sx2 = std::min(sx2, ssize.width-1); - - if( sx1 > fsx1 ) - { - assert( k < ssize.width*2 ); - xofs[k].di = dx*cn; - xofs[k].si = (sx1-1)*cn; - xofs[k++].alpha = (float)((sx1 - fsx1) / min(scale_x, src.cols - fsx1)); - } - - for( sx = sx1; sx < sx2; sx++ ) - { - assert( k < ssize.width*2 ); - xofs[k].di = dx*cn; - xofs[k].si = sx*cn; - xofs[k++].alpha = float(1.0 / min(scale_x, src.cols - fsx1)); - } - - if( fsx2 - sx2 > 1e-3 ) - { - assert( k < ssize.width*2 ); - xofs[k].di = dx*cn; - xofs[k].si = sx2*cn; - xofs[k++].alpha = (float)(min(fsx2 - sx2, 1.) / min(scale_x, src.cols - fsx1)); - } - } - func( src, dst, xofs, k ,scale_y); - return; } int xmin = 0, xmax = dsize.width, width = dsize.width*cn; @@ -2549,6 +2762,206 @@ typedef void (*RemapFunc)(const Mat& _src, Mat& _dst, const Mat& _xy, const Mat& _fxy, const void* _wtab, int borderType, const Scalar& _borderValue); +class remapInvoker : + public ParallelLoopBody +{ +public: + remapInvoker(const Mat& _src, Mat _dst, const Mat& _map1, const Mat& _map2, const Mat *_m1, + const Mat *_m2, int _interpolation, int _borderType, const Scalar &_borderValue, + int _planar_input, RemapNNFunc _nnfunc, RemapFunc _ifunc, const void *_ctab) : + ParallelLoopBody(), src(_src), dst(_dst), map1(_map1), map2(_map2), m1(_m1), m2(_m2), + interpolation(_interpolation), borderType(_borderType), borderValue(_borderValue), + planar_input(_planar_input), nnfunc(_nnfunc), ifunc(_ifunc), ctab(_ctab) + { + } + + virtual void operator() (const Range& range) const + { + int x, y, x1, y1; + const int buf_size = 1 << 14; + int brows0 = std::min(128, dst.rows), map_depth = map1.depth(); + int bcols0 = std::min(buf_size/brows0, dst.cols); + brows0 = std::min(buf_size/bcols0, dst.rows); + #if CV_SSE2 + bool useSIMD = checkHardwareSupport(CV_CPU_SSE2); + #endif + + Mat _bufxy(brows0, bcols0, CV_16SC2), _bufa; + if( !nnfunc ) + _bufa.create(brows0, bcols0, CV_16UC1); + + for( y = range.start; y < range.end; y += brows0 ) + { + for( x = 0; x < dst.cols; x += bcols0 ) + { + int brows = std::min(brows0, range.end - y); + int bcols = std::min(bcols0, dst.cols - x); + Mat dpart(dst, Rect(x, y, bcols, brows)); + Mat bufxy(_bufxy, Rect(0, 0, bcols, brows)); + + if( nnfunc ) + { + if( map1.type() == CV_16SC2 && !map2.data ) // the data is already in the right format + bufxy = map1(Rect(x, y, bcols, brows)); + else if( map_depth != CV_32F ) + { + for( y1 = 0; y1 < brows; y1++ ) + { + short* XY = (short*)(bufxy.data + bufxy.step*y1); + const short* sXY = (const short*)(m1->data + m1->step*(y+y1)) + x*2; + const ushort* sA = (const ushort*)(m2->data + m2->step*(y+y1)) + x; + + for( x1 = 0; x1 < bcols; x1++ ) + { + int a = sA[x1] & (INTER_TAB_SIZE2-1); + XY[x1*2] = sXY[x1*2] + NNDeltaTab_i[a][0]; + XY[x1*2+1] = sXY[x1*2+1] + NNDeltaTab_i[a][1]; + } + } + } + else if( !planar_input ) + map1(Rect(x, y, bcols, brows)).convertTo(bufxy, bufxy.depth()); + else + { + for( y1 = 0; y1 < brows; y1++ ) + { + short* XY = (short*)(bufxy.data + bufxy.step*y1); + const float* sX = (const float*)(map1.data + map1.step*(y+y1)) + x; + const float* sY = (const float*)(map2.data + map2.step*(y+y1)) + x; + x1 = 0; + + #if CV_SSE2 + if( useSIMD ) + { + for( ; x1 <= bcols - 8; x1 += 8 ) + { + __m128 fx0 = _mm_loadu_ps(sX + x1); + __m128 fx1 = _mm_loadu_ps(sX + x1 + 4); + __m128 fy0 = _mm_loadu_ps(sY + x1); + __m128 fy1 = _mm_loadu_ps(sY + x1 + 4); + __m128i ix0 = _mm_cvtps_epi32(fx0); + __m128i ix1 = _mm_cvtps_epi32(fx1); + __m128i iy0 = _mm_cvtps_epi32(fy0); + __m128i iy1 = _mm_cvtps_epi32(fy1); + ix0 = _mm_packs_epi32(ix0, ix1); + iy0 = _mm_packs_epi32(iy0, iy1); + ix1 = _mm_unpacklo_epi16(ix0, iy0); + iy1 = _mm_unpackhi_epi16(ix0, iy0); + _mm_storeu_si128((__m128i*)(XY + x1*2), ix1); + _mm_storeu_si128((__m128i*)(XY + x1*2 + 8), iy1); + } + } + #endif + + for( ; x1 < bcols; x1++ ) + { + XY[x1*2] = saturate_cast(sX[x1]); + XY[x1*2+1] = saturate_cast(sY[x1]); + } + } + } + nnfunc( src, dpart, bufxy, borderType, borderValue ); + continue; + } + + Mat bufa(_bufa, Rect(0, 0, bcols, brows)); + for( y1 = 0; y1 < brows; y1++ ) + { + short* XY = (short*)(bufxy.data + bufxy.step*y1); + ushort* A = (ushort*)(bufa.data + bufa.step*y1); + + if( (map1.type() == CV_16SC2 && (map2.type() == CV_16UC1 || map2.type() == CV_16SC1)) || + (map2.type() == CV_16SC2 && (map1.type() == CV_16UC1 || map1.type() == CV_16SC1)) ) + { + bufxy = m1->operator()(Rect(x, y, bcols, brows)); + bufa = m2->operator()(Rect(x, y, bcols, brows)); + } + else if( planar_input ) + { + const float* sX = (const float*)(map1.data + map1.step*(y+y1)) + x; + const float* sY = (const float*)(map2.data + map2.step*(y+y1)) + x; + + x1 = 0; + #if CV_SSE2 + if( useSIMD ) + { + __m128 scale = _mm_set1_ps((float)INTER_TAB_SIZE); + __m128i mask = _mm_set1_epi32(INTER_TAB_SIZE-1); + for( ; x1 <= bcols - 8; x1 += 8 ) + { + __m128 fx0 = _mm_loadu_ps(sX + x1); + __m128 fx1 = _mm_loadu_ps(sX + x1 + 4); + __m128 fy0 = _mm_loadu_ps(sY + x1); + __m128 fy1 = _mm_loadu_ps(sY + x1 + 4); + __m128i ix0 = _mm_cvtps_epi32(_mm_mul_ps(fx0, scale)); + __m128i ix1 = _mm_cvtps_epi32(_mm_mul_ps(fx1, scale)); + __m128i iy0 = _mm_cvtps_epi32(_mm_mul_ps(fy0, scale)); + __m128i iy1 = _mm_cvtps_epi32(_mm_mul_ps(fy1, scale)); + __m128i mx0 = _mm_and_si128(ix0, mask); + __m128i mx1 = _mm_and_si128(ix1, mask); + __m128i my0 = _mm_and_si128(iy0, mask); + __m128i my1 = _mm_and_si128(iy1, mask); + mx0 = _mm_packs_epi32(mx0, mx1); + my0 = _mm_packs_epi32(my0, my1); + my0 = _mm_slli_epi16(my0, INTER_BITS); + mx0 = _mm_or_si128(mx0, my0); + _mm_storeu_si128((__m128i*)(A + x1), mx0); + ix0 = _mm_srai_epi32(ix0, INTER_BITS); + ix1 = _mm_srai_epi32(ix1, INTER_BITS); + iy0 = _mm_srai_epi32(iy0, INTER_BITS); + iy1 = _mm_srai_epi32(iy1, INTER_BITS); + ix0 = _mm_packs_epi32(ix0, ix1); + iy0 = _mm_packs_epi32(iy0, iy1); + ix1 = _mm_unpacklo_epi16(ix0, iy0); + iy1 = _mm_unpackhi_epi16(ix0, iy0); + _mm_storeu_si128((__m128i*)(XY + x1*2), ix1); + _mm_storeu_si128((__m128i*)(XY + x1*2 + 8), iy1); + } + } + #endif + + for( ; x1 < bcols; x1++ ) + { + int sx = cvRound(sX[x1]*INTER_TAB_SIZE); + int sy = cvRound(sY[x1]*INTER_TAB_SIZE); + int v = (sy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (sx & (INTER_TAB_SIZE-1)); + XY[x1*2] = (short)(sx >> INTER_BITS); + XY[x1*2+1] = (short)(sy >> INTER_BITS); + A[x1] = (ushort)v; + } + } + else + { + const float* sXY = (const float*)(map1.data + map1.step*(y+y1)) + x*2; + + for( x1 = 0; x1 < bcols; x1++ ) + { + int sx = cvRound(sXY[x1*2]*INTER_TAB_SIZE); + int sy = cvRound(sXY[x1*2+1]*INTER_TAB_SIZE); + int v = (sy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (sx & (INTER_TAB_SIZE-1)); + XY[x1*2] = (short)(sx >> INTER_BITS); + XY[x1*2+1] = (short)(sy >> INTER_BITS); + A[x1] = (ushort)v; + } + } + } + ifunc(src, dpart, bufxy, bufa, ctab, borderType, borderValue); + } + } + } + +private: + const Mat src; + Mat dst; + const Mat map1, map2, *m1, *m2; + int interpolation, borderType; + const Scalar borderValue; + int planar_input; + RemapNNFunc nnfunc; + RemapFunc ifunc; + const void *ctab; +}; + } void cv::remap( InputArray _src, OutputArray _dst, @@ -2590,14 +3003,15 @@ void cv::remap( InputArray _src, OutputArray _dst, Mat src = _src.getMat(), map1 = _map1.getMat(), map2 = _map2.getMat(); - CV_Assert( (!map2.data || map2.size() == map1.size())); + CV_Assert( map1.size().area() > 0 ); + CV_Assert( !map2.data || (map2.size() == map1.size())); _dst.create( map1.size(), src.type() ); Mat dst = _dst.getMat(); if( dst.data == src.data ) src = src.clone(); - int depth = src.depth(), map_depth = map1.depth(); + int depth = src.depth(); RemapNNFunc nnfunc = 0; RemapFunc ifunc = 0; const void* ctab = 0; @@ -2608,12 +3022,6 @@ void cv::remap( InputArray _src, OutputArray _dst, { nnfunc = nn_tab[depth]; CV_Assert( nnfunc != 0 ); - - if( map1.type() == CV_16SC2 && !map2.data ) // the data is already in the right format - { - nnfunc( src, dst, map1, borderType, borderValue ); - return; - } } else { @@ -2639,182 +3047,19 @@ void cv::remap( InputArray _src, OutputArray _dst, { if( map1.type() != CV_16SC2 ) std::swap(m1, m2); - if( ifunc ) - { - ifunc( src, dst, *m1, *m2, ctab, borderType, borderValue ); - return; - } } else { - CV_Assert( (map1.type() == CV_32FC2 && !map2.data) || + CV_Assert( ((map1.type() == CV_32FC2 || map1.type() == CV_16SC2) && !map2.data) || (map1.type() == CV_32FC1 && map2.type() == CV_32FC1) ); planar_input = map1.channels() == 1; } - int x, y, x1, y1; - const int buf_size = 1 << 14; - int brows0 = std::min(128, dst.rows); - int bcols0 = std::min(buf_size/brows0, dst.cols); - brows0 = std::min(buf_size/bcols0, dst.rows); -#if CV_SSE2 - bool useSIMD = checkHardwareSupport(CV_CPU_SSE2); -#endif - - Mat _bufxy(brows0, bcols0, CV_16SC2), _bufa; - if( !nnfunc ) - _bufa.create(brows0, bcols0, CV_16UC1); - - for( y = 0; y < dst.rows; y += brows0 ) - { - for( x = 0; x < dst.cols; x += bcols0 ) - { - int brows = std::min(brows0, dst.rows - y); - int bcols = std::min(bcols0, dst.cols - x); - Mat dpart(dst, Rect(x, y, bcols, brows)); - Mat bufxy(_bufxy, Rect(0, 0, bcols, brows)); - - if( nnfunc ) - { - if( map_depth != CV_32F ) - { - for( y1 = 0; y1 < brows; y1++ ) - { - short* XY = (short*)(bufxy.data + bufxy.step*y1); - const short* sXY = (const short*)(m1->data + m1->step*(y+y1)) + x*2; - const ushort* sA = (const ushort*)(m2->data + m2->step*(y+y1)) + x; - - for( x1 = 0; x1 < bcols; x1++ ) - { - int a = sA[x1] & (INTER_TAB_SIZE2-1); - XY[x1*2] = sXY[x1*2] + NNDeltaTab_i[a][0]; - XY[x1*2+1] = sXY[x1*2+1] + NNDeltaTab_i[a][1]; - } - } - } - else if( !planar_input ) - map1(Rect(0,0,bcols,brows)).convertTo(bufxy, bufxy.depth()); - else - { - for( y1 = 0; y1 < brows; y1++ ) - { - short* XY = (short*)(bufxy.data + bufxy.step*y1); - const float* sX = (const float*)(map1.data + map1.step*(y+y1)) + x; - const float* sY = (const float*)(map2.data + map2.step*(y+y1)) + x; - x1 = 0; - - #if CV_SSE2 - if( useSIMD ) - { - for( ; x1 <= bcols - 8; x1 += 8 ) - { - __m128 fx0 = _mm_loadu_ps(sX + x1); - __m128 fx1 = _mm_loadu_ps(sX + x1 + 4); - __m128 fy0 = _mm_loadu_ps(sY + x1); - __m128 fy1 = _mm_loadu_ps(sY + x1 + 4); - __m128i ix0 = _mm_cvtps_epi32(fx0); - __m128i ix1 = _mm_cvtps_epi32(fx1); - __m128i iy0 = _mm_cvtps_epi32(fy0); - __m128i iy1 = _mm_cvtps_epi32(fy1); - ix0 = _mm_packs_epi32(ix0, ix1); - iy0 = _mm_packs_epi32(iy0, iy1); - ix1 = _mm_unpacklo_epi16(ix0, iy0); - iy1 = _mm_unpackhi_epi16(ix0, iy0); - _mm_storeu_si128((__m128i*)(XY + x1*2), ix1); - _mm_storeu_si128((__m128i*)(XY + x1*2 + 8), iy1); - } - } - #endif - - for( ; x1 < bcols; x1++ ) - { - XY[x1*2] = saturate_cast(sX[x1]); - XY[x1*2+1] = saturate_cast(sY[x1]); - } - } - } - nnfunc( src, dpart, bufxy, borderType, borderValue ); - continue; - } - - Mat bufa(_bufa, Rect(0,0,bcols, brows)); - for( y1 = 0; y1 < brows; y1++ ) - { - short* XY = (short*)(bufxy.data + bufxy.step*y1); - ushort* A = (ushort*)(bufa.data + bufa.step*y1); - - if( planar_input ) - { - const float* sX = (const float*)(map1.data + map1.step*(y+y1)) + x; - const float* sY = (const float*)(map2.data + map2.step*(y+y1)) + x; - - x1 = 0; - #if CV_SSE2 - if( useSIMD ) - { - __m128 scale = _mm_set1_ps((float)INTER_TAB_SIZE); - __m128i mask = _mm_set1_epi32(INTER_TAB_SIZE-1); - for( ; x1 <= bcols - 8; x1 += 8 ) - { - __m128 fx0 = _mm_loadu_ps(sX + x1); - __m128 fx1 = _mm_loadu_ps(sX + x1 + 4); - __m128 fy0 = _mm_loadu_ps(sY + x1); - __m128 fy1 = _mm_loadu_ps(sY + x1 + 4); - __m128i ix0 = _mm_cvtps_epi32(_mm_mul_ps(fx0, scale)); - __m128i ix1 = _mm_cvtps_epi32(_mm_mul_ps(fx1, scale)); - __m128i iy0 = _mm_cvtps_epi32(_mm_mul_ps(fy0, scale)); - __m128i iy1 = _mm_cvtps_epi32(_mm_mul_ps(fy1, scale)); - __m128i mx0 = _mm_and_si128(ix0, mask); - __m128i mx1 = _mm_and_si128(ix1, mask); - __m128i my0 = _mm_and_si128(iy0, mask); - __m128i my1 = _mm_and_si128(iy1, mask); - mx0 = _mm_packs_epi32(mx0, mx1); - my0 = _mm_packs_epi32(my0, my1); - my0 = _mm_slli_epi16(my0, INTER_BITS); - mx0 = _mm_or_si128(mx0, my0); - _mm_storeu_si128((__m128i*)(A + x1), mx0); - ix0 = _mm_srai_epi32(ix0, INTER_BITS); - ix1 = _mm_srai_epi32(ix1, INTER_BITS); - iy0 = _mm_srai_epi32(iy0, INTER_BITS); - iy1 = _mm_srai_epi32(iy1, INTER_BITS); - ix0 = _mm_packs_epi32(ix0, ix1); - iy0 = _mm_packs_epi32(iy0, iy1); - ix1 = _mm_unpacklo_epi16(ix0, iy0); - iy1 = _mm_unpackhi_epi16(ix0, iy0); - _mm_storeu_si128((__m128i*)(XY + x1*2), ix1); - _mm_storeu_si128((__m128i*)(XY + x1*2 + 8), iy1); - } - } - #endif - - for( ; x1 < bcols; x1++ ) - { - int sx = cvRound(sX[x1]*INTER_TAB_SIZE); - int sy = cvRound(sY[x1]*INTER_TAB_SIZE); - int v = (sy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (sx & (INTER_TAB_SIZE-1)); - XY[x1*2] = (short)(sx >> INTER_BITS); - XY[x1*2+1] = (short)(sy >> INTER_BITS); - A[x1] = (ushort)v; - } - } - else - { - const float* sXY = (const float*)(map1.data + map1.step*(y+y1)) + x*2; - - for( x1 = 0; x1 < bcols; x1++ ) - { - int sx = cvRound(sXY[x1*2]*INTER_TAB_SIZE); - int sy = cvRound(sXY[x1*2+1]*INTER_TAB_SIZE); - int v = (sy & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (sx & (INTER_TAB_SIZE-1)); - XY[x1*2] = (short)(sx >> INTER_BITS); - XY[x1*2+1] = (short)(sy >> INTER_BITS); - A[x1] = (ushort)v; - } - } - } - ifunc(src, dpart, bufxy, bufa, ctab, borderType, borderValue); - } - } + Range range(0, dst.rows); + remapInvoker invoker(src, dst, map1, map2, m1, m2, interpolation, + borderType, borderValue, planar_input, nnfunc, ifunc, + ctab); + parallel_for_(range, invoker); } @@ -2956,7 +3201,134 @@ void cv::convertMaps( InputArray _map1, InputArray _map2, } } + +namespace cv +{ +class warpAffineInvoker : + public ParallelLoopBody +{ +public: + warpAffineInvoker(const Mat &_src, Mat &_dst, int _interpolation, int _borderType, + const Scalar &_borderValue, int *_adelta, int *_bdelta, double *_M) : + ParallelLoopBody(), src(_src), dst(_dst), interpolation(_interpolation), + borderType(_borderType), borderValue(_borderValue), adelta(_adelta), bdelta(_bdelta), + M(_M) + { + } + + virtual void operator() (const Range& range) const + { + const int BLOCK_SZ = 64; + short XY[BLOCK_SZ*BLOCK_SZ*2], A[BLOCK_SZ*BLOCK_SZ]; + const int AB_BITS = MAX(10, (int)INTER_BITS); + const int AB_SCALE = 1 << AB_BITS; + int round_delta = interpolation == INTER_NEAREST ? AB_SCALE/2 : AB_SCALE/INTER_TAB_SIZE/2, x, y, x1, y1; + #if CV_SSE2 + bool useSIMD = checkHardwareSupport(CV_CPU_SSE2); + #endif + + int bh0 = std::min(BLOCK_SZ/2, dst.rows); + int bw0 = std::min(BLOCK_SZ*BLOCK_SZ/bh0, dst.cols); + bh0 = std::min(BLOCK_SZ*BLOCK_SZ/bw0, dst.rows); + + for( y = range.start; y < range.end; y += bh0 ) + { + for( x = 0; x < dst.cols; x += bw0 ) + { + int bw = std::min( bw0, dst.cols - x); + int bh = std::min( bh0, range.end - y); + + Mat _XY(bh, bw, CV_16SC2, XY), matA; + Mat dpart(dst, Rect(x, y, bw, bh)); + + for( y1 = 0; y1 < bh; y1++ ) + { + short* xy = XY + y1*bw*2; + int X0 = saturate_cast((M[1]*(y + y1) + M[2])*AB_SCALE) + round_delta; + int Y0 = saturate_cast((M[4]*(y + y1) + M[5])*AB_SCALE) + round_delta; + + if( interpolation == INTER_NEAREST ) + for( x1 = 0; x1 < bw; x1++ ) + { + int X = (X0 + adelta[x+x1]) >> AB_BITS; + int Y = (Y0 + bdelta[x+x1]) >> AB_BITS; + xy[x1*2] = saturate_cast(X); + xy[x1*2+1] = saturate_cast(Y); + } + else + { + short* alpha = A + y1*bw; + x1 = 0; + #if CV_SSE2 + if( useSIMD ) + { + __m128i fxy_mask = _mm_set1_epi32(INTER_TAB_SIZE - 1); + __m128i XX = _mm_set1_epi32(X0), YY = _mm_set1_epi32(Y0); + for( ; x1 <= bw - 8; x1 += 8 ) + { + __m128i tx0, tx1, ty0, ty1; + tx0 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(adelta + x + x1)), XX); + ty0 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(bdelta + x + x1)), YY); + tx1 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(adelta + x + x1 + 4)), XX); + ty1 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(bdelta + x + x1 + 4)), YY); + + tx0 = _mm_srai_epi32(tx0, AB_BITS - INTER_BITS); + ty0 = _mm_srai_epi32(ty0, AB_BITS - INTER_BITS); + tx1 = _mm_srai_epi32(tx1, AB_BITS - INTER_BITS); + ty1 = _mm_srai_epi32(ty1, AB_BITS - INTER_BITS); + + __m128i fx_ = _mm_packs_epi32(_mm_and_si128(tx0, fxy_mask), + _mm_and_si128(tx1, fxy_mask)); + __m128i fy_ = _mm_packs_epi32(_mm_and_si128(ty0, fxy_mask), + _mm_and_si128(ty1, fxy_mask)); + tx0 = _mm_packs_epi32(_mm_srai_epi32(tx0, INTER_BITS), + _mm_srai_epi32(tx1, INTER_BITS)); + ty0 = _mm_packs_epi32(_mm_srai_epi32(ty0, INTER_BITS), + _mm_srai_epi32(ty1, INTER_BITS)); + fx_ = _mm_adds_epi16(fx_, _mm_slli_epi16(fy_, INTER_BITS)); + + _mm_storeu_si128((__m128i*)(xy + x1*2), _mm_unpacklo_epi16(tx0, ty0)); + _mm_storeu_si128((__m128i*)(xy + x1*2 + 8), _mm_unpackhi_epi16(tx0, ty0)); + _mm_storeu_si128((__m128i*)(alpha + x1), fx_); + } + } + #endif + for( ; x1 < bw; x1++ ) + { + int X = (X0 + adelta[x+x1]) >> (AB_BITS - INTER_BITS); + int Y = (Y0 + bdelta[x+x1]) >> (AB_BITS - INTER_BITS); + xy[x1*2] = saturate_cast(X >> INTER_BITS); + xy[x1*2+1] = saturate_cast(Y >> INTER_BITS); + alpha[x1] = (short)((Y & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + + (X & (INTER_TAB_SIZE-1))); + } + } + } + + if( interpolation == INTER_NEAREST ) + remap( src, dpart, _XY, Mat(), interpolation, borderType, borderValue ); + else + { + Mat _matA(bh, bw, CV_16U, A); + remap( src, dpart, _XY, _matA, interpolation, borderType, borderValue ); + } + } + } + } + +private: + const Mat src; + Mat dst; + int interpolation, borderType; + const Scalar borderValue; + int *adelta, *bdelta; + double *M; +}; + +} + + void cv::warpAffine( InputArray _src, OutputArray _dst, InputArray _M0, Size dsize, int flags, int borderType, const Scalar& borderValue ) @@ -2968,8 +3340,6 @@ void cv::warpAffine( InputArray _src, OutputArray _dst, if( dst.data == src.data ) src = src.clone(); - const int BLOCK_SZ = 64; - short XY[BLOCK_SZ*BLOCK_SZ*2], A[BLOCK_SZ*BLOCK_SZ]; double M[6]; Mat matM(2, 3, CV_64F, M); int interpolation = flags & INTER_MAX; @@ -2996,112 +3366,121 @@ void cv::warpAffine( InputArray _src, OutputArray _dst, M[2] = b1; M[5] = b2; } - int x, y, x1, y1, width = dst.cols, height = dst.rows; - AutoBuffer _abdelta(width*2); - int* adelta = &_abdelta[0], *bdelta = adelta + width; + int x; + AutoBuffer _abdelta(dst.cols*2); + int* adelta = &_abdelta[0], *bdelta = adelta + dst.cols; const int AB_BITS = MAX(10, (int)INTER_BITS); const int AB_SCALE = 1 << AB_BITS; - int round_delta = interpolation == INTER_NEAREST ? AB_SCALE/2 : AB_SCALE/INTER_TAB_SIZE/2; -#if CV_SSE2 - bool useSIMD = checkHardwareSupport(CV_CPU_SSE2); -#endif - for( x = 0; x < width; x++ ) + for( x = 0; x < dst.cols; x++ ) { adelta[x] = saturate_cast(M[0]*x*AB_SCALE); bdelta[x] = saturate_cast(M[3]*x*AB_SCALE); } - int bh0 = std::min(BLOCK_SZ/2, height); - int bw0 = std::min(BLOCK_SZ*BLOCK_SZ/bh0, width); - bh0 = std::min(BLOCK_SZ*BLOCK_SZ/bw0, height); + Range range(0, dst.rows); + warpAffineInvoker invoker(src, dst, interpolation, borderType, + borderValue, adelta, bdelta, M); + parallel_for_(range, invoker); +} - for( y = 0; y < height; y += bh0 ) + +namespace cv +{ + +class warpPerspectiveInvoker : + public ParallelLoopBody +{ +public: + + warpPerspectiveInvoker(const Mat &_src, Mat &_dst, double *_M, int _interpolation, + int _borderType, const Scalar &_borderValue) : + ParallelLoopBody(), src(_src), dst(_dst), M(_M), interpolation(_interpolation), + borderType(_borderType), borderValue(_borderValue) { - for( x = 0; x < width; x += bw0 ) + } + + virtual void operator() (const Range& range) const + { + const int BLOCK_SZ = 32; + short XY[BLOCK_SZ*BLOCK_SZ*2], A[BLOCK_SZ*BLOCK_SZ]; + int x, y, x1, y1, width = dst.cols, height = dst.rows; + + int bh0 = std::min(BLOCK_SZ/2, height); + int bw0 = std::min(BLOCK_SZ*BLOCK_SZ/bh0, width); + bh0 = std::min(BLOCK_SZ*BLOCK_SZ/bw0, height); + + for( y = range.start; y < range.end; y += bh0 ) { - int bw = std::min( bw0, width - x); - int bh = std::min( bh0, height - y); - - Mat _XY(bh, bw, CV_16SC2, XY), matA; - Mat dpart(dst, Rect(x, y, bw, bh)); - - for( y1 = 0; y1 < bh; y1++ ) + for( x = 0; x < width; x += bw0 ) { - short* xy = XY + y1*bw*2; - int X0 = saturate_cast((M[1]*(y + y1) + M[2])*AB_SCALE) + round_delta; - int Y0 = saturate_cast((M[4]*(y + y1) + M[5])*AB_SCALE) + round_delta; - - if( interpolation == INTER_NEAREST ) - for( x1 = 0; x1 < bw; x1++ ) - { - int X = (X0 + adelta[x+x1]) >> AB_BITS; - int Y = (Y0 + bdelta[x+x1]) >> AB_BITS; - xy[x1*2] = saturate_cast(X); - xy[x1*2+1] = saturate_cast(Y); - } - else + int bw = std::min( bw0, width - x); + int bh = std::min( bh0, range.end - y); // height + + Mat _XY(bh, bw, CV_16SC2, XY), matA; + Mat dpart(dst, Rect(x, y, bw, bh)); + + for( y1 = 0; y1 < bh; y1++ ) { - short* alpha = A + y1*bw; - x1 = 0; - #if CV_SSE2 - if( useSIMD ) - { - __m128i fxy_mask = _mm_set1_epi32(INTER_TAB_SIZE - 1); - __m128i XX = _mm_set1_epi32(X0), YY = _mm_set1_epi32(Y0); - for( ; x1 <= bw - 8; x1 += 8 ) + short* xy = XY + y1*bw*2; + double X0 = M[0]*x + M[1]*(y + y1) + M[2]; + double Y0 = M[3]*x + M[4]*(y + y1) + M[5]; + double W0 = M[6]*x + M[7]*(y + y1) + M[8]; + + if( interpolation == INTER_NEAREST ) + for( x1 = 0; x1 < bw; x1++ ) { - __m128i tx0, tx1, ty0, ty1; - tx0 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(adelta + x + x1)), XX); - ty0 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(bdelta + x + x1)), YY); - tx1 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(adelta + x + x1 + 4)), XX); - ty1 = _mm_add_epi32(_mm_loadu_si128((const __m128i*)(bdelta + x + x1 + 4)), YY); - - tx0 = _mm_srai_epi32(tx0, AB_BITS - INTER_BITS); - ty0 = _mm_srai_epi32(ty0, AB_BITS - INTER_BITS); - tx1 = _mm_srai_epi32(tx1, AB_BITS - INTER_BITS); - ty1 = _mm_srai_epi32(ty1, AB_BITS - INTER_BITS); - - __m128i fx_ = _mm_packs_epi32(_mm_and_si128(tx0, fxy_mask), - _mm_and_si128(tx1, fxy_mask)); - __m128i fy_ = _mm_packs_epi32(_mm_and_si128(ty0, fxy_mask), - _mm_and_si128(ty1, fxy_mask)); - tx0 = _mm_packs_epi32(_mm_srai_epi32(tx0, INTER_BITS), - _mm_srai_epi32(tx1, INTER_BITS)); - ty0 = _mm_packs_epi32(_mm_srai_epi32(ty0, INTER_BITS), - _mm_srai_epi32(ty1, INTER_BITS)); - fx_ = _mm_adds_epi16(fx_, _mm_slli_epi16(fy_, INTER_BITS)); - - _mm_storeu_si128((__m128i*)(xy + x1*2), _mm_unpacklo_epi16(tx0, ty0)); - _mm_storeu_si128((__m128i*)(xy + x1*2 + 8), _mm_unpackhi_epi16(tx0, ty0)); - _mm_storeu_si128((__m128i*)(alpha + x1), fx_); + double W = W0 + M[6]*x1; + W = W ? 1./W : 0; + double fX = std::max((double)INT_MIN, std::min((double)INT_MAX, (X0 + M[0]*x1)*W)); + double fY = std::max((double)INT_MIN, std::min((double)INT_MAX, (Y0 + M[3]*x1)*W)); + int X = saturate_cast(fX); + int Y = saturate_cast(fY); + + xy[x1*2] = saturate_cast(X); + xy[x1*2+1] = saturate_cast(Y); + } + else + { + short* alpha = A + y1*bw; + for( x1 = 0; x1 < bw; x1++ ) + { + double W = W0 + M[6]*x1; + W = W ? INTER_TAB_SIZE/W : 0; + double fX = std::max((double)INT_MIN, std::min((double)INT_MAX, (X0 + M[0]*x1)*W)); + double fY = std::max((double)INT_MIN, std::min((double)INT_MAX, (Y0 + M[3]*x1)*W)); + int X = saturate_cast(fX); + int Y = saturate_cast(fY); + + xy[x1*2] = saturate_cast(X >> INTER_BITS); + xy[x1*2+1] = saturate_cast(Y >> INTER_BITS); + alpha[x1] = (short)((Y & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + + (X & (INTER_TAB_SIZE-1))); } } - #endif - for( ; x1 < bw; x1++ ) - { - int X = (X0 + adelta[x+x1]) >> (AB_BITS - INTER_BITS); - int Y = (Y0 + bdelta[x+x1]) >> (AB_BITS - INTER_BITS); - xy[x1*2] = saturate_cast(X >> INTER_BITS); - xy[x1*2+1] = saturate_cast(Y >> INTER_BITS); - alpha[x1] = (short)((Y & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + - (X & (INTER_TAB_SIZE-1))); - } } - } - - if( interpolation == INTER_NEAREST ) - remap( src, dpart, _XY, Mat(), interpolation, borderType, borderValue ); - else - { - Mat _matA(bh, bw, CV_16U, A); - remap( src, dpart, _XY, _matA, interpolation, borderType, borderValue ); + + if( interpolation == INTER_NEAREST ) + remap( src, dpart, _XY, Mat(), interpolation, borderType, borderValue ); + else + { + Mat _matA(bh, bw, CV_16U, A); + remap( src, dpart, _XY, _matA, interpolation, borderType, borderValue ); + } } } } + +private: + const Mat src; + Mat dst; + double* M; + int interpolation, borderType; + const Scalar borderValue; +}; + } - void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0, Size dsize, int flags, int borderType, const Scalar& borderValue ) { @@ -3113,8 +3492,6 @@ void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0, if( dst.data == src.data ) src = src.clone(); - const int BLOCK_SZ = 32; - short XY[BLOCK_SZ*BLOCK_SZ*2], A[BLOCK_SZ*BLOCK_SZ]; double M[9]; Mat matM(3, 3, CV_64F, M); int interpolation = flags & INTER_MAX; @@ -3132,71 +3509,9 @@ void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0, if( !(flags & WARP_INVERSE_MAP) ) invert(matM, matM); - int x, y, x1, y1, width = dst.cols, height = dst.rows; - - int bh0 = std::min(BLOCK_SZ/2, height); - int bw0 = std::min(BLOCK_SZ*BLOCK_SZ/bh0, width); - bh0 = std::min(BLOCK_SZ*BLOCK_SZ/bw0, height); - - for( y = 0; y < height; y += bh0 ) - { - for( x = 0; x < width; x += bw0 ) - { - int bw = std::min( bw0, width - x); - int bh = std::min( bh0, height - y); - - Mat _XY(bh, bw, CV_16SC2, XY), matA; - Mat dpart(dst, Rect(x, y, bw, bh)); - - for( y1 = 0; y1 < bh; y1++ ) - { - short* xy = XY + y1*bw*2; - double X0 = M[0]*x + M[1]*(y + y1) + M[2]; - double Y0 = M[3]*x + M[4]*(y + y1) + M[5]; - double W0 = M[6]*x + M[7]*(y + y1) + M[8]; - - if( interpolation == INTER_NEAREST ) - for( x1 = 0; x1 < bw; x1++ ) - { - double W = W0 + M[6]*x1; - W = W ? 1./W : 0; - double fX = std::max((double)INT_MIN, std::min((double)INT_MAX, (X0 + M[0]*x1)*W)); - double fY = std::max((double)INT_MIN, std::min((double)INT_MAX, (Y0 + M[3]*x1)*W)); - int X = saturate_cast(fX); - int Y = saturate_cast(fY); - - xy[x1*2] = saturate_cast(X); - xy[x1*2+1] = saturate_cast(Y); - } - else - { - short* alpha = A + y1*bw; - for( x1 = 0; x1 < bw; x1++ ) - { - double W = W0 + M[6]*x1; - W = W ? INTER_TAB_SIZE/W : 0; - double fX = std::max((double)INT_MIN, std::min((double)INT_MAX, (X0 + M[0]*x1)*W)); - double fY = std::max((double)INT_MIN, std::min((double)INT_MAX, (Y0 + M[3]*x1)*W)); - int X = saturate_cast(fX); - int Y = saturate_cast(fY); - - xy[x1*2] = saturate_cast(X >> INTER_BITS); - xy[x1*2+1] = saturate_cast(Y >> INTER_BITS); - alpha[x1] = (short)((Y & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + - (X & (INTER_TAB_SIZE-1))); - } - } - } - - if( interpolation == INTER_NEAREST ) - remap( src, dpart, _XY, Mat(), interpolation, borderType, borderValue ); - else - { - Mat _matA(bh, bw, CV_16U, A); - remap( src, dpart, _XY, _matA, interpolation, borderType, borderValue ); - } - } - } + Range range(0, dst.rows); + warpPerspectiveInvoker invoker(src, dst, M, interpolation, borderType, borderValue); + parallel_for_(range, invoker); } From da5aaab27788d32a9f4118b4a90667000c8282aa Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Wed, 22 Aug 2012 12:11:11 +0400 Subject: [PATCH 052/163] optimized gpu::integral for Kepler --- modules/core/include/opencv2/core/gpumat.hpp | 4 +- modules/gpu/src/cuda/integral_image.cu | 385 +++++++++++++++++++ modules/gpu/src/imgproc.cpp | 96 ++++- 3 files changed, 463 insertions(+), 22 deletions(-) create mode 100644 modules/gpu/src/cuda/integral_image.cu diff --git a/modules/core/include/opencv2/core/gpumat.hpp b/modules/core/include/opencv2/core/gpumat.hpp index 9893359253..e09f1bc4c3 100644 --- a/modules/core/include/opencv2/core/gpumat.hpp +++ b/modules/core/include/opencv2/core/gpumat.hpp @@ -72,9 +72,11 @@ namespace cv { namespace gpu FEATURE_SET_COMPUTE_13 = 13, FEATURE_SET_COMPUTE_20 = 20, FEATURE_SET_COMPUTE_21 = 21, + FEATURE_SET_COMPUTE_30 = 30, GLOBAL_ATOMICS = FEATURE_SET_COMPUTE_11, SHARED_ATOMICS = FEATURE_SET_COMPUTE_12, - NATIVE_DOUBLE = FEATURE_SET_COMPUTE_13 + NATIVE_DOUBLE = FEATURE_SET_COMPUTE_13, + WARP_SHUFFLE_FUNCTIONS = FEATURE_SET_COMPUTE_30 }; // Gives information about what GPU archs this OpenCV GPU module was diff --git a/modules/gpu/src/cuda/integral_image.cu b/modules/gpu/src/cuda/integral_image.cu new file mode 100644 index 0000000000..ead0ddefec --- /dev/null +++ b/modules/gpu/src/cuda/integral_image.cu @@ -0,0 +1,385 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or bpied warranties, including, but not limited to, the bpied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "opencv2/gpu/device/common.hpp" + +namespace cv { namespace gpu { namespace device +{ + namespace imgproc + { + // Utility function to extract unsigned chars from an unsigned integer + __device__ uchar4 int_to_uchar4(unsigned int in) + { + uchar4 bytes; + bytes.x = (in && 0x000000ff) >> 0; + bytes.y = (in && 0x0000ff00) >> 8; + bytes.z = (in && 0x00ff0000) >> 16; + bytes.w = (in && 0xff000000) >> 24; + return bytes; + } + + __global__ void shfl_integral_horizontal(const PtrStep_ img, PtrStep_ integral) + { + #if __CUDA_ARCH__ >= 300 + __shared__ int sums[128]; + + const int id = threadIdx.x; + const int lane_id = id % warpSize; + const int warp_id = id / warpSize; + + const uint4 data = img(blockIdx.x, id); + + const uchar4 a = int_to_uchar4(data.x); + const uchar4 b = int_to_uchar4(data.y); + const uchar4 c = int_to_uchar4(data.z); + const uchar4 d = int_to_uchar4(data.w); + + int result[16]; + + result[0] = a.x; + result[1] = result[0] + a.y; + result[2] = result[1] + a.z; + result[3] = result[2] + a.w; + + result[4] = result[3] + b.x; + result[5] = result[4] + b.y; + result[6] = result[5] + b.z; + result[7] = result[6] + b.w; + + result[8] = result[7] + c.x; + result[9] = result[8] + c.y; + result[10] = result[9] + c.z; + result[11] = result[10] + c.w; + + result[12] = result[11] + d.x; + result[13] = result[12] + d.y; + result[14] = result[13] + d.z; + result[15] = result[14] + d.w; + + int sum = result[15]; + + // the prefix sum for each thread's 16 value is computed, + // now the final sums (result[15]) need to be shared + // with the other threads and add. To do this, + // the __shfl_up() instruction is used and a shuffle scan + // operation is performed to distribute the sums to the correct + // threads + #pragma unroll + for (int i = 1; i < 32; i *= 2) + { + const int n = __shfl_up(sum, i, 32); + + if (lane_id >= i) + { + #pragma unroll + for (int i = 0; i < 16; ++i) + result[i] += n; + + sum += n; + } + } + + // Now the final sum for the warp must be shared + // between warps. This is done by each warp + // having a thread store to shared memory, then + // having some other warp load the values and + // compute a prefix sum, again by using __shfl_up. + // The results are uniformly added back to the warps. + // last thread in the warp holding sum of the warp + // places that in shared + if (threadIdx.x % warpSize == warpSize - 1) + sums[warp_id] = result[15]; + + __syncthreads(); + + if (warp_id == 0) + { + int warp_sum = sums[lane_id]; + + #pragma unroll + for (int i = 1; i <= 32; i *= 2) + { + const int n = __shfl_up(warp_sum, i, 32); + + if (lane_id >= i) + warp_sum += n; + } + + sums[lane_id] = warp_sum; + } + + __syncthreads(); + + int blockSum = 0; + + // fold in unused warp + if (warp_id > 0) + { + blockSum = sums[warp_id - 1]; + + #pragma unroll + for (int i = 0; i < 16; ++i) + result[i] += blockSum; + } + + // assemble result + // Each thread has 16 values to write, which are + // now integer data (to avoid overflow). Instead of + // each thread writing consecutive uint4s, the + // approach shown here experiments using + // the shuffle command to reformat the data + // inside the registers so that each thread holds + // consecutive data to be written so larger contiguous + // segments can be assembled for writing. + + /* + For example data that needs to be written as + + GMEM[16] <- x0 x1 x2 x3 y0 y1 y2 y3 z0 z1 z2 z3 w0 w1 w2 w3 + but is stored in registers (r0..r3), in four threads (0..3) as: + + threadId 0 1 2 3 + r0 x0 y0 z0 w0 + r1 x1 y1 z1 w1 + r2 x2 y2 z2 w2 + r3 x3 y3 z3 w3 + + after apply __shfl_xor operations to move data between registers r1..r3: + + threadId 00 01 10 11 + x0 y0 z0 w0 + xor(01)->y1 x1 w1 z1 + xor(10)->z2 w2 x2 y2 + xor(11)->w3 z3 y3 x3 + + and now x0..x3, and z0..z3 can be written out in order by all threads. + + In the current code, each register above is actually representing + four integers to be written as uint4's to GMEM. + */ + + result[4] = __shfl_xor(result[4] , 1, 32); + result[5] = __shfl_xor(result[5] , 1, 32); + result[6] = __shfl_xor(result[6] , 1, 32); + result[7] = __shfl_xor(result[7] , 1, 32); + + result[8] = __shfl_xor(result[8] , 2, 32); + result[9] = __shfl_xor(result[9] , 2, 32); + result[10] = __shfl_xor(result[10], 2, 32); + result[11] = __shfl_xor(result[11], 2, 32); + + result[12] = __shfl_xor(result[12], 3, 32); + result[13] = __shfl_xor(result[13], 3, 32); + result[14] = __shfl_xor(result[14], 3, 32); + result[15] = __shfl_xor(result[15], 3, 32); + + uint4* integral_row = integral.ptr(blockIdx.x); + uint4 output; + + /////// + + if (threadIdx.x % 4 == 0) + output = make_uint4(result[0], result[1], result[2], result[3]); + + if (threadIdx.x % 4 == 1) + output = make_uint4(result[4], result[5], result[6], result[7]); + + if (threadIdx.x % 4 == 2) + output = make_uint4(result[8], result[9], result[10], result[11]); + + if (threadIdx.x % 4 == 3) + output = make_uint4(result[12], result[13], result[14], result[15]); + + integral_row[threadIdx.x % 4 + (threadIdx.x / 4) * 16] = output; + + /////// + + if (threadIdx.x % 4 == 2) + output = make_uint4(result[0], result[1], result[2], result[3]); + + if (threadIdx.x % 4 == 3) + output = make_uint4(result[4], result[5], result[6], result[7]); + + if (threadIdx.x % 4 == 0) + output = make_uint4(result[8], result[9], result[10], result[11]); + + if (threadIdx.x % 4 == 1) + output = make_uint4(result[12], result[13], result[14], result[15]); + + integral_row[(threadIdx.x + 2) % 4 + (threadIdx.x / 4) * 16 + 8] = output; + + // continuning from the above example, + // this use of __shfl_xor() places the y0..y3 and w0..w3 data + // in order. + + #pragma unroll + for (int i = 0; i < 16; ++i) + result[i] = __shfl_xor(result[i], 1, 32); + + if (threadIdx.x % 4 == 0) + output = make_uint4(result[0], result[1], result[2], result[3]); + + if (threadIdx.x % 4 == 1) + output = make_uint4(result[4], result[5], result[6], result[7]); + + if (threadIdx.x % 4 == 2) + output = make_uint4(result[8], result[9], result[10], result[11]); + + if (threadIdx.x % 4 == 3) + output = make_uint4(result[12], result[13], result[14], result[15]); + + integral_row[threadIdx.x % 4 + (threadIdx.x / 4) * 16 + 4] = output; + + /////// + + if (threadIdx.x % 4 == 2) + output = make_uint4(result[0], result[1], result[2], result[3]); + + if (threadIdx.x % 4 == 3) + output = make_uint4(result[4], result[5], result[6], result[7]); + + if (threadIdx.x % 4 == 0) + output = make_uint4(result[8], result[9], result[10], result[11]); + + if (threadIdx.x % 4 == 1) + output = make_uint4(result[12], result[13], result[14], result[15]); + + integral_row[(threadIdx.x + 2) % 4 + (threadIdx.x / 4) * 16 + 12] = output; + #endif + } + + // This kernel computes columnwise prefix sums. When the data input is + // the row sums from above, this completes the integral image. + // The approach here is to have each block compute a local set of sums. + // First , the data covered by the block is loaded into shared memory, + // then instead of performing a sum in shared memory using __syncthreads + // between stages, the data is reformatted so that the necessary sums + // occur inside warps and the shuffle scan operation is used. + // The final set of sums from the block is then propgated, with the block + // computing "down" the image and adding the running sum to the local + // block sums. + __global__ void shfl_integral_vertical(DevMem2D_ integral) + { + #if __CUDA_ARCH__ >= 300 + __shared__ unsigned int sums[32][9]; + + const int tidx = blockIdx.x * blockDim.x + threadIdx.x; + const int lane_id = tidx % 8; + + if (tidx >= integral.cols) + return; + + sums[threadIdx.x][threadIdx.y] = 0; + __syncthreads(); + + unsigned int stepSum = 0; + + for (int y = threadIdx.y; y < integral.rows; y += blockDim.y) + { + unsigned int* p = integral.ptr(y) + tidx; + + unsigned int sum = *p; + + sums[threadIdx.x][threadIdx.y] = sum; + __syncthreads(); + + // place into SMEM + // shfl scan reduce the SMEM, reformating so the column + // sums are computed in a warp + // then read out properly + const int j = threadIdx.x % 8; + const int k = threadIdx.x / 8 + threadIdx.y * 4; + + int partial_sum = sums[k][j]; + + for (int i = 1; i <= 8; i *= 2) + { + int n = __shfl_up(partial_sum, i, 32); + + if (lane_id >= i) + partial_sum += n; + } + + sums[k][j] = partial_sum; + __syncthreads(); + + if (threadIdx.y > 0) + sum += sums[threadIdx.x][threadIdx.y - 1]; + + sum += stepSum; + stepSum += sums[threadIdx.x][blockDim.y - 1]; + + __syncthreads(); + + *p = sum; + } + #endif + } + + void shfl_integral_gpu(DevMem2Db img, DevMem2D_ integral, cudaStream_t stream) + { + { + // each thread handles 16 values, use 1 block/row + const int block = img.cols / 16; + + // launch 1 block / row + const int grid = img.rows; + + cudaSafeCall( cudaFuncSetCacheConfig(shfl_integral_horizontal, cudaFuncCachePreferL1) ); + + shfl_integral_horizontal<<>>((DevMem2D_) img, (DevMem2D_) integral); + cudaSafeCall( cudaGetLastError() ); + } + + { + const dim3 block(32, 8); + const dim3 grid(divUp(integral.cols, block.x), 1); + + shfl_integral_vertical<<>>(integral); + cudaSafeCall( cudaGetLastError() ); + } + + if (stream == 0) + cudaSafeCall( cudaDeviceSynchronize() ); + } + } +}}} diff --git a/modules/gpu/src/imgproc.cpp b/modules/gpu/src/imgproc.cpp index fe1ad7bd89..5b8fb9c057 100644 --- a/modules/gpu/src/imgproc.cpp +++ b/modules/gpu/src/imgproc.cpp @@ -223,7 +223,7 @@ void cv::gpu::reprojectImageTo3D(const GpuMat& disp, GpuMat& xyz, const Mat& Q, using namespace cv::gpu::device::imgproc; typedef void (*func_t)(const DevMem2Db disp, DevMem2Db xyz, const float* q, cudaStream_t stream); - static const func_t funcs[2][4] = + static const func_t funcs[2][4] = { {reprojectImageTo3D_gpu, 0, 0, reprojectImageTo3D_gpu}, {reprojectImageTo3D_gpu, 0, 0, reprojectImageTo3D_gpu} @@ -533,32 +533,86 @@ void cv::gpu::integral(const GpuMat& src, GpuMat& sum, Stream& s) integralBuffered(src, sum, buffer, s); } +namespace cv { namespace gpu { namespace device +{ + namespace imgproc + { + void shfl_integral_gpu(DevMem2Db img, DevMem2D_ integral, cudaStream_t stream); + } +}}} + void cv::gpu::integralBuffered(const GpuMat& src, GpuMat& sum, GpuMat& buffer, Stream& s) { CV_Assert(src.type() == CV_8UC1); - if (sum.cols != src.cols + 1 && sum.rows != src.rows + 1) - sum.create(src.rows + 1, src.cols + 1, CV_32S); - - NcvSize32u roiSize; - roiSize.width = src.cols; - roiSize.height = src.rows; - - cudaDeviceProp prop; - cudaSafeCall( cudaGetDeviceProperties(&prop, cv::gpu::getDevice()) ); - - Ncv32u bufSize; - ncvSafeCall( nppiStIntegralGetSize_8u32u(roiSize, &bufSize, prop) ); - ensureSizeIsEnough(1, bufSize, CV_8UC1, buffer); cudaStream_t stream = StreamAccessor::getStream(s); - NppStStreamHandler h(stream); + DeviceInfo info; - ncvSafeCall( nppiStIntegral_8u32u_C1R(const_cast(src.ptr()), static_cast(src.step), - sum.ptr(), static_cast(sum.step), roiSize, buffer.ptr(), bufSize, prop) ); + if (info.supports(WARP_SHUFFLE_FUNCTIONS)) + { + GpuMat src16; - if (stream == 0) - cudaSafeCall( cudaDeviceSynchronize() ); + if (src.cols % 16 == 0) + src16 = src; + else + { + ensureSizeIsEnough(src.rows, ((src.cols + 15) / 16) * 16, src.type(), buffer); + + GpuMat inner = buffer(Rect(0, 0, src.cols, src.rows)); + + if (s) + { + s.enqueueMemSet(buffer, Scalar::all(0)); + s.enqueueCopy(src, inner); + } + else + { + buffer.setTo(Scalar::all(0)); + src.copyTo(inner); + } + + src16 = buffer; + } + + sum.create(src16.rows + 1, src16.cols + 1, CV_32SC1); + + if (s) + s.enqueueMemSet(sum, Scalar::all(0)); + else + sum.setTo(Scalar::all(0)); + + GpuMat inner = sum(Rect(1, 1, src16.cols, src16.rows)); + + cv::gpu::device::imgproc::shfl_integral_gpu(src16, inner, stream); + + if (src16.cols != src.cols) + sum = sum(Rect(0, 0, src.cols + 1, src.rows + 1)); + } + else + { + sum.create(src.rows + 1, src.cols + 1, CV_32SC1); + + NcvSize32u roiSize; + roiSize.width = src.cols; + roiSize.height = src.rows; + + cudaDeviceProp prop; + cudaSafeCall( cudaGetDeviceProperties(&prop, cv::gpu::getDevice()) ); + + Ncv32u bufSize; + ncvSafeCall( nppiStIntegralGetSize_8u32u(roiSize, &bufSize, prop) ); + ensureSizeIsEnough(1, bufSize, CV_8UC1, buffer); + + + NppStStreamHandler h(stream); + + ncvSafeCall( nppiStIntegral_8u32u_C1R(const_cast(src.ptr()), static_cast(src.step), + sum.ptr(), static_cast(sum.step), roiSize, buffer.ptr(), bufSize, prop) ); + + if (stream == 0) + cudaSafeCall( cudaDeviceSynchronize() ); + } } ////////////////////////////////////////////////////////////////////////////// @@ -1340,7 +1394,7 @@ Size cv::gpu::ConvolveBuf::estimateBlockSize(Size result_size, Size /*templ_size int width = (result_size.width + 2) / 3; int height = (result_size.height + 2) / 3; width = std::min(width, result_size.width); - height = std::min(height, result_size.height); + height = std::min(height, result_size.height); return Size(width, height); } @@ -1380,7 +1434,7 @@ void cv::gpu::convolve(const GpuMat& image, const GpuMat& templ, GpuMat& result, cufftHandle planR2C, planC2R; cufftSafeCall(cufftPlan2d(&planC2R, dft_size.height, dft_size.width, CUFFT_C2R)); - cufftSafeCall(cufftPlan2d(&planR2C, dft_size.height, dft_size.width, CUFFT_R2C)); + cufftSafeCall(cufftPlan2d(&planR2C, dft_size.height, dft_size.width, CUFFT_R2C)); cufftSafeCall( cufftSetStream(planR2C, StreamAccessor::getStream(stream)) ); cufftSafeCall( cufftSetStream(planC2R, StreamAccessor::getStream(stream)) ); From e95bc7d502ce74748cde30c48bc54e360e039fd1 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Wed, 22 Aug 2012 13:33:13 +0400 Subject: [PATCH 053/163] fixed ios camera timing (patch by Eduard Feicho) --- .../highgui/include/opencv2/highgui/cap_ios.h | 5 +- modules/highgui/src/cap_ios_video_camera.mm | 149 +++++------------- 2 files changed, 43 insertions(+), 111 deletions(-) diff --git a/modules/highgui/include/opencv2/highgui/cap_ios.h b/modules/highgui/include/opencv2/highgui/cap_ios.h index cc6668ace0..26a28c077b 100644 --- a/modules/highgui/include/opencv2/highgui/cap_ios.h +++ b/modules/highgui/include/opencv2/highgui/cap_ios.h @@ -80,7 +80,6 @@ @property (nonatomic, retain) UIView* parentView; -- (void)pause; - (void)start; - (void)stop; - (void)switchCameras; @@ -120,6 +119,8 @@ AVAssetWriterInput* recordAssetWriterInput; AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; AVAssetWriter* recordAssetWriter; + + CMTime lastSampleTime; } @@ -134,6 +135,8 @@ - (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; - (void)layoutPreviewLayer; - (void)saveVideo; +- (NSURL *)videoFileURL; + @end diff --git a/modules/highgui/src/cap_ios_video_camera.mm b/modules/highgui/src/cap_ios_video_camera.mm index 6f7bfa20fc..0a162ebea0 100644 --- a/modules/highgui/src/cap_ios_video_camera.mm +++ b/modules/highgui/src/cap_ios_video_camera.mm @@ -98,90 +98,29 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; { [super start]; - if (self.recordVideo == YES) { -// [self.videoFileOutput startRecordingToOutputFileURL:[self tempFileURL] recordingDelegate:self]; - + if (self.recordVideo == YES) { NSError* error; - if ([[NSFileManager defaultManager] fileExistsAtPath:[self tempFileString]]) [[NSFileManager defaultManager] removeItemAtPath:[self tempFileString] error:&error]; + if ([[NSFileManager defaultManager] fileExistsAtPath:[self videoFileString]]) { + [[NSFileManager defaultManager] removeItemAtPath:[self videoFileString] error:&error]; + } if (error == nil) { - NSLog(@"[Camera] Delete file %@", [self tempFileString]); - } - - - BOOL started = [self.recordAssetWriter startWriting]; - [self.recordAssetWriter startSessionAtSourceTime:kCMTimeZero]; - - NSLog(@"[Camera] Session started? %d", started); - - if (self.recordAssetWriter.status == AVAssetWriterStatusUnknown) { - NSLog(@"AVAssetWriter status: unknown"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { - NSLog(@"AVAssetWriter status: writing"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusCompleted) { - NSLog(@"AVAssetWriter status: completed"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusFailed) { - NSLog(@"AVAssetWriter status: failed"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusCancelled) { - NSLog(@"AVAssetWriter status: cancelled"); - } - - if (self.recordAssetWriter.status != AVAssetWriterStatusWriting) { - NSLog(@"[Camera] Recording Error: asset writer status is not writing: %@", self.recordAssetWriter.error); - } else { - NSLog(@"[Camera] Recording started"); + NSLog(@"[Camera] Delete file %@", [self videoFileString]); } } } -- (void)pause; -{ - [super pause]; - if (self.recordVideo == YES) { -// [self.videoFileOutput stopRecording]; - - - if (self.recordAssetWriter.status == AVAssetWriterStatusUnknown) { - NSLog(@"AVAssetWriter status: unknown"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { - NSLog(@"AVAssetWriter status: writing"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusCompleted) { - NSLog(@"AVAssetWriter status: completed"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusFailed) { - NSLog(@"AVAssetWriter status: failed"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusCancelled) { - NSLog(@"AVAssetWriter status: cancelled"); - } - - if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { - [self.recordAssetWriter finishWriting]; - NSLog(@"[Camera] recording stopped"); - } else { - NSLog(@"[Camera] Recording Error: asset writer status is not writing"); - } - } -} - - - (void)stop; { [super stop]; - if (self.recordVideo == YES) { - NSLog(@"recording stop"); - if (self.recordAssetWriter.status == AVAssetWriterStatusUnknown) { - NSLog(@"AVAssetWriter status: unknown"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { - NSLog(@"AVAssetWriter status: writing"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusCompleted) { - NSLog(@"AVAssetWriter status: completed"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusFailed) { - NSLog(@"AVAssetWriter status: failed"); - } else if (self.recordAssetWriter.status == AVAssetWriterStatusCancelled) { - NSLog(@"AVAssetWriter status: cancelled"); - } - + self.videoDataOutput = nil; + if (videoDataOutputQueue) { + dispatch_release(videoDataOutputQueue); + } + + if (self.recordVideo == YES) { if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) { [self.recordAssetWriter finishWriting]; @@ -194,11 +133,6 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; self.recordAssetWriterInput = nil; self.recordPixelBufferAdaptor = nil; } - - self.videoDataOutput = nil; - if (videoDataOutputQueue) { - dispatch_release(videoDataOutputQueue); - } [self.customPreviewLayer removeFromSuperlayer]; self.customPreviewLayer = nil; @@ -405,15 +339,6 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; - (void)createVideoFileOutput; { - /* - if (self.recordVideo == YES) { - self.videoFileOutput = [[AVCaptureMovieFileOutput alloc] init]; - if ( [self.captureSession canAddOutput:self.videoFileOutput] ) { - [self.captureSession addOutput:self.videoFileOutput]; - } - } - */ - /* Video File Output in H.264, via AVAsserWriter */ NSLog(@"Create Video with dimensions %dx%d", self.imageWidth, self.imageHeight); @@ -426,21 +351,18 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; self.recordAssetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings]; - - /* I'm going to push pixel buffers to it, so will need a - AVAssetWriterPixelBufferAdaptor, to expect the same 32BGRA input as I've - asked the AVCaptureVideDataOutput to supply */ + int pixelBufferFormat = (self.grayscaleMode == YES) ? kCVPixelFormatType_420YpCbCr8BiPlanarFullRange : kCVPixelFormatType_32BGRA; self.recordPixelBufferAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:self.recordAssetWriterInput - sourcePixelBufferAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:pixelBufferFormat], kCVPixelBufferPixelFormatTypeKey,nil]]; + sourcePixelBufferAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:pixelBufferFormat], kCVPixelBufferPixelFormatTypeKey, nil]]; NSError* error = nil; - NSLog(@"Create AVAssetWriter with url: %@", [self tempFileURL]); - self.recordAssetWriter = [AVAssetWriter assetWriterWithURL:[self tempFileURL] + NSLog(@"Create AVAssetWriter with url: %@", [self videoFileURL]); + self.recordAssetWriter = [AVAssetWriter assetWriterWithURL:[self videoFileURL] fileType:AVFileTypeMPEG4 error:&error]; if (error != nil) { @@ -448,10 +370,9 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; } [self.recordAssetWriter addInput:self.recordAssetWriterInput]; - self.recordAssetWriterInput.expectsMediaDataInRealTime = NO; + self.recordAssetWriterInput.expectsMediaDataInRealTime = YES; NSLog(@"[Camera] created AVAssetWriter"); - } @@ -580,8 +501,6 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; } - - // render buffer dispatch_sync(dispatch_get_main_queue(), ^{ self.customPreviewLayer.contents = (__bridge id)dstImage; @@ -589,16 +508,26 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; if (self.recordVideo == YES) { - // a very dense way to keep track of the time at which this frame - // occurs relative to the output stream, but it's just an example! - - // TODO reset frame number - static int64_t frameNumber = 0; - if (self.recordAssetWriterInput.readyForMoreMediaData) { - [self.recordPixelBufferAdaptor appendPixelBuffer:imageBuffer - withPresentationTime:CMTimeMake(frameNumber, self.defaultFPS)]; + lastSampleTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer); +// CMTimeShow(lastSampleTime); + if (self.recordAssetWriter.status != AVAssetWriterStatusWriting) { + [self.recordAssetWriter startWriting]; + [self.recordAssetWriter startSessionAtSourceTime:lastSampleTime]; + if (self.recordAssetWriter.status != AVAssetWriterStatusWriting) { + NSLog(@"[Camera] Recording Error: asset writer status is not writing: %@", self.recordAssetWriter.error); + return; + } else { + NSLog(@"[Camera] Video recording started"); + } } - frameNumber++; + + if (self.recordAssetWriterInput.readyForMoreMediaData) { + if (! [self.recordPixelBufferAdaptor appendPixelBuffer:imageBuffer + withPresentationTime:lastSampleTime] ) { + NSLog(@"Video Writing Error"); + } + } + } @@ -627,14 +556,14 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; } ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; - if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:[self tempFileURL]]) { - [library writeVideoAtPathToSavedPhotosAlbum:[self tempFileURL] + if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:[self videoFileURL]]) { + [library writeVideoAtPathToSavedPhotosAlbum:[self videoFileURL] completionBlock:^(NSURL *assetURL, NSError *error){}]; } } -- (NSURL *)tempFileURL; +- (NSURL *)videoFileURL; { NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"]; NSURL *outputURL = [NSURL fileURLWithPath:outputPath]; @@ -647,7 +576,7 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; -- (NSString *)tempFileString; +- (NSString *)videoFileString; { NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"]; return outputPath; From bbf679267ae1ffdd4bdedb5497a8e03ed059678b Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Wed, 22 Aug 2012 15:48:57 +0400 Subject: [PATCH 054/163] modified facedetect to properly display very oblong objects and optionally flip image horizontally (for profile face detection). Added LBP cascades by Attila Novak for profile face detection and silverware detection (those are results of GSoC 2012) --- data/lbpcascades/lbpcascade_profileface.xml | 1275 ++++++++++++++++++ data/lbpcascades/lbpcascade_silverware.xml | 1279 +++++++++++++++++++ samples/c/facedetect.cpp | 90 +- 3 files changed, 2615 insertions(+), 29 deletions(-) create mode 100755 data/lbpcascades/lbpcascade_profileface.xml create mode 100755 data/lbpcascades/lbpcascade_silverware.xml diff --git a/data/lbpcascades/lbpcascade_profileface.xml b/data/lbpcascades/lbpcascade_profileface.xml new file mode 100755 index 0000000000..a9e8437306 --- /dev/null +++ b/data/lbpcascades/lbpcascade_profileface.xml @@ -0,0 +1,1275 @@ + + + + + BOOST + LBP + 34 + 20 + + GAB + 9.9500000476837158e-001 + 3.0000001192092896e-001 + 9.4999999999999996e-001 + 1 + 100 + + 256 + 1 + 16 + + + <_> + 4 + -5.9480339288711548e-001 + + <_> + + 0 -1 114 -2360321 -82228595 -771518211 -713436773 + -1060447799 -810385271 -2004135683 -2566104 + + -8.0942183732986450e-001 5.9530025720596313e-001 + <_> + + 0 -1 54 -649134608 -1060077114 1375916272 -719981432 + 1073801352 33024 281198795 -5246465 + + -7.7979278564453125e-001 5.4052764177322388e-001 + <_> + + 0 -1 12 -960266913 -495857599 -1068498864 -867970987 + 457398579 -1174173695 1749041235 1849162079 + + -8.0028575658798218e-001 5.0435048341751099e-001 + <_> + + 0 -1 120 -1228145793 -807247727 18059735 -138644520 + 998980043 -41250583 673112549 -1930366540 + + -7.7902388572692871e-001 4.9006074666976929e-001 + + <_> + 6 + -5.4879629611968994e-001 + + <_> + + 0 -1 6 -254346881 -746143606 -1039596583 1963430479 + -263790449 -1073545213 698505999 -1349357 + + -6.6315788030624390e-001 6.0000002384185791e-001 + <_> + + 0 -1 112 -134225985 -684228389 -988213089 -684716007 + -1966960899 -896630615 152815840 -864497420 + + -7.0195454359054565e-001 5.8843690156936646e-001 + <_> + + 0 -1 53 -35923461 520818827 -1862167847 856916291 68141197 + 2072530978 304306417 526079163 + + -6.4593964815139771e-001 5.7274609804153442e-001 + <_> + + 0 -1 101 -2097665 -1781432163 588321018 -1677405808 + -1968469982 -1450147831 -1467632684 -593693808 + + -7.2959578037261963e-001 4.9470889568328857e-001 + <_> + + 0 -1 79 -205847273 -1088716541 285266431 1393693056 + 293931101 -1634205688 -452263692 -111136684 + + -7.0331865549087524e-001 5.2564400434494019e-001 + <_> + + 0 -1 126 579801457 -670613495 -1065269989 -117095565 + -1295163359 -779534335 -1744220101 -1355860 + + -7.5121974945068359e-001 4.5217981934547424e-001 + + <_> + 4 + -4.3886357545852661e-001 + + <_> + + 0 -1 20 -346563793 1217040543 -1324639677 206303367 + -260894653 1165249072 1359168335 1652518863 + + -8.3054625988006592e-001 5.5417186021804810e-001 + <_> + + 0 -1 69 -925898078 -917290147 -2147368790 -1995968378 + 1203961890 1765910571 789128481 -4201473 + + -7.5220447778701782e-001 6.1290657520294189e-001 + <_> + + 0 -1 7 -425790473 -368916470 -1065172848 -1877712894 + -1067360254 -847191997 1342400518 -680037517 + + -7.8469508886337280e-001 5.9731280803680420e-001 + <_> + + 0 -1 5 -260315918 -1567751150 -805289977 1721229843 + 1644296976 1954742530 824530213 -8392601 + + -7.3686408996582031e-001 5.6347119808197021e-001 + + <_> + 6 + -4.6629825234413147e-001 + + <_> + + 0 -1 111 -67634177 -72175593 -246181185 -144772036 + -1465917455 -1426934837 -345249307 -539041852 + + -7.1692305803298950e-001 5.5034482479095459e-001 + <_> + + 0 -1 47 -1048705 -96415158 -1996126927 67301684 -659873481 + 1800863745 -402143413 1647570815 + + -7.6134461164474487e-001 4.7370144724845886e-001 + <_> + + 0 -1 119 1905247351 -1111526689 1426654203 -116427277 + 1731664419 -81052249 1051905317 -1628448513 + + -5.9460461139678955e-001 6.1952447891235352e-001 + <_> + + 0 -1 2 578486263 -2115313530 -788268733 -1122507629 + -343408719 2127242147 -85406399 -37295 + + -6.0801470279693604e-001 5.8719038963317871e-001 + <_> + + 0 -1 127 -1147176065 52139167 21156225 -540503783 -771529299 + -33325024 -671045243 -1913073360 + + -7.4383884668350220e-001 5.1643568277359009e-001 + <_> + + 0 -1 93 -319091633 -58633529 1166906391 1854443149 + 1267403009 -1198817246 1208634960 -35661669 + + -6.8595260381698608e-001 5.5931246280670166e-001 + + <_> + 8 + -6.0948312282562256e-001 + + <_> + + 0 -1 102 -747899393 -543522675 545333467 -34230241 + -1572626245 -17790840 -1182162691 -1078427420 + + -6.0826772451400757e-001 4.6491229534149170e-001 + <_> + + 0 -1 38 -103812609 503024467 -2121908081 722834075 + 1375757518 2022089353 197321677 2077719203 + + -6.2948691844940186e-001 4.8044654726982117e-001 + <_> + + 0 -1 19 -774429826 -607461158 1158791644 -971587409 + -1732167611 2015560010 -1278549257 -159911361 + + -5.9694272279739380e-001 4.7999730706214905e-001 + <_> + + 0 -1 122 735837495 -875325281 152208339 -741020481 + -1471817477 -1165246433 -1450830159 -1696546384 + + -6.4947181940078735e-001 4.2661586403846741e-001 + <_> + + 0 -1 104 -629063145 -49708711 50692231 1973945160 157637120 + 2056259593 1771350547 -78911181 + + -6.2496536970138550e-001 4.4524449110031128e-001 + <_> + + 0 -1 67 -74189973 -803307502 688005268 1600057378 -131870050 + -1600503318 571446250 -386668002 + + -5.5046343803405762e-001 5.6090569496154785e-001 + <_> + + 0 -1 81 586347861 -2071051852 -250078020 -1455374076 + 546287843 1216708619 -1853707673 -35130912 + + -6.3877129554748535e-001 4.7911971807479858e-001 + <_> + + 0 -1 22 -1436568057 1555188001 164315 2084672259 1809869105 + 1132626050 1223430266 -596124761 + + -6.4428490400314331e-001 4.7921949625015259e-001 + + <_> + 8 + -5.4387503862380981e-001 + + <_> + + 0 -1 44 -783680003 -771883143 -302055943 -5898247 -253370375 + -1996628131 1625947386 -2004157446 + + -5.2870607376098633e-001 5.9474670886993408e-001 + <_> + + 0 -1 49 -586034977 -41205679 352424062 -163145456 151126042 + -1171652503 1208036058 -9019322 + + -5.6763833761215210e-001 4.8789894580841064e-001 + <_> + + 0 -1 39 1402589836 1363509256 103583 823365787 -1861443377 + 412131360 539718283 1002160350 + + -5.9899079799652100e-001 4.9562713503837585e-001 + <_> + + 0 -1 113 -783429121 -1559215981 286355953 -794820602 + 461510679 -611662910 -2136237584 -96429424 + + -6.3842493295669556e-001 4.3330931663513184e-001 + <_> + + 0 -1 99 -1365839532 -1291265163 1091604493 965968977 + 147472779 -1466925055 -2013090821 -1410703205 + + -5.8633142709732056e-001 5.0152444839477539e-001 + <_> + + 0 -1 26 1846469631 -788479850 268796195 -754872317 + 1630603451 -896532480 1208092751 -72652777 + + -5.9243172407150269e-001 4.7917708754539490e-001 + <_> + + 0 -1 85 -715395062 -113037167 1342198133 -552594287 + 411123713 11059209 -2012512153 -877809205 + + -6.9079184532165527e-001 4.2610234022140503e-001 + <_> + + 0 -1 100 -526391817 -921022135 -1593630697 671093393 + -2004270453 -1962835840 -1870413655 -1597095644 + + -6.5030521154403687e-001 4.4748127460479736e-001 + + <_> + 8 + -6.3195121288299561e-001 + + <_> + + 0 -1 109 -674761315 -581726065 352407899 -83717423 + -660870145 -1165915966 -326837763 -927182608 + + -7.3185729980468750e-001 3.3258172869682312e-001 + <_> + + 0 -1 97 860755579 -707063662 1361264863 1065505299 + -1022866435 -1776123776 -1865661700 -1615196136 + + -6.1147916316986084e-001 3.7205791473388672e-001 + <_> + + 0 -1 15 -678435969 -106962866 268652561 -826396597 + -802066313 1931092070 1208025439 1211582847 + + -6.8679082393646240e-001 3.6285603046417236e-001 + <_> + + 0 -1 86 -1573074550 -2080337595 299991 110482176 268552379 + -310373944 596185787 -1428952165 + + -6.4654982089996338e-001 4.1456297039985657e-001 + <_> + + 0 -1 30 -72637790 -1258143612 1342937104 -544352374 + -1046875163 -121076606 -786059128 -71702400 + + -5.2772462368011475e-001 4.9787566065788269e-001 + <_> + + 0 -1 89 -683288417 -218031996 33734999 -16115386 -2013259561 + -2008907509 -1978533232 -352342880 + + -5.2718847990036011e-001 5.2839303016662598e-001 + <_> + + 0 -1 10 -268764033 -1078984772 -65537 -281182212 -524291 -1 + -8489090 -4227265 + + -5.0513482093811035e-001 5.8522778749465942e-001 + <_> + + 0 -1 82 -570445845 784662143 -268435661 -1292701712 + -436263043 -1367507075 -671091243 -751108132 + + -5.2438414096832275e-001 5.4709094762802124e-001 + + <_> + 8 + -5.9874147176742554e-001 + + <_> + + 0 -1 27 -721421649 -1001940437 2300046 -720004829 -792686333 + 1908900882 -160055232 -134763633 + + -5.7692307233810425e-001 3.7921348214149475e-001 + <_> + + 0 -1 78 -1764279809 -1755824061 1937871313 -42069793 + -1241158993 -1196293937 -1576828673 -70371296 + + -4.7039109468460083e-001 4.8607903718948364e-001 + <_> + + 0 -1 29 -795875130 432079111 285457049 -620658641 -780072971 + 1158283432 -226254016 1839935243 + + -6.2938809394836426e-001 4.1353255510330200e-001 + <_> + + 0 -1 33 -37236389 1654493543 202129823 1788182787 + -1186162321 1912913933 -122942838 1968176815 + + -5.9031385183334351e-001 4.1488575935363770e-001 + <_> + + 0 -1 88 1903888863 -286828472 -2125248034 -623115882 + -268301806 -894826357 -2046633148 -696873056 + + -6.3875061273574829e-001 4.0209171175956726e-001 + <_> + + 0 -1 123 -87223501 -1873424249 -1878929092 -586710990 + -643825151 -1039040192 -285122488 -264093 + + -5.4196298122406006e-001 4.5856228470802307e-001 + <_> + + 0 -1 52 -780030833 1363755203 -385150929 25502018 1214818435 + -1020786271 -1870036478 1200354241 + + -5.2826374769210815e-001 5.3351372480392456e-001 + <_> + + 0 -1 84 -1724706499 -184429355 620844509 -179010317 + -1610327896 -341801844 -1190328066 1755915264 + + -5.7672232389450073e-001 4.4138705730438232e-001 + + <_> + 9 + -5.4533123970031738e-001 + + <_> + + 0 -1 48 -254347649 -565919658 1079050328 1090502875 + 1895985446 2013437961 -916419445 -53481573 + + -5.8105266094207764e-001 3.3599999547004700e-001 + <_> + + 0 -1 65 2030928895 1438877010 1124143121 258207763 + 1361199276 1527410834 2072519624 1004267991 + + -5.9629368782043457e-001 3.6112698912620544e-001 + <_> + + 0 -1 45 -247204964 -242712316 54544644 892459288 1888023456 + -2138044280 -802615208 13199500 + + -6.5467655658721924e-001 3.0486112833023071e-001 + <_> + + 0 -1 3 -430509345 -1865653973 554091143 -1069121312 + 1091180718 50577994 -1031731181 -211321225 + + -5.8759629726409912e-001 3.9526104927062988e-001 + <_> + + 0 -1 106 -741412064 -255623164 1090945848 -1687760764 + 42428760 -1064762741 -1861683196 -81029101 + + -6.5875691175460815e-001 3.4154877066612244e-001 + <_> + + 0 -1 128 -464010241 762112 285299147 -589082223 1373135017 + -2138955645 1057005712 -526876236 + + -6.5968728065490723e-001 3.3614772558212280e-001 + <_> + + 0 -1 80 -666744719 -635780797 33637339 -887860848 + -1073532217 -108904320 440608996 -1100753973 + + -5.0520354509353638e-001 4.4810971617698669e-001 + <_> + + 0 -1 28 -1580738774 -1506653838 302055688 -721223615 + 1427604224 -1566332144 1078565791 -558431977 + + -5.5560898780822754e-001 4.3426483869552612e-001 + <_> + + 0 -1 103 957796629 538644536 352997725 80838797 453085387 + -1165492198 285346042 1487077737 + + -5.5915868282318115e-001 4.0778505802154541e-001 + + <_> + 9 + -6.7299038171768188e-001 + + <_> + + 0 -1 0 -882973185 -620584737 279035921 -673986422 + -1568464349 -2105466877 1468391879 -38825 + + -5.7544225454330444e-001 3.4235453605651855e-001 + <_> + + 0 -1 90 -1820101795 -1336770299 285245717 -57216724 + -502134548 -1425341984 -1475618680 -1195896480 + + -6.6810834407806396e-001 2.7653357386589050e-001 + <_> + + 0 -1 9 -100197449 -457893579 200991 1964749325 -754875920 + 1897044675 1669843618 -70792821 + + -4.9064287543296814e-001 4.3120625615119934e-001 + <_> + + 0 -1 117 -792114173 -544111547 537001999 2034569362 + -1065213888 1630052634 -1450583484 -532405661 + + -6.4218991994857788e-001 3.6113587021827698e-001 + <_> + + 0 -1 107 -1564241697 -1429683702 -2062974587 -1900539448 + -1040078205 -394262006 -188628336 -390485984 + + -5.9181970357894897e-001 3.5756480693817139e-001 + <_> + + 0 -1 4 1893434787 -1945108258 82458 -318734161 -939347837 + 684196040 1078496869 2133023515 + + -6.1955446004867554e-001 3.4674292802810669e-001 + <_> + + 0 -1 31 -196247204 1964277780 -1810886012 21827851 + -364280891 -1062338560 -536741128 -362562814 + + -5.2849757671356201e-001 4.1380330920219421e-001 + <_> + + 0 -1 61 -1929140897 353472529 -721412674 -1228123782 + -392951233 -1442693096 672800826 -232914898 + + -5.7934975624084473e-001 3.9208874106407166e-001 + <_> + + 0 -1 72 -1004361296 -1069243858 268710018 1393598601 + 213956864 417530145 -912735606 1327495627 + + -7.5585323572158813e-001 2.6728668808937073e-001 + + <_> + 9 + -7.1303337812423706e-001 + + <_> + + 0 -1 23 -557797393 1524138462 277074064 -737259367 + -1878818960 -81600384 -1740109301 -59267505 + + -6.7397260665893555e-001 1.9793814420700073e-001 + <_> + + 0 -1 42 -1222377543 960610456 -2013138684 -989277927 + -1010064731 -802979830 -645806439 -885143219 + + -4.5935314893722534e-001 4.1904711723327637e-001 + <_> + + 0 -1 124 -783292542 -728791016 1342570700 1481418249 + 1258825942 -1580563964 -1178136688 -272306640 + + -6.3012123107910156e-001 2.9463621973991394e-001 + <_> + + 0 -1 46 1369396573 -188563225 22085642 -1005861886 + 2023260232 -1123842045 -2146991925 1245170171 + + -5.2092707157135010e-001 3.9743596315383911e-001 + <_> + + 0 -1 64 1540188400 1976259599 -805025279 864127692 544944 + 1484935304 -2147056504 1002584738 + + -6.5315401554107666e-001 3.1758561730384827e-001 + <_> + + 0 -1 77 -188606981 -1873391210 16842830 -117157654 + -1576842600 -1454767992 -518835576 -1625272280 + + -5.8580338954925537e-001 3.4936144948005676e-001 + <_> + + 0 -1 18 -473497030 -477572088 16842905 -12164860 184698994 + 1350566019 -2143169323 1405313030 + + -6.0962837934494019e-001 3.0044576525688171e-001 + <_> + + 0 -1 92 -528022006 -611028904 1075937757 -577660920 + 1073809492 -1341620207 -1475846395 -162412743 + + -6.6547930240631104e-001 3.1993752717971802e-001 + <_> + + 0 -1 116 -2062347245 35311783 406966429 -640155632 + -1904205761 -2012610494 399245455 -937752211 + + -4.8515367507934570e-001 4.3642494082450867e-001 + + <_> + 10 + -1.1831332445144653e+000 + + <_> + + 0 -1 115 -912525479 -2146793066 247327 -554139184 320582141 + -1442774971 1552517769 -1464330096 + + -7.2892564535140991e-001 1.2876711785793304e-001 + <_> + + 0 -1 41 -182757566 -683667118 268566545 -540408959 + 1547915506 2014497074 1817806103 -549486525 + + -5.6024330854415894e-001 2.8734233975410461e-001 + <_> + + 0 -1 13 -1396013057 -175218480 536903951 -35946104 -92067077 + 956498056 -200474487 1331907188 + + -5.5237007141113281e-001 3.2844060659408569e-001 + <_> + + 0 -1 17 2110443855 1547702666 -1874853670 1083212172 + -2004008413 -498614008 572624451 1179093527 + + -7.2481799125671387e-001 2.6627025008201599e-001 + <_> + + 0 -1 43 -1751428966 -1626324992 -1073540847 -783806124 + -2146909454 -913440767 -2138941303 -558233160 + + -4.4304186105728149e-001 4.1505634784698486e-001 + <_> + + 0 -1 37 -576405461 -1625709950 1627439763 1116373274 + 1622902452 1107834529 975868423 2074176171 + + -5.6509882211685181e-001 3.5433205962181091e-001 + <_> + + 0 -1 118 1171205664 1426522307 49281 563122240 -791985520 + -930869245 -364148081 -590624140 + + -5.6250953674316406e-001 3.3341854810714722e-001 + <_> + + 0 -1 76 1162033968 1180991656 16859165 230787289 -2104786299 + -1819967351 1118240928 -343561865 + + -4.7331553697586060e-001 4.1576251387596130e-001 + <_> + + 0 -1 110 -2147085315 -1228897088 -2146839339 -1751314339 + -531605907 -393183232 1804153563 -1399324416 + + -5.8979070186614990e-001 3.7525305151939392e-001 + <_> + + 0 -1 55 1581887865 999817729 151311688 331546624 -991625824 + -938834941 1837335184 852075394 + + -5.4071021080017090e-001 4.0077716112136841e-001 + + <_> + 10 + -6.4480733871459961e-001 + + <_> + + 0 -1 16 -510660401 -884555766 272896026 -12189566 + -1685363509 -662568805 1073840823 -545105785 + + -5.3361344337463379e-001 2.7807486057281494e-001 + <_> + + 0 -1 48 -557408354 2115155922 -2130669353 1616707591 + 693193240 -1569554175 -1743918878 1983596555 + + -5.3364741802215576e-001 3.1411096453666687e-001 + <_> + + 0 -1 108 -413278733 83935516 536961502 1452278484 + -2004277212 -391683967 -1426466672 -85395040 + + -7.4530494213104248e-001 2.3025059700012207e-001 + <_> + + 0 -1 32 -938623022 1469386887 822151432 421593370 + -1433793568 -1602191360 -527916919 680112651 + + -4.6078306436538696e-001 4.0021440386772156e-001 + <_> + + 0 -1 50 1619785226 -1004367410 1417725137 126732357 + 148062614 -625983352 -712398335 -412918226 + + -4.9818846583366394e-001 3.6678382754325867e-001 + <_> + + 0 -1 24 -1064322531 1351938204 196691 -561840073 -1978859471 + -649944954 -2003664885 -1172094197 + + -4.7309580445289612e-001 4.2868506908416748e-001 + <_> + + 0 -1 96 -1878961904 1360035888 -1073721317 -1051487863 + -431841087 1628112896 -2112640640 -1829440828 + + -6.9250243902206421e-001 2.8783574700355530e-001 + <_> + + 0 -1 62 67496095 391741589 -2146154237 96245592 -893992548 + 982687872 571488264 278906307 + + -6.4613574743270874e-001 3.0145862698554993e-001 + <_> + + 0 -1 73 -415771792 1208487966 339825796 1792117580 + 1128517807 144965669 -536376816 732856538 + + -6.9449120759963989e-001 3.0338683724403381e-001 + <_> + + 0 -1 40 -1991530440 324215457 -2080275930 -1857940798 + 1342685625 721420800 1250592988 1493903457 + + -7.0043331384658813e-001 2.5916099548339844e-001 + + <_> + 10 + -6.0248321294784546e-001 + + <_> + + 0 -1 21 -16537745 2114438797 1409323561 1691064397 + -207434939 822260754 -384857461 2031088579 + + -6.1256545782089233e-001 1.7948718369007111e-001 + <_> + + 0 -1 1 -95427858 67117166 -1308426467 -1962693439 601886855 + 924320187 1661215701 2078945158 + + -6.8756872415542603e-001 2.2317354381084442e-001 + <_> + + 0 -1 121 -1853361185 -619857007 16793601 -184516476 + -1422775873 -488996831 1476610285 -926297672 + + -5.2260422706604004e-001 3.2479336857795715e-001 + <_> + + 0 -1 105 -267171326 1436635177 1937772829 -2092859315 + -769638067 -2122268534 1502103583 -18894227 + + -5.2588832378387451e-001 3.4061828255653381e-001 + <_> + + 0 -1 83 1880187281 -1862250368 303299 960921986 -2002701917 + -1593343958 -334888263 1058018448 + + -6.9037044048309326e-001 2.7262538671493530e-001 + <_> + + 0 -1 34 -2125487365 1347551377 -1861970752 1368654274 + -1064675233 436275211 327448684 2068015115 + + -5.3338903188705444e-001 3.2425448298454285e-001 + <_> + + 0 -1 36 1192659162 235536712 1078002258 428089414 + -2138651204 -1937242101 507742421 1932739127 + + -6.4654779434204102e-001 3.0722403526306152e-001 + <_> + + 0 -1 14 -805047416 -1962622822 -2013265442 2030239751 + 1082134810 1744963592 -1836871485 -249326965 + + -5.7250964641571045e-001 3.1499111652374268e-001 + <_> + + 0 -1 75 -650653297 170234379 -2063527695 448823424 + -2139088862 319586315 -2067685344 -1347692410 + + -5.4618871212005615e-001 3.8171616196632385e-001 + <_> + + 0 -1 56 -168821125 -1107300354 -536871052 -1125515426 + -1795721360 -1672085508 1845358040 -2114327569 + + -4.2669427394866943e-001 5.0532561540603638e-001 + + <_> + 11 + -1.1912760734558105e+000 + + <_> + + 0 -1 11 -1043414305 -1735900650 268517385 -1137929054 + -1048411462 -2011152253 -1957405841 -497557425 + + -5.7042253017425537e-001 2.1933962404727936e-001 + <_> + + 0 -1 71 -233469310 1360073157 376971 626087057 -1180588024 + -1191067261 -1474310132 830601690 + + -5.3927713632583618e-001 2.9026004672050476e-001 + <_> + + 0 -1 35 -1599643389 42074270 -1811918838 -949960625 + 1564707361 289538187 1204527649 -112006873 + + -6.0980087518692017e-001 2.8851604461669922e-001 + <_> + + 0 -1 59 585529126 -1100070936 -1342177537 833961983 + 1306961797 1986559992 -810088568 -1082149201 + + -3.2345715165138245e-001 5.5635309219360352e-001 + <_> + + 0 -1 95 1107806555 2030223765 17039707 -1224163308 + -1073053535 -1291837432 822618633 -121972608 + + -6.5054124593734741e-001 3.1912675499916077e-001 + <_> + + 0 -1 51 -171583461 -1660890605 268504396 453157697 + -1065215606 -1740602879 1824636801 1940062923 + + -4.7275745868682861e-001 4.2362514138221741e-001 + <_> + + 0 -1 87 -799546379 -2097769968 293605405 -21571376 285294733 + 136347650 -930405536 -69420863 + + -5.5549502372741699e-001 3.3842340111732483e-001 + <_> + + 0 -1 60 -594509036 -267114166 35413 -1052598126 545325639 + -1207959408 -1073643381 682827807 + + -5.4805672168731689e-001 3.7224516272544861e-001 + <_> + + 0 -1 63 1513710022 194882313 1109000450 28010496 -601835264 + -645791614 -1041880446 1561822180 + + -5.3384119272232056e-001 3.7635508179664612e-001 + <_> + + 0 -1 125 -754581391 -246595569 -2113336948 -1855323709 + 1090531337 -931133310 950984 -3971805 + + -5.2334308624267578e-001 4.0167775750160217e-001 + <_> + + 0 -1 58 -361268680 662383988 2147483638 -209756289 + -1375932428 -1895890954 -1744855042 -1142215109 + + -3.4343415498733521e-001 6.1590969562530518e-001 + + <_> + 10 + -7.7425497770309448e-001 + + <_> + + 0 -1 66 -716447302 -602037376 1090519043 -150261760 + 342934202 -2034138749 1141152394 -351301493 + + -4.8867926001548767e-001 3.4062498807907104e-001 + <_> + + 0 -1 98 -2071985592 -700120831 1078417460 672719121 + 1082264136 -209075063 -1438988203 -1465205245 + + -7.1539443731307983e-001 2.4058867990970612e-001 + <_> + + 0 -1 74 872558624 331821072 1610649929 -1181384552 + -2130081587 -92209146 -612134248 -1199562344 + + -4.4142067432403564e-001 3.7935256958007813e-001 + <_> + + 0 -1 68 -791554721 -737771072 2425605 740044819 1208549387 + 973897998 1124108962 802102203 + + -4.6558478474617004e-001 4.2193859815597534e-001 + <_> + + 0 -1 8 1893114270 -1013792636 360523 -586362838 -1073151001 + -2146917824 -2104934391 -875596965 + + -5.0676107406616211e-001 3.5864940285682678e-001 + <_> + + 0 -1 91 574816266 -2011773950 1476495634 580227538 + -2146781128 -2147448830 1901535891 -692616573 + + -6.1020326614379883e-001 3.0061775445938110e-001 + <_> + + 0 -1 70 2125429880 2080309246 -285282561 2142961407 + -1259516274 1073741823 754945025 867497448 + + -4.3854746222496033e-001 4.7815895080566406e-001 + <_> + + 0 -1 94 -1727736509 -1979678624 285229334 1115689064 + 537927788 -1207402368 1098914016 -91503488 + + -6.8697202205657959e-001 3.5183742642402649e-001 + <_> + + 0 -1 57 -528465144 -707035113 -1048575869 1372127361 8651416 + -526909310 -1845360374 -1451016182 + + -4.5901125669479370e-001 4.5875525474548340e-001 + <_> + + 0 -1 25 -2076984798 -533130869 -1060954112 1639977472 + 828440586 1792508680 -1693988801 -13285232 + + -4.8493441939353943e-001 4.3403539061546326e-001 + + <_> + + 0 1 1 9 + <_> + + 0 1 4 7 + <_> + + 0 2 2 6 + <_> + + 0 2 2 10 + <_> + + 0 2 3 4 + <_> + + 0 3 3 8 + <_> + + 0 4 1 8 + <_> + + 0 5 2 9 + <_> + + 0 7 1 8 + <_> + + 0 7 5 7 + <_> + + 0 9 1 5 + <_> + + 0 9 2 6 + <_> + + 0 10 3 7 + <_> + + 0 11 1 3 + <_> + + 0 12 2 1 + <_> + + 0 13 3 7 + <_> + + 0 14 1 1 + <_> + + 0 14 3 4 + <_> + + 0 16 1 1 + <_> + + 0 19 3 5 + <_> + + 0 20 3 4 + <_> + + 0 21 3 4 + <_> + + 0 22 2 4 + <_> + + 0 25 3 3 + <_> + + 0 25 4 3 + <_> + + 1 0 5 10 + <_> + + 1 2 1 9 + <_> + + 1 4 4 8 + <_> + + 1 4 5 9 + <_> + + 1 6 3 5 + <_> + + 1 9 2 3 + <_> + + 1 11 2 4 + <_> + + 1 15 3 2 + <_> + + 1 20 3 3 + <_> + + 1 28 2 2 + <_> + + 2 0 2 3 + <_> + + 2 0 3 5 + <_> + + 2 0 4 8 + <_> + + 2 3 4 5 + <_> + + 2 4 5 5 + <_> + + 2 5 2 5 + <_> + + 2 7 5 9 + <_> + + 2 8 1 3 + <_> + + 2 12 1 2 + <_> + + 2 13 3 3 + <_> + + 2 14 2 2 + <_> + + 2 16 3 5 + <_> + + 2 18 3 5 + <_> + + 2 22 2 4 + <_> + + 2 31 3 1 + <_> + + 3 0 2 3 + <_> + + 3 1 3 5 + <_> + + 3 1 3 8 + <_> + + 3 2 3 6 + <_> + + 3 8 4 6 + <_> + + 3 10 2 4 + <_> + + 3 14 2 2 + <_> + + 3 16 1 1 + <_> + + 3 18 1 1 + <_> + + 3 19 1 1 + <_> + + 3 19 1 2 + <_> + + 3 31 2 1 + <_> + + 4 4 4 4 + <_> + + 4 5 2 7 + <_> + + 4 6 2 4 + <_> + + 4 6 3 4 + <_> + + 4 7 2 8 + <_> + + 4 12 3 5 + <_> + + 4 19 2 3 + <_> + + 5 0 5 7 + <_> + + 5 3 4 4 + <_> + + 5 3 5 4 + <_> + + 5 5 2 8 + <_> + + 5 12 4 4 + <_> + + 5 22 1 1 + <_> + + 6 21 3 3 + <_> + + 6 26 2 2 + <_> + + 6 30 1 1 + <_> + + 6 31 1 1 + <_> + + 6 31 2 1 + <_> + + 7 0 2 3 + <_> + + 7 9 3 7 + <_> + + 7 17 1 1 + <_> + + 7 31 1 1 + <_> + + 7 31 2 1 + <_> + + 8 0 4 1 + <_> + + 8 5 2 4 + <_> + + 8 10 3 6 + <_> + + 8 16 2 1 + <_> + + 8 25 3 2 + <_> + + 8 30 1 1 + <_> + + 9 0 1 1 + <_> + + 9 0 3 2 + <_> + + 9 0 3 4 + <_> + + 9 15 2 1 + <_> + + 9 24 3 3 + <_> + + 9 29 1 1 + <_> + + 9 31 1 1 + <_> + + 10 4 2 2 + <_> + + 10 8 1 3 + <_> + + 10 15 1 3 + <_> + + 10 26 2 1 + <_> + + 10 30 1 1 + <_> + + 10 31 3 1 + <_> + + 11 0 3 2 + <_> + + 11 1 3 4 + <_> + + 11 5 3 8 + <_> + + 11 14 1 1 + <_> + + 11 23 2 2 + <_> + + 11 27 2 2 + <_> + + 11 31 1 1 + <_> + + 12 22 2 3 + <_> + + 12 29 1 1 + <_> + + 13 23 2 1 + <_> + + 13 24 1 3 + <_> + + 13 29 1 1 + <_> + + 13 31 2 1 + <_> + + 14 1 2 2 + <_> + + 14 1 2 6 + <_> + + 14 2 2 1 + <_> + + 14 24 2 2 + <_> + + 14 26 2 2 + <_> + + 14 28 1 1 + <_> + + 15 4 1 1 + <_> + + 15 24 1 1 + <_> + + 17 0 1 3 + <_> + + 17 3 1 4 + <_> + + 17 23 1 2 + <_> + + 17 27 1 1 + diff --git a/data/lbpcascades/lbpcascade_silverware.xml b/data/lbpcascades/lbpcascade_silverware.xml new file mode 100755 index 0000000000..33aa443c24 --- /dev/null +++ b/data/lbpcascades/lbpcascade_silverware.xml @@ -0,0 +1,1279 @@ + + + + + BOOST + LBP + 80 + 12 + + GAB + 9.9500000476837158e-001 + 3.0000001192092896e-001 + 9.4999999999999996e-001 + 1 + 100 + + 256 + 1 + 16 + + + <_> + 4 + -8.2867860794067383e-002 + + <_> + + 0 -1 99 -268435521 -486543361 -258 1659633406 -134217857 + 1702887279 -134217929 -184549377 + + -7.5000000000000000e-001 8.6380833387374878e-001 + <_> + + 0 -1 39 -540541017 -1060113913 -781245688 -477121697 + -1818664155 1105186857 -505961467 -152575569 + + -7.9976779222488403e-001 7.5056612491607666e-001 + <_> + + 0 -1 101 -479208497 -353380921 -855254781 -1566689761 + -454302869 1893310787 -271591561 -134222965 + + -7.1062028408050537e-001 7.7380746603012085e-001 + <_> + + 0 -1 41 -338958865 -925383977 -1438297681 -981777969 + -882901177 1913369038 -135286729 1995959223 + + -7.8616768121719360e-001 6.9309240579605103e-001 + + <_> + 5 + -7.7058833837509155e-001 + + <_> + + 0 -1 14 -34089161 -2245 1878980471 -8687769 -134316045 + 1744797563 -8388737 1795146607 + + -6.1089491844177246e-001 7.3594772815704346e-001 + <_> + + 0 -1 32 -707274321 1896302609 1132560802 -183140351 17019099 + 830472347 -1993621429 1440074510 + + -6.4869755506515503e-001 5.6941097974777222e-001 + <_> + + 0 -1 4 -1055898237 -104492975 -1795141251 1464975384 + -1602043461 -914358144 1111543953 -2067496448 + + -6.0432785749435425e-001 5.5685383081436157e-001 + <_> + + 0 -1 96 -520160401 2063466495 -65665 -134217729 -50462805 + 1761476478 1693969709 1910503031 + + -5.6237226724624634e-001 6.2263637781143188e-001 + <_> + + 0 -1 6 -1479564374 -954482597 16859161 -799804534 268468874 + 713187329 1108033665 -714619755 + + -6.9048601388931274e-001 5.3264212608337402e-001 + + <_> + 5 + -7.1249550580978394e-001 + + <_> + + 0 -1 21 -34638473 -553976197 -134217865 -159715533 + -142901385 -272629761 -8421377 -956303361 + + -6.4170038700103760e-001 7.0683228969573975e-001 + <_> + + 0 -1 100 -8389777 -185860353 -277 -2097152001 -161 + -209780865 -1 -529006609 + + -5.5270516872406006e-001 6.9983023405075073e-001 + <_> + + 0 -1 118 -545259537 -276857217 -1258291302 1652358910 + -134236308 1735819126 -16812809 -221249673 + + -5.6243920326232910e-001 6.2150186300277710e-001 + <_> + + 0 -1 19 -342885713 -1369882213 -2079215310 -765214587 + -2113207945 1074365452 1393631959 1409022707 + + -6.8943935632705688e-001 5.3469669818878174e-001 + <_> + + 0 -1 23 -506991005 1360417115 -1844809365 -821575604 + 21178499 986120459 1347943419 -969541850 + + -6.7428857088088989e-001 5.5008578300476074e-001 + + <_> + 6 + -3.0183684825897217e-001 + + <_> + + 0 -1 31 -144703505 -143130625 -17 -134381841 -143130625 + 2012741567 -134218802 -134217841 + + -5.3079712390899658e-001 7.5616836547851563e-001 + <_> + + 0 -1 35 -137887809 -1924805943 1363218446 -817782134 + 1099022547 1082327168 -1279204784 1128784467 + + -6.4090979099273682e-001 5.3444361686706543e-001 + <_> + + 0 -1 15 -786433589 -515129128 277173650 -132673121 + -884037451 1137229866 1938662135 -676336865 + + -5.2920126914978027e-001 5.9623366594314575e-001 + <_> + + 0 -1 92 -1897400451 -1627924747 -335548553 -1 1257762559 + -2113929417 -419433067 -235309193 + + -5.5294114351272583e-001 5.8814722299575806e-001 + <_> + + 0 -1 112 -187176146 1743897116 -1878957040 542033563 + 1372582934 823282242 -158609727 -779295046 + + -6.8665105104446411e-001 4.4378995895385742e-001 + <_> + + 0 -1 9 1676637640 1887961346 16875658 1977614736 1682145753 + 813744265 -842338550 1930548135 + + -7.5830078125000000e-001 3.9562159776687622e-001 + + <_> + 8 + -3.9228534698486328e-001 + + <_> + + 0 -1 25 -167774345 -6689161 -2097153 -4194541 -282329093 -1 + -1 -352323601 + + -4.7727271914482117e-001 7.4114018678665161e-001 + <_> + + 0 -1 2 -1051598753 -1005571964 1900827102 2065404120 + -1207262247 -120553331 -1725955392 -494812414 + + -5.2365595102310181e-001 5.3981113433837891e-001 + <_> + + 0 -1 116 -2142770433 -1601462143 16842760 -804892128 1032369 + 268763273 1091011104 -1142957585 + + -4.7790464758872986e-001 5.4881525039672852e-001 + <_> + + 0 -1 87 -532155537 1351188929 1073823759 -1253637875 + -721321497 -662691837 -955278809 1623500836 + + -6.8072116374969482e-001 3.7135115265846252e-001 + <_> + + 0 -1 113 -1996457508 -2146282492 -1728016135 -578347007 + -1609004859 193626505 1153570968 -1920333632 + + -5.7289212942123413e-001 4.6210876107215881e-001 + <_> + + 0 -1 56 -972008109 -691003372 -2147413749 2098355010 + 143009971 -1744174583 -1073051430 617488921 + + -5.9549087285995483e-001 4.8842963576316833e-001 + <_> + + 0 -1 48 26 1971388449 419479901 2080931848 -1140292918 + -1719074813 -2130476842 -268398592 + + -5.8355164527893066e-001 4.7890499234199524e-001 + <_> + + 0 -1 57 -1052266874 167813132 -2130690045 -703061621 + -131874777 -662142838 -1064730555 1119947703 + + -6.9379311800003052e-001 3.9936643838882446e-001 + + <_> + 9 + -6.6581231355667114e-001 + + <_> + + 0 -1 29 2080314175 -112910205 805323551 1024016674 + 1073891387 -2137847805 1653140111 -7676933 + + -5.5957448482513428e-001 5.4044550657272339e-001 + <_> + + 0 -1 94 -1358956801 -100880986 -1887436809 1073741823 + -1896350220 -838860811 268434686 -1912602633 + + -4.3124794960021973e-001 5.6135851144790649e-001 + <_> + + 0 -1 76 -26230993 1357905647 -1358958674 -135266305 -524434 + -176291841 -142622837 -1005125829 + + -4.6799373626708984e-001 5.1660954952239990e-001 + <_> + + 0 -1 30 -313836176 -742240245 16818511 -1391787262 + 1632363443 -156630911 -83631445 248984215 + + -6.2023061513900757e-001 3.9792594313621521e-001 + <_> + + 0 -1 91 -612895966 591778561 1073812490 369347088 + -1870223303 556335107 553910792 1907094058 + + -6.2148678302764893e-001 4.1758581995964050e-001 + <_> + + 0 -1 46 -1430257749 -672663689 -218104082 -135266322 + -1493174275 -873463809 -276826113 -690006715 + + -5.1617449522018433e-001 5.2012032270431519e-001 + <_> + + 0 -1 123 1088746207 1489289603 16781456 -443461355 + -762795606 -670564192 -1465814774 -101527550 + + -5.0202989578247070e-001 5.0987190008163452e-001 + <_> + + 0 -1 53 -1001679641 -955695103 25248080 -738078457 671123502 + 193003713 -1836523327 -216026117 + + -5.2692401409149170e-001 5.3243070840835571e-001 + <_> + + 0 -1 89 2147417937 -1048642 -1039 -1766457361 -134236382 + -1922646177 -16777473 -1534591162 + + -4.6150138974189758e-001 5.6634509563446045e-001 + + <_> + 8 + -1.2349532842636108e+000 + + <_> + + 0 -1 67 -142902409 -67142273 1878982639 -1182802113 -75841 + -274219146 -88604929 -31817921 + + -4.5625588297843933e-001 5.7534247636795044e-001 + <_> + + 0 -1 128 -808330661 1390004234 1107406871 -2098932967 + -767440829 1208655939 -1971196977 1351600587 + + -5.7236993312835693e-001 4.1942635178565979e-001 + <_> + + 0 -1 0 -805307409 -1052697 -65684 -4233 -134217745 -4194453 + -696778831 -708062879 + + -4.5485407114028931e-001 5.5909335613250732e-001 + <_> + + 0 -1 119 -169888509 1150652435 1074791064 541757442 + -645182635 989929472 1262741126 1963976639 + + -6.4869618415832520e-001 3.9796143770217896e-001 + <_> + + 0 -1 38 -912524801 811171970 33644801 -717151469 -2108956437 + 294158344 1109713681 1900266000 + + -5.0387507677078247e-001 5.1329559087753296e-001 + <_> + + 0 -1 20 -746687625 -200802301 1073872962 285491202 + 1208512717 -2138664446 -1837102693 1174835902 + + -5.9465301036834717e-001 4.4057011604309082e-001 + <_> + + 0 -1 16 -442903927 -988184502 -717209211 1443168395 + -1465793521 1252524168 1107337938 -1050414557 + + -5.9043467044830322e-001 4.3687704205513000e-001 + <_> + + 0 -1 104 -1692667790 -612286452 -1056931520 437452806 + -2136309078 -401536992 -1987928929 -1033981310 + + -5.0495445728302002e-001 4.9910807609558105e-001 + + <_> + 9 + -5.4583048820495605e-001 + + <_> + + 0 -1 97 -419954689 -570949699 2147417599 -1 -872415749 + -301989897 -872433670 -268443689 + + -4.0734556317329407e-001 7.1092438697814941e-001 + <_> + + 0 -1 3 -1062674253 1929486475 197402 1841550219 135268235 + -1165491808 956369290 1258896162 + + -5.4886269569396973e-001 4.1644170880317688e-001 + <_> + + 0 -1 37 -620271105 -901300206 1359008346 -603537150 + 1355455189 596312193 -247999129 -728767550 + + -5.1914668083190918e-001 3.9419922232627869e-001 + <_> + + 0 -1 17 -1072700149 546031429 12798103 1881656595 35238042 + 682232321 176931799 1148695251 + + -5.4100900888442993e-001 4.0588796138763428e-001 + <_> + + 0 -1 71 -522857685 1350893957 17339597 1999601732 -779974469 + -359071607 1879296642 -1236927697 + + -4.9249285459518433e-001 4.4877073168754578e-001 + <_> + + 0 -1 93 2037497904 492944831 -2013291075 -754983169 + 1837104414 -671812233 -1660989976 -973105033 + + -4.6483671665191650e-001 4.8267844319343567e-001 + <_> + + 0 -1 33 -553943182 -100663369 -1327169 -181207174 -805896236 + -16777225 -32770 -344459717 + + -3.9679497480392456e-001 5.6408804655075073e-001 + <_> + + 0 -1 44 -8439301 -9502850 2147412095 2134171367 1467968283 + -555876513 1719612907 -959121 + + -3.7275579571723938e-001 6.2219065427780151e-001 + <_> + + 0 -1 62 -2086686357 -2143072184 1073745988 -1878839231 + 1221503177 -2113732606 1133091218 1470880455 + + -5.5160778760910034e-001 4.4197219610214233e-001 + + <_> + 8 + -4.9482953548431396e-001 + + <_> + + 0 -1 124 803987455 -1207959557 -1073747969 -3 -1879048193 + -1720221705 -1073744641 -1212159499 + + -4.2883211374282837e-001 5.8106172084808350e-001 + <_> + + 0 -1 1 -1520569905 -125497088 1360134399 -49444069 + -1065189105 -612134877 -1497194288 -1006112575 + + -4.8296096920967102e-001 4.3431344628334045e-001 + <_> + + 0 -1 108 -67112229 -797503462 268623881 1083056391 + -1874187198 1879638016 -804355463 1985162053 + + -6.1597704887390137e-001 3.4508374333381653e-001 + <_> + + 0 -1 26 -686760009 1468434576 1140918535 -880733942 12599987 + -1304752000 -1593784081 115557220 + + -5.7973521947860718e-001 4.0324980020523071e-001 + <_> + + 0 -1 115 -753405796 4259842 -872415136 85172613 154534824 + 8454145 -2147292968 1094185899 + + -4.7171372175216675e-001 4.6018373966217041e-001 + <_> + + 0 -1 64 -737160572 2107229470 1478238399 386729999 46739708 + -1717532540 134302191 1502456202 + + -4.7625115513801575e-001 4.6307522058486938e-001 + <_> + + 0 -1 63 574973114 1079378118 151608 -1089433600 683881170 + 1234370560 25761968 1305471639 + + -5.4804503917694092e-001 4.2817059159278870e-001 + <_> + + 0 -1 126 -913048353 -1333444591 303141015 1107341569 + -1727960821 1644167297 -1190753878 1418524891 + + -6.3843786716461182e-001 3.2018747925758362e-001 + + <_> + 10 + -4.7552201151847839e-001 + + <_> + + 0 -1 54 -17825929 -8718489 -34111631 -135004289 -1358954497 + -16814213 -151556225 -285220369 + + -4.1965106129646301e-001 5.5681818723678589e-001 + <_> + + 0 -1 88 -1856526326 -645691871 337711324 1464176998 + -1602581814 -1710751608 168420078 -1341468062 + + -4.0517404675483704e-001 4.9981650710105896e-001 + <_> + + 0 -1 45 -741223945 -1627185101 822169913 407916675 + -897447857 589300224 540099855 -1156899883 + + -4.4794428348541260e-001 4.3524059653282166e-001 + <_> + + 0 -1 66 258608606 -1120993285 -419517441 -578240642 + -1879056401 -1101037569 -13383 -28301584 + + -3.9371734857559204e-001 5.2872020006179810e-001 + <_> + + 0 -1 117 -350280689 -829730738 -1073461695 38377489 + -645158785 839057410 -1249137694 1882566387 + + -5.7474929094314575e-001 3.8859930634498596e-001 + <_> + + 0 -1 34 1536523031 -952168281 -1855975139 -854621937 + -939095838 -1744699368 -796270511 1582955555 + + -5.4318642616271973e-001 4.1631007194519043e-001 + <_> + + 0 -1 51 1393782562 319525363 8471383 1368384004 889651722 + 1921550554 -1836930098 1660195204 + + -7.2387772798538208e-001 2.8236424922943115e-001 + <_> + + 0 -1 78 1675075922 637567168 -2130116204 -1890844654 + 34255055 167907336 1091555477 -2142773065 + + -5.3113341331481934e-001 3.7920853495597839e-001 + <_> + + 0 -1 7 1164149387 1433912608 16876979 1595080980 1275865262 + -1446313974 1241665562 173580528 + + -5.0643980503082275e-001 4.4159597158432007e-001 + <_> + + 0 -1 129 -111949961 -783789413 268583504 -923765997 + -1073657336 -1340440574 -394149886 1216081042 + + -5.0880813598632813e-001 4.1170257329940796e-001 + + <_> + 11 + -6.9445723295211792e-001 + + <_> + + 0 -1 106 -487588613 -118095873 -1 2109472735 -1258291202 + -101712129 -33832963 -67652237 + + -4.0311419963836670e-001 6.2951332330703735e-001 + <_> + + 0 -1 49 -268435473 -353372166 2138045906 -4121 -276824105 + 1317007308 -41945099 -134484017 + + -3.5493713617324829e-001 5.5815106630325317e-001 + <_> + + 0 -1 5 1460877355 -15613689 558207061 -1623109371 + -1926723379 244908044 -113047169 1414649856 + + -5.8201593160629272e-001 3.5618588328361511e-001 + <_> + + 0 -1 103 -669296387 189940185 -1860046723 -1760460773 + -1740078915 -931100536 276828352 -1917868015 + + -4.2647001147270203e-001 4.6035429835319519e-001 + <_> + + 0 -1 107 -2109233498 -602287230 -1054785005 1360101827 + 1099137177 -318504822 -1341497202 232232049 + + -4.9850422143936157e-001 4.4256457686424255e-001 + <_> + + 0 -1 40 -54286241 -1608934766 286327519 -1270398764 + 1267376258 1636335746 542720627 1966594122 + + -5.5573022365570068e-001 3.9825862646102905e-001 + <_> + + 0 -1 18 -904213325 1133543618 67508251 -714997735 1094779186 + 160088201 872654991 -903019733 + + -5.2738076448440552e-001 3.8662704825401306e-001 + <_> + + 0 -1 70 1275766299 1347454976 150995380 -217382907 + 1661501627 -788494333 1259046051 -1006600122 + + -4.6260216832160950e-001 4.6852749586105347e-001 + <_> + + 0 -1 121 -367803633 420562962 36765796 -502050533 1380984391 + 268601345 536897573 -995624251 + + -5.2821987867355347e-001 4.4226339459419250e-001 + <_> + + 0 -1 68 -470086117 1069514507 -268472471 1936420849 + -1904232854 1475346303 -160432647 -258802070 + + -4.5063796639442444e-001 5.2728754281997681e-001 + <_> + + 0 -1 85 -698610339 -1504477166 1267372697 822280328 + -909606742 -561903583 -1658732533 962675013 + + -5.5067950487136841e-001 3.9346820116043091e-001 + + <_> + 9 + -7.5511032342910767e-001 + + <_> + + 0 -1 27 -485801045 -1031585761 285212749 -1013038975 + 427848842 -1006632832 -1039468406 -162905189 + + -4.8945146799087524e-001 4.7218933701515198e-001 + <_> + + 0 -1 114 -962887670 1547862275 -1827077881 1140871689 + -536829941 -763363328 -264142181 1112595267 + + -6.1379230022430420e-001 3.4447920322418213e-001 + <_> + + 0 -1 111 -784109321 320069633 1073811463 1074292770 + -2138957664 -2130001880 -2147252214 315289683 + + -5.6861025094985962e-001 3.7049382925033569e-001 + <_> + + 0 -1 80 -679857295 -17928596 -328961 991442748 1064728144 + -357040523 -1082493190 -1368229638 + + -3.9095887541770935e-001 6.0248941183090210e-001 + <_> + + 0 -1 82 175736687 -17072405 2130705262 -218107907 + -1358978530 1692925804 787824558 -672137257 + + -4.0445902943611145e-001 6.0857713222503662e-001 + <_> + + 0 -1 47 -985116365 -553647839 420626839 1968635918 + -1576924981 -360119808 142606465 -795508656 + + -4.8094493150711060e-001 5.1770961284637451e-001 + <_> + + 0 -1 50 -1459109750 33792144 21514342 1343230978 1124110539 + 50364672 441024643 -202393597 + + -5.2261912822723389e-001 4.6680617332458496e-001 + <_> + + 0 -1 98 -259008926 1378975745 -1476362162 1888485505 + 1082744897 571146241 1367392642 -1073229683 + + -6.1712646484375000e-001 3.8970091938972473e-001 + <_> + + 0 -1 125 34318799 1090695442 25199491 1342177299 -2060943181 + 143360000 -2097010032 -907873592 + + -5.3400212526321411e-001 4.4268184900283813e-001 + + <_> + 10 + -4.8388049006462097e-001 + + <_> + + 0 -1 120 -1477443585 -1140940929 -1342185476 1308588029 + -1376256001 218070525 1073741181 -41951875 + + -5.0602412223815918e-001 5.5081558227539063e-001 + <_> + + 0 -1 36 -73936261 -2137816955 -1073659749 -553533419 + -1073706765 -30799693 -972443088 1998113303 + + -4.8420175909996033e-001 4.5527526736259460e-001 + <_> + + 0 -1 77 454566983 420696071 16777221 -2130608117 -1719576352 + -644874174 -2111166071 577795078 + + -6.1467814445495605e-001 3.4610831737518311e-001 + <_> + + 0 -1 60 -1592753970 -251404269 570458176 486621571 + -2130476982 -1207431030 25803086 -2029039551 + + -5.2004736661911011e-001 4.5498979091644287e-001 + <_> + + 0 -1 72 694105913 1907355278 -37129 821280759 931135417 + -923336907 1073716718 -68419540 + + -4.1492795944213867e-001 5.7309722900390625e-001 + <_> + + 0 -1 79 1393265851 -1032732526 264196 -920530793 754211 + 169623560 1149456611 1135983235 + + -5.1638025045394897e-001 4.7242832183837891e-001 + <_> + + 0 -1 73 706130001 -1708251305 1056944760 1006373626 + -1303178409 -813991949 -1183128387 -604048669 + + -4.1649991273880005e-001 5.9589266777038574e-001 + <_> + + 0 -1 95 -904859491 -134017015 1090589192 -587038719 + -167673709 -897449815 152141841 886696449 + + -6.4827072620391846e-001 3.5843926668167114e-001 + <_> + + 0 -1 90 -717057392 690163912 822149263 65803 -1706982525 + -1736400884 534537 -1630082545 + + -5.0309199094772339e-001 5.1634097099304199e-001 + <_> + + 0 -1 12 -1366843350 -2126376671 1041 -566034432 142770176 + 12583104 51712 1116198165 + + -7.9860860109329224e-001 3.1541401147842407e-001 + + <_> + 10 + -5.6616169214248657e-001 + + <_> + + 0 -1 28 -143395977 2004844407 -32897 1840447419 -852257 + -4097 -272630497 -1165502065 + + -4.4186046719551086e-001 5.1379764080047607e-001 + <_> + + 0 -1 8 -519577109 -427718635 -1862262703 -65943231 9163380 + 1112064264 553714225 1157599521 + + -6.9529622793197632e-001 2.9373377561569214e-001 + <_> + + 0 -1 109 990036221 -1392408495 85 -1455423472 537079956 + -1451032448 -2121658180 -1917118335 + + -4.6548900008201599e-001 4.4904062151908875e-001 + <_> + + 0 -1 83 -307263958 1726969598 602799716 -587284627 + -2110304757 -1500547078 1400237979 -194002951 + + -4.4492045044898987e-001 5.2867370843887329e-001 + <_> + + 0 -1 84 -696132137 331497536 -1868546039 -1859480056 + 1753940107 -1029504896 -1341584891 937520647 + + -4.9129620194435120e-001 4.4696673750877380e-001 + <_> + + 0 -1 61 -1056718371 -912911872 67113021 1498447874 134777514 + -1412955989 -2138406733 1082270464 + + -5.8106380701065063e-001 4.1291686892509460e-001 + <_> + + 0 -1 43 -648808770 -703963135 -2147401712 -1858043831 + 1073823883 1074266248 159924795 1879588907 + + -5.2166140079498291e-001 4.6159252524375916e-001 + <_> + + 0 -1 65 538123210 285607041 -2122121208 -1651965941 + -1047953261 1661077920 591915 1689841382 + + -7.4180144071578979e-001 3.0022916197776794e-001 + <_> + + 0 -1 55 805390529 407044123 285213203 211421255 -1702852378 + -1919942528 -2134294375 2066729839 + + -4.8658525943756104e-001 5.4231238365173340e-001 + <_> + + 0 -1 69 -490280822 -1274937328 268439820 1359003776 + -931126870 1220674050 268681287 1997226373 + + -5.6268626451492310e-001 4.5061412453651428e-001 + + <_> + 10 + -9.9649858474731445e-001 + + <_> + + 0 -1 122 -1745100805 -1209164803 -1073770531 -436207891 + -1090560009 234354687 -1610664449 -1082138881 + + -4.0143370628356934e-001 5.6573116779327393e-001 + <_> + + 0 -1 11 -644493203 -1021149047 16847288 -804977263 + 1074438223 1375879170 1099505907 -233072125 + + -4.9022576212882996e-001 4.1356840729713440e-001 + <_> + + 0 -1 110 -1092637138 -1127253650 -604013462 309325799 + 511047567 -562074754 -700452946 -763371997 + + -4.2038223147392273e-001 5.0647193193435669e-001 + <_> + + 0 -1 24 1223739637 -1419051417 1043595135 -215335105 + 376670206 -167870465 -4194306 -222771398 + + -4.0432786941528320e-001 5.9335744380950928e-001 + <_> + + 0 -1 75 -1761937577 -1076383745 -286361737 -9060559 + 2013197781 2013265783 -98370 -1002109842 + + -4.4517979025840759e-001 5.2503407001495361e-001 + <_> + + 0 -1 102 1359075611 -233766656 65681 -1878048735 -1610570746 + 1379991688 -1073689784 -221669373 + + -4.9918147921562195e-001 4.6203434467315674e-001 + <_> + + 0 -1 52 1186053495 -36241670 -268451888 519745529 175382495 + 788381687 2147319804 1327036346 + + -4.6265572309494019e-001 5.1841813325881958e-001 + <_> + + 0 -1 59 -1040035797 1946189894 50247 -1862266624 1090519113 + 268961800 679544907 757613389 + + -5.5006593465805054e-001 4.4656375050544739e-001 + <_> + + 0 -1 10 1610993732 -939524096 1073877397 -267910919 + 151167146 537427968 -769096510 -181428117 + + -5.6329357624053955e-001 4.2267900705337524e-001 + <_> + + 0 -1 86 -1596021624 2047393801 -2130673584 -1856700352 + 327207619 272728192 -2004808112 491069440 + + -6.3942277431488037e-001 3.8081073760986328e-001 + + <_> + 8 + -5.5261385440826416e-001 + + <_> + + 0 -1 13 -648185009 -1315897313 -2139077632 1367998985 + 1744840211 -1005502457 -935198613 -74777841 + + -5.3191488981246948e-001 4.0654698014259338e-001 + <_> + + 0 -1 105 1699432742 -1890377581 1343232064 -1039957887 + -2142687167 637566976 -2122282989 -460871217 + + -5.4315727949142456e-001 3.6683899164199829e-001 + <_> + + 0 -1 81 -67160267 2105388843 -1619001345 1937768302 + -1359003974 -1098989786 -805322771 -1874678652 + + -3.9974156022071838e-001 5.5645257234573364e-001 + <_> + + 0 -1 58 -1072656189 1095241792 16777487 -352059374 4718723 + 1109393544 1074438486 -1848987381 + + -5.0869542360305786e-001 4.9633875489234924e-001 + <_> + + 0 -1 22 226493774 -1911816127 1091108968 26214662 26222970 + -1123287032 -1987040599 -882898875 + + -6.0312920808792114e-001 3.5752627253532410e-001 + <_> + + 0 -1 127 -259153461 -805273578 50364730 -1060208632 + -1708161014 947912705 -2147450710 80388754 + + -6.9576680660247803e-001 3.3376914262771606e-001 + <_> + + 0 -1 42 -800800303 1368954882 75795 2031108096 -2013069281 + 212336778 538680 2064105488 + + -5.6596046686172485e-001 4.3809539079666138e-001 + <_> + + 0 -1 74 -2108215089 1260109955 -1207926768 268812673 + -2146893693 167788680 55189712 -140564306 + + -5.1393473148345947e-001 4.8148322105407715e-001 + + <_> + + 0 0 1 2 + <_> + + 0 0 1 3 + <_> + + 0 0 2 1 + <_> + + 0 0 2 11 + <_> + + 0 0 3 1 + <_> + + 0 0 4 4 + <_> + + 0 1 1 3 + <_> + + 0 1 3 5 + <_> + + 0 2 1 2 + <_> + + 0 2 4 17 + <_> + + 0 3 1 1 + <_> + + 0 4 1 1 + <_> + + 0 4 1 4 + <_> + + 0 4 1 18 + <_> + + 0 4 2 21 + <_> + + 0 5 1 1 + <_> + + 0 5 1 2 + <_> + + 0 5 1 4 + <_> + + 0 5 2 11 + <_> + + 0 6 1 2 + <_> + + 0 7 1 15 + <_> + + 0 7 2 18 + <_> + + 0 13 3 3 + <_> + + 0 13 3 19 + <_> + + 0 14 2 5 + <_> + + 0 14 2 14 + <_> + + 0 16 3 17 + <_> + + 0 17 1 6 + <_> + + 0 17 2 9 + <_> + + 0 18 1 6 + <_> + + 0 19 2 17 + <_> + + 0 21 4 13 + <_> + + 0 21 4 16 + <_> + + 0 22 2 8 + <_> + + 0 36 1 5 + <_> + + 0 40 2 12 + <_> + + 0 43 1 7 + <_> + + 0 46 2 10 + <_> + + 0 48 1 9 + <_> + + 0 48 2 4 + <_> + + 0 50 1 2 + <_> + + 0 56 2 3 + <_> + + 0 71 1 3 + <_> + + 0 74 1 2 + <_> + + 0 77 1 1 + <_> + + 0 77 2 1 + <_> + + 1 0 1 3 + <_> + + 1 0 2 1 + <_> + + 1 0 3 1 + <_> + + 1 2 1 1 + <_> + + 1 4 1 2 + <_> + + 1 4 3 23 + <_> + + 1 5 2 7 + <_> + + 1 9 1 1 + <_> + + 1 10 2 15 + <_> + + 1 12 2 7 + <_> + + 1 14 2 9 + <_> + + 1 25 2 18 + <_> + + 1 39 2 10 + <_> + + 1 71 1 3 + <_> + + 2 0 1 3 + <_> + + 2 0 2 1 + <_> + + 2 3 1 2 + <_> + + 2 4 1 5 + <_> + + 2 16 3 8 + <_> + + 2 18 3 14 + <_> + + 2 21 2 2 + <_> + + 2 22 1 4 + <_> + + 2 24 1 2 + <_> + + 2 64 1 5 + <_> + + 3 0 2 1 + <_> + + 3 1 3 25 + <_> + + 3 2 3 6 + <_> + + 3 3 2 11 + <_> + + 3 6 1 3 + <_> + + 3 17 1 11 + <_> + + 3 22 3 17 + <_> + + 3 23 1 4 + <_> + + 3 42 1 10 + <_> + + 3 52 1 6 + <_> + + 3 77 1 1 + <_> + + 4 0 2 2 + <_> + + 4 1 1 2 + <_> + + 4 2 1 1 + <_> + + 5 7 2 20 + <_> + + 5 12 2 19 + <_> + + 5 14 1 3 + <_> + + 5 19 2 15 + <_> + + 6 0 1 1 + <_> + + 6 0 2 1 + <_> + + 6 1 2 13 + <_> + + 6 5 2 5 + <_> + + 6 7 2 17 + <_> + + 6 10 2 7 + <_> + + 6 13 2 10 + <_> + + 6 14 2 13 + <_> + + 6 16 2 14 + <_> + + 6 19 2 7 + <_> + + 6 36 1 8 + <_> + + 6 39 2 7 + <_> + + 6 41 2 9 + <_> + + 6 44 2 2 + <_> + + 6 51 2 6 + <_> + + 6 77 2 1 + <_> + + 7 0 1 1 + <_> + + 7 9 1 2 + <_> + + 7 20 1 9 + <_> + + 7 23 1 4 + <_> + + 7 45 1 7 + <_> + + 7 77 1 1 + <_> + + 8 0 1 1 + <_> + + 8 47 1 11 + <_> + + 8 53 1 4 + <_> + + 8 77 1 1 + <_> + + 9 0 1 2 + <_> + + 9 0 1 15 + <_> + + 9 0 1 20 + <_> + + 9 2 1 3 + <_> + + 9 3 1 2 + <_> + + 9 6 1 3 + <_> + + 9 9 1 13 + <_> + + 9 13 1 2 + <_> + + 9 13 1 8 + <_> + + 9 19 1 16 + <_> + + 9 20 1 4 + <_> + + 9 25 1 4 + <_> + + 9 43 1 5 + <_> + + 9 48 1 4 + <_> + + 9 59 1 3 + <_> + + 9 61 1 5 + diff --git a/samples/c/facedetect.cpp b/samples/c/facedetect.cpp index a641a74a8a..69b9e9983a 100644 --- a/samples/c/facedetect.cpp +++ b/samples/c/facedetect.cpp @@ -3,6 +3,7 @@ #include "opencv2/imgproc/imgproc.hpp" #include +#include #include using namespace std; @@ -11,36 +12,41 @@ using namespace cv; static void help() { cout << "\nThis program demonstrates the cascade recognizer. Now you can use Haar or LBP features.\n" - "This classifier can recognize many ~rigid objects, it's most known use is for faces.\n" + "This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n" + "It's most known use is for faces.\n" "Usage:\n" "./facedetect [--cascade= this is the primary trained classifier such as frontal face]\n" " [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n" - " [--scale=\n" + " [--scale=]\n" + " [--try-flip]\n" " [filename|camera_index]\n\n" "see facedetect.cmd for one call:\n" - "./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye.xml\" --scale=1.3 \n" - "Hit any key to quit.\n" - "Using OpenCV version " << CV_VERSION << "\n" << endl; + "./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye.xml\" --scale=1.3\n\n" + "During execution:\n\tHit any key to quit.\n" + "\tUsing OpenCV version " << CV_VERSION << "\n" << endl; } -void detectAndDraw( Mat& img, - CascadeClassifier& cascade, CascadeClassifier& nestedCascade, - double scale); +void detectAndDraw( Mat& img, CascadeClassifier& cascade, + CascadeClassifier& nestedCascade, + double scale, bool tryflip ); -String cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml"; -String nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml"; +string cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml"; +string nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml"; int main( int argc, const char** argv ) { CvCapture* capture = 0; Mat frame, frameCopy, image; - const String scaleOpt = "--scale="; + const string scaleOpt = "--scale="; size_t scaleOptLen = scaleOpt.length(); - const String cascadeOpt = "--cascade="; + const string cascadeOpt = "--cascade="; size_t cascadeOptLen = cascadeOpt.length(); - const String nestedCascadeOpt = "--nested-cascade"; + const string nestedCascadeOpt = "--nested-cascade"; size_t nestedCascadeOptLen = nestedCascadeOpt.length(); - String inputName; + const string tryFlipOpt = "--try-flip"; + size_t tryFlipOptLen = tryFlipOpt.length(); + string inputName; + bool tryflip = false; help(); @@ -68,6 +74,11 @@ int main( int argc, const char** argv ) scale = 1; cout << " from which we read scale = " << scale << endl; } + else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 ) + { + tryflip = true; + cout << " will try to flip image horizontally to detect assymetric objects\n"; + } else if( argv[i][0] == '-' ) { cerr << "WARNING: Unknown option %s" << argv[i] << endl; @@ -79,10 +90,7 @@ int main( int argc, const char** argv ) if( !cascade.load( cascadeName ) ) { cerr << "ERROR: Could not load classifier cascade" << endl; - cerr << "Usage: facedetect [--cascade=]\n" - " [--nested-cascade[=nested_cascade_path]]\n" - " [--scale[=\n" - " [filename|camera_index]\n" << endl ; + help(); return -1; } @@ -123,7 +131,7 @@ int main( int argc, const char** argv ) else flip( frame, frameCopy, 0 ); - detectAndDraw( frameCopy, cascade, nestedCascade, scale ); + detectAndDraw( frameCopy, cascade, nestedCascade, scale, tryflip ); if( waitKey( 10 ) >= 0 ) goto _cleanup_; @@ -139,7 +147,7 @@ _cleanup_: cout << "In image read" << endl; if( !image.empty() ) { - detectAndDraw( image, cascade, nestedCascade, scale ); + detectAndDraw( image, cascade, nestedCascade, scale, tryflip ); waitKey(0); } else if( !inputName.empty() ) @@ -160,7 +168,7 @@ _cleanup_: image = imread( buf, 1 ); if( !image.empty() ) { - detectAndDraw( image, cascade, nestedCascade, scale ); + detectAndDraw( image, cascade, nestedCascade, scale, tryflip ); c = waitKey(0); if( c == 27 || c == 'q' || c == 'Q' ) break; @@ -180,13 +188,13 @@ _cleanup_: return 0; } -void detectAndDraw( Mat& img, - CascadeClassifier& cascade, CascadeClassifier& nestedCascade, - double scale) +void detectAndDraw( Mat& img, CascadeClassifier& cascade, + CascadeClassifier& nestedCascade, + double scale, bool tryflip ) { int i = 0; double t = 0; - vector faces; + vector faces, faces2; const static Scalar colors[] = { CV_RGB(0,0,255), CV_RGB(0,128,255), CV_RGB(0,255,255), @@ -209,6 +217,21 @@ void detectAndDraw( Mat& img, |CV_HAAR_SCALE_IMAGE , Size(30, 30) ); + if( tryflip ) + { + flip(smallImg, smallImg, 1); + cascade.detectMultiScale( smallImg, faces2, + 1.1, 2, 0 + //|CV_HAAR_FIND_BIGGEST_OBJECT + //|CV_HAAR_DO_ROUGH_SEARCH + |CV_HAAR_SCALE_IMAGE + , + Size(30, 30) ); + for( vector::const_iterator r = faces2.begin(); r != faces2.end(); r++ ) + { + faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height)); + } + } t = (double)cvGetTickCount() - t; printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) ); for( vector::const_iterator r = faces.begin(); r != faces.end(); r++, i++ ) @@ -218,10 +241,19 @@ void detectAndDraw( Mat& img, Point center; Scalar color = colors[i%8]; int radius; - center.x = cvRound((r->x + r->width*0.5)*scale); - center.y = cvRound((r->y + r->height*0.5)*scale); - radius = cvRound((r->width + r->height)*0.25*scale); - circle( img, center, radius, color, 3, 8, 0 ); + + double aspect_ratio = (double)r->width/r->height; + if( 0.75 < aspect_ratio && aspect_ratio < 1.3 ) + { + center.x = cvRound((r->x + r->width*0.5)*scale); + center.y = cvRound((r->y + r->height*0.5)*scale); + radius = cvRound((r->width + r->height)*0.25*scale); + circle( img, center, radius, color, 3, 8, 0 ); + } + else + rectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)), + cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)), + color, 3, 8, 0); if( nestedCascade.empty() ) continue; smallImgROI = smallImg(*r); From d9185ec21b42198b55b97bef119a9621da34258a Mon Sep 17 00:00:00 2001 From: Alexander Mordvintesv Date: Wed, 22 Aug 2012 16:42:19 +0300 Subject: [PATCH 055/163] added _doc.py -- doc-string ckecking utility added some sample description --- samples/python2/_coverage.py | 37 ++++++++++++++++++++--------------- samples/python2/_doc.py | 14 +++++++++++++ samples/python2/common.py | 4 ++++ samples/python2/demo.py | 4 ++++ samples/python2/distrans.py | 17 ++++++++++------ samples/python2/floodfill.py | 14 ++++++++----- samples/python2/inpaint.py | 17 +++++++++++----- samples/python2/morphology.py | 18 +++++++++++++---- samples/python2/squares.py | 6 ++++++ 9 files changed, 95 insertions(+), 36 deletions(-) create mode 100644 samples/python2/_doc.py diff --git a/samples/python2/_coverage.py b/samples/python2/_coverage.py index e64c7c9bcb..3a365dc589 100644 --- a/samples/python2/_coverage.py +++ b/samples/python2/_coverage.py @@ -1,24 +1,29 @@ +''' +Utility for measuring python opencv API coverage by samples. +''' + from glob import glob import cv2 import re -cv2_callable = set(['cv2.'+name for name in dir(cv2) if callable( getattr(cv2, name) )]) +if __name__ == '__main__': + cv2_callable = set(['cv2.'+name for name in dir(cv2) if callable( getattr(cv2, name) )]) -found = set() -for fn in glob('*.py'): - print ' --- ', fn - code = open(fn).read() - found |= set(re.findall('cv2?\.\w+', code)) + found = set() + for fn in glob('*.py'): + print ' --- ', fn + code = open(fn).read() + found |= set(re.findall('cv2?\.\w+', code)) -cv2_used = found & cv2_callable -cv2_unused = cv2_callable - cv2_used -with open('unused_api.txt', 'w') as f: - f.write('\n'.join(sorted(cv2_unused))) + cv2_used = found & cv2_callable + cv2_unused = cv2_callable - cv2_used + with open('unused_api.txt', 'w') as f: + f.write('\n'.join(sorted(cv2_unused))) -r = 1.0 * len(cv2_used) / len(cv2_callable) -print '\ncv2 api coverage: %d / %d (%.1f%%)' % ( len(cv2_used), len(cv2_callable), r*100 ) + r = 1.0 * len(cv2_used) / len(cv2_callable) + print '\ncv2 api coverage: %d / %d (%.1f%%)' % ( len(cv2_used), len(cv2_callable), r*100 ) -print '\nold (cv) symbols:' -for s in found: - if s.startswith('cv.'): - print s + print '\nold (cv) symbols:' + for s in found: + if s.startswith('cv.'): + print s diff --git a/samples/python2/_doc.py b/samples/python2/_doc.py new file mode 100644 index 0000000000..1204ae65a5 --- /dev/null +++ b/samples/python2/_doc.py @@ -0,0 +1,14 @@ +''' +Scans current directory for *.py files and reports +ones with missing __doc__ string. +''' + +from glob import glob + +if __name__ == '__main__': + print '--- undocumented files:' + for fn in glob('*.py'): + loc = {} + execfile(fn, loc) + if '__doc__' not in loc: + print fn diff --git a/samples/python2/common.py b/samples/python2/common.py index 883aa9ae23..5415942d5a 100644 --- a/samples/python2/common.py +++ b/samples/python2/common.py @@ -1,3 +1,7 @@ +''' +This module contais some common routines used by other samples. +''' + import numpy as np import cv2 import os diff --git a/samples/python2/demo.py b/samples/python2/demo.py index 3f75703303..9dd7779e19 100644 --- a/samples/python2/demo.py +++ b/samples/python2/demo.py @@ -1,3 +1,7 @@ +''' +Sample-launcher application. +''' + import Tkinter as tk from ScrolledText import ScrolledText from glob import glob diff --git a/samples/python2/distrans.py b/samples/python2/distrans.py index 2cbca0ca20..15b1fac425 100644 --- a/samples/python2/distrans.py +++ b/samples/python2/distrans.py @@ -1,20 +1,25 @@ -import numpy as np -import cv2 -import cv2.cv as cv -from common import make_cmap +''' +Distance transform sample. -help_message = '''USAGE: distrans.py [] +Usage: + distrans.py [] Keys: ESC - exit v - toggle voronoi mode ''' + +import numpy as np +import cv2 +import cv2.cv as cv +from common import make_cmap + if __name__ == '__main__': import sys try: fn = sys.argv[1] except: fn = '../cpp/fruits.jpg' - print help_message + print __doc__ img = cv2.imread(fn, 0) cm = make_cmap('jet') diff --git a/samples/python2/floodfill.py b/samples/python2/floodfill.py index c2d0d70578..7ddc4c01df 100644 --- a/samples/python2/floodfill.py +++ b/samples/python2/floodfill.py @@ -1,9 +1,10 @@ -import numpy as np -import cv2 +''' +Floodfill sample. -help_message = '''USAGE: floodfill.py [] +Usage: + floodfill.py [] -Click on the image to set seed point + Click on the image to set seed point Keys: f - toggle floating range @@ -11,11 +12,14 @@ Keys: ESC - exit ''' +import numpy as np +import cv2 + if __name__ == '__main__': import sys try: fn = sys.argv[1] except: fn = '../cpp/fruits.jpg' - print help_message + print __doc__ img = cv2.imread(fn, True) h, w = img.shape[:2] diff --git a/samples/python2/inpaint.py b/samples/python2/inpaint.py index 6a52d01627..9ed6bab101 100644 --- a/samples/python2/inpaint.py +++ b/samples/python2/inpaint.py @@ -1,8 +1,11 @@ -import numpy as np -import cv2 -from common import Sketcher +''' +Inpainting sample. -help_message = '''USAGE: inpaint.py [] +Inpainting repairs damage to images by floodfilling +the damage with surrounding image areas. + +Usage: + inpaint.py [] Keys: SPACE - inpaint @@ -10,11 +13,15 @@ Keys: ESC - exit ''' +import numpy as np +import cv2 +from common import Sketcher + if __name__ == '__main__': import sys try: fn = sys.argv[1] except: fn = '../cpp/fruits.jpg' - print help_message + print __doc__ img = cv2.imread(fn) img_mark = img.copy() diff --git a/samples/python2/morphology.py b/samples/python2/morphology.py index b7f84fbb28..b2f6e0ebfd 100644 --- a/samples/python2/morphology.py +++ b/samples/python2/morphology.py @@ -1,8 +1,22 @@ +''' +Morphology operations. + +Usage: + morphology.py [] + +Keys: + 1 - change operation + 2 - change structure element shape + ESC - exit +''' + import numpy as np import cv2 if __name__ == '__main__': + print __doc__ + import sys from itertools import cycle from common import draw_str @@ -44,10 +58,6 @@ if __name__ == '__main__': cv2.createTrackbar('op/size', 'morphology', 12, 20, update) cv2.createTrackbar('iters', 'morphology', 1, 10, update) update() - print "Controls:" - print " 1 - change operation" - print " 2 - change structure element shape" - print while True: ch = 0xFF & cv2.waitKey() if ch == 27: diff --git a/samples/python2/squares.py b/samples/python2/squares.py index 6c6b899d83..60b04f2882 100644 --- a/samples/python2/squares.py +++ b/samples/python2/squares.py @@ -1,3 +1,9 @@ +''' +Simple "Square Detector" program. + +Loads several images sequentially and tries to find squares in each image. +''' + import numpy as np import cv2 From 6a5d996ca88387bb9f9b8ae03b6b46bb0a874df4 Mon Sep 17 00:00:00 2001 From: Leonid Beynenson Date: Wed, 22 Aug 2012 17:51:52 +0400 Subject: [PATCH 056/163] Removed the header opencv2/photo/denoising.hpp All the functions from it are moved to the header opencv2/photo/photo.hpp --- .../photo/include/opencv2/photo/denoising.hpp | 79 ------------------- modules/photo/include/opencv2/photo/photo.hpp | 20 ++++- modules/photo/src/denoising.cpp | 2 +- modules/photo/test/test_denoising.cpp | 2 +- 4 files changed, 21 insertions(+), 82 deletions(-) delete mode 100644 modules/photo/include/opencv2/photo/denoising.hpp diff --git a/modules/photo/include/opencv2/photo/denoising.hpp b/modules/photo/include/opencv2/photo/denoising.hpp deleted file mode 100644 index 718c3b73e8..0000000000 --- a/modules/photo/include/opencv2/photo/denoising.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_DENOISING_HPP__ -#define __OPENCV_DENOISING_HPP__ - -#include "opencv2/core/core.hpp" -#include "opencv2/imgproc/imgproc.hpp" -#include - -#ifdef __cplusplus - -/*! \namespace cv - Namespace where all the C++ OpenCV functionality resides - */ -namespace cv -{ - -CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, - int templateWindowSize, int searchWindowSize, int h); - -CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, - int templateWindowSize, int searchWindowSize, - int h, int hForColorComponents); - -CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, - int imgToDenoiseIndex, int temporalWindowSize, - OutputArray dst, - int templateWindowSize, int searchWindowSize, int h); - -CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, - int imgToDenoiseIndex, int temporalWindowSize, - OutputArray dst, - int templateWindowSize, int searchWindowSize, - int h, int hForColorComponents); - -} -#endif - -#endif diff --git a/modules/photo/include/opencv2/photo/photo.hpp b/modules/photo/include/opencv2/photo/photo.hpp index f771b8fbd9..bae83bbb0e 100644 --- a/modules/photo/include/opencv2/photo/photo.hpp +++ b/modules/photo/include/opencv2/photo/photo.hpp @@ -47,7 +47,6 @@ #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/photo/photo_c.h" -#include "opencv2/photo/denoising.hpp" #ifdef __cplusplus @@ -68,6 +67,25 @@ enum CV_EXPORTS_W void inpaint( InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int flags ); + +CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, + int templateWindowSize, int searchWindowSize, int h); + +CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, + int templateWindowSize, int searchWindowSize, + int h, int hForColorComponents); + +CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + OutputArray dst, + int templateWindowSize, int searchWindowSize, int h); + +CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, + int imgToDenoiseIndex, int temporalWindowSize, + OutputArray dst, + int templateWindowSize, int searchWindowSize, + int h, int hForColorComponents); + } #endif diff --git a/modules/photo/src/denoising.cpp b/modules/photo/src/denoising.cpp index 7452d0d3ce..42620575bc 100644 --- a/modules/photo/src/denoising.cpp +++ b/modules/photo/src/denoising.cpp @@ -40,7 +40,7 @@ //M*/ #include "precomp.hpp" -#include "opencv2/photo/denoising.hpp" +#include "opencv2/photo/photo.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "fast_nlmeans_denoising_invoker.hpp" #include "fast_nlmeans_multi_denoising_invoker.hpp" diff --git a/modules/photo/test/test_denoising.cpp b/modules/photo/test/test_denoising.cpp index 39aa699811..6b202f133a 100644 --- a/modules/photo/test/test_denoising.cpp +++ b/modules/photo/test/test_denoising.cpp @@ -41,7 +41,7 @@ //M*/ #include "test_precomp.hpp" -#include "opencv2/photo/denoising.hpp" +#include "opencv2/photo/photo.hpp" #include using namespace cv; From c8b7a8c80c9d290bf9264a73b344d2cea4dbd233 Mon Sep 17 00:00:00 2001 From: Alexey Spizhevoy Date: Thu, 23 Aug 2012 10:47:15 +0400 Subject: [PATCH 057/163] added median-based version of global motion estimation (videostab) --- .../opencv2/videostab/global_motion.hpp | 5 +- modules/videostab/src/global_motion.cpp | 70 ++++++++++++++++++- modules/videostab/src/precomp.hpp | 1 + 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/modules/videostab/include/opencv2/videostab/global_motion.hpp b/modules/videostab/include/opencv2/videostab/global_motion.hpp index 19fcfefaca..9616eae5c4 100644 --- a/modules/videostab/include/opencv2/videostab/global_motion.hpp +++ b/modules/videostab/include/opencv2/videostab/global_motion.hpp @@ -66,7 +66,10 @@ CV_EXPORTS Mat estimateGlobalMotionLeastSquares( InputOutputArray points0, InputOutputArray points1, int model = MM_AFFINE, float *rmse = 0); -CV_EXPORTS Mat estimateGlobalMotionRobust( +CV_EXPORTS Mat estimateGlobalMotionMedian( + InputArray points0, InputArray points1, int model, int size, int niters); + +CV_EXPORTS Mat estimateGlobalMotionRansac( InputArray points0, InputArray points1, int model = MM_AFFINE, const RansacParams ¶ms = RansacParams::default2dMotion(MM_AFFINE), float *rmse = 0, int *ninliers = 0); diff --git a/modules/videostab/src/global_motion.cpp b/modules/videostab/src/global_motion.cpp index 6a40eac8b7..1eb2f0f46b 100644 --- a/modules/videostab/src/global_motion.cpp +++ b/modules/videostab/src/global_motion.cpp @@ -305,7 +305,73 @@ Mat estimateGlobalMotionLeastSquares( } -Mat estimateGlobalMotionRobust( +Mat estimateGlobalMotionMedian( + InputArray points0, InputArray points1, int model, int size, int niters) +{ + // perform 'niters' iterations over points subsets ('size' elements each) estimating + // motions, after that select median motion parameters from the distribution + + CV_Assert(model <= MM_AFFINE); + CV_Assert(points0.type() == points1.type()); + const int npoints = points0.getMat().checkVector(2); + CV_Assert(points1.getMat().checkVector(2) == npoints); + + const Point2f *points0_ = points0.getMat().ptr(); + const Point2f *points1_ = points1.getMat().ptr(); + + // all estimated motions + vector Ms[3][3]; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + Ms[i][j].resize(niters); + + // current hypothesis + vector indices(size); + vector subset0(size); + vector subset1(size); + + RNG rng(0); + + for (int iter = 0; iter < niters; ++iter) + { + for (int i = 0; i < size; ++i) + { + bool ok = false; + while (!ok) + { + ok = true; + indices[i] = static_cast(rng) % npoints; + for (int j = 0; j < i; ++j) + if (indices[i] == indices[j]) + { ok = false; break; } + } + } + for (int i = 0; i < size; ++i) + { + subset0[i] = points0_[indices[i]]; + subset1[i] = points1_[indices[i]]; + } + + Mat_ M = estimateGlobalMotionLeastSquares(subset0, subset1, model, 0); + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + Ms[i][j][iter] = M(i, j); + } + + Mat_ medianM(3, 3); + + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + { + nth_element(Ms[i][j].begin(), Ms[i][j].begin() + niters/2, Ms[i][j].end()); + medianM(i, j) = Ms[i][j][niters/2]; + } + + return medianM; +} + + +Mat estimateGlobalMotionRansac( InputArray points0, InputArray points1, int model, const RansacParams ¶ms, float *rmse, int *ninliers) { @@ -424,7 +490,7 @@ Mat MotionEstimatorRansacL2::estimate(InputArray points0, InputArray points1, bo Mat_ M; if (motionModel() != MM_HOMOGRAPHY) - M = estimateGlobalMotionRobust( + M = estimateGlobalMotionRansac( points0, points1, motionModel(), ransacParams_, 0, &ninliers); else { diff --git a/modules/videostab/src/precomp.hpp b/modules/videostab/src/precomp.hpp index 6a1fa7c46a..848c54836a 100644 --- a/modules/videostab/src/precomp.hpp +++ b/modules/videostab/src/precomp.hpp @@ -50,6 +50,7 @@ #include #include #include +#include #include "opencv2/core/core.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/video/video.hpp" From d395bf1522163cceb59b100bab8c01d9b8be1136 Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Tue, 21 Aug 2012 13:59:27 +0400 Subject: [PATCH 058/163] minor fix in FindTBB added texture_binder --- cmake/CMakeParseArguments.cmake | 138 ++++++++++++++++++++++++ cmake/OpenCVDetectTBB.cmake | 7 +- cmake/OpenCVUtils.cmake | 9 ++ modules/core/CMakeLists.txt | 7 +- modules/gpu/src/cuda/texture_binder.hpp | 92 ++++++++++++++++ 5 files changed, 249 insertions(+), 4 deletions(-) create mode 100644 cmake/CMakeParseArguments.cmake create mode 100644 modules/gpu/src/cuda/texture_binder.hpp diff --git a/cmake/CMakeParseArguments.cmake b/cmake/CMakeParseArguments.cmake new file mode 100644 index 0000000000..7ce4c49ae5 --- /dev/null +++ b/cmake/CMakeParseArguments.cmake @@ -0,0 +1,138 @@ +# CMAKE_PARSE_ARGUMENTS( args...) +# +# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for +# parsing the arguments given to that macro or function. +# It processes the arguments and defines a set of variables which hold the +# values of the respective options. +# +# The argument contains all options for the respective macro, +# i.e. keywords which can be used when calling the macro without any value +# following, like e.g. the OPTIONAL keyword of the install() command. +# +# The argument contains all keywords for this macro +# which are followed by one value, like e.g. DESTINATION keyword of the +# install() command. +# +# The argument contains all keywords for this macro +# which can be followed by more than one value, like e.g. the TARGETS or +# FILES keywords of the install() command. +# +# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the +# keywords listed in , and +# a variable composed of the given +# followed by "_" and the name of the respective keyword. +# These variables will then hold the respective value from the argument list. +# For the keywords this will be TRUE or FALSE. +# +# All remaining arguments are collected in a variable +# _UNPARSED_ARGUMENTS, this can be checked afterwards to see whether +# your macro was called with unrecognized parameters. +# +# As an example here a my_install() macro, which takes similar arguments as the +# real install() command: +# +# function(MY_INSTALL) +# set(options OPTIONAL FAST) +# set(oneValueArgs DESTINATION RENAME) +# set(multiValueArgs TARGETS CONFIGURATIONS) +# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) +# ... +# +# Assume my_install() has been called like this: +# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) +# +# After the cmake_parse_arguments() call the macro will have set the following +# variables: +# MY_INSTALL_OPTIONAL = TRUE +# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() +# MY_INSTALL_DESTINATION = "bin" +# MY_INSTALL_RENAME = "" (was not used) +# MY_INSTALL_TARGETS = "foo;bar" +# MY_INSTALL_CONFIGURATIONS = "" (was not used) +# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" +# +# You can the continue and process these variables. +# +# Keywords terminate lists of values, e.g. if directly after a one_value_keyword +# another recognized keyword follows, this is interpreted as the beginning of +# the new option. +# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in +# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would +# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. + +#============================================================================= +# Copyright 2010 Alexander Neundorf +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) + return() +endif() +set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) + + +function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) + # first set all result variables to empty/FALSE + foreach(arg_name ${_singleArgNames} ${_multiArgNames}) + set(${prefix}_${arg_name}) + endforeach(arg_name) + + foreach(option ${_optionNames}) + set(${prefix}_${option} FALSE) + endforeach(option) + + set(${prefix}_UNPARSED_ARGUMENTS) + + set(insideValues FALSE) + set(currentArgName) + + # now iterate over all arguments and fill the result variables + foreach(currentArg ${ARGN}) + list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword + + if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) + if(insideValues) + if("${insideValues}" STREQUAL "SINGLE") + set(${prefix}_${currentArgName} ${currentArg}) + set(insideValues FALSE) + elseif("${insideValues}" STREQUAL "MULTI") + list(APPEND ${prefix}_${currentArgName} ${currentArg}) + endif() + else(insideValues) + list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) + endif(insideValues) + else() + if(NOT ${optionIndex} EQUAL -1) + set(${prefix}_${currentArg} TRUE) + set(insideValues FALSE) + elseif(NOT ${singleArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "SINGLE") + elseif(NOT ${multiArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "MULTI") + endif() + endif() + + endforeach(currentArg) + + # propagate the result variables to the caller: + foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) + set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) + endforeach(arg_name) + set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) + +endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs) diff --git a/cmake/OpenCVDetectTBB.cmake b/cmake/OpenCVDetectTBB.cmake index c37a8c34ec..3dba759f9f 100644 --- a/cmake/OpenCVDetectTBB.cmake +++ b/cmake/OpenCVDetectTBB.cmake @@ -21,7 +21,12 @@ elseif(UNIX AND NOT APPLE) endif() if(NOT HAVE_TBB) - set(TBB_DEFAULT_INCLUDE_DIRS "/opt/intel/tbb" "/usr/local/include" "/usr/include" "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB" "C:/Program Files (x86)/TBB" "${CMAKE_INSTALL_PREFIX}/include") + set(TBB_DEFAULT_INCLUDE_DIRS + "/opt/intel/tbb" "/usr/local/include" "/usr/include" + "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB" + "C:/Program Files (x86)/tbb/include" + "C:/Program Files (x86)/tbb/include" + "${CMAKE_INSTALL_PREFIX}/include") find_path(TBB_INCLUDE_DIRS "tbb/tbb.h" PATHS ${TBB_INCLUDE_DIR} ${TBB_DEFAULT_INCLUDE_DIRS} DOC "The path to TBB headers") if(TBB_INCLUDE_DIRS) diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 7fa56781f8..879d332532 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -501,3 +501,12 @@ macro(ocv_parse_header2 LIBNAME HDR_PATH VARNAME) endif() endif() endmacro() + + +################################################################################################ +# short command to setup source group +function(ocv_source_group group) + cmake_parse_arguments(OCV_SOURCE_GROUP "" "" "GLOB" ${ARGN}) + file(GLOB srcs ${OCV_SOURCE_GROUP_GLOB}) + source_group(${group} FILES ${srcs}) +endfunction() \ No newline at end of file diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt index 644e10e5eb..db673c7a2e 100644 --- a/modules/core/CMakeLists.txt +++ b/modules/core/CMakeLists.txt @@ -3,13 +3,14 @@ ocv_add_module(core ${ZLIB_LIBRARIES}) ocv_module_include_directories(${ZLIB_INCLUDE_DIR}) if(HAVE_CUDA) - file(GLOB lib_cuda "src/cuda/*.cu") - source_group("Cuda" FILES "${lib_cuda}") - + ocv_source_group("Src\\Cuda" GLOB "src/cuda/*.cu") ocv_include_directories("${OpenCV_SOURCE_DIR}/modules/gpu/src" "${OpenCV_SOURCE_DIR}/modules/gpu/src/cuda" ${CUDA_INCLUDE_DIRS}) ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef) + + file(GLOB lib_cuda "src/cuda/*.cu") ocv_cuda_compile(cuda_objs ${lib_cuda}) + set(cuda_link_libs ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY}) else() set(lib_cuda "") diff --git a/modules/gpu/src/cuda/texture_binder.hpp b/modules/gpu/src/cuda/texture_binder.hpp new file mode 100644 index 0000000000..812062da80 --- /dev/null +++ b/modules/gpu/src/cuda/texture_binder.hpp @@ -0,0 +1,92 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef OPENCV_GPU_TEXTURE_BINDER_HPP_ +#define OPENCV_GPU_TEXTURE_BINDER_HPP_ + +#include "opencv2/gpu/devmem2d.hpp" +#include + +namespace cv +{ + namespace gpu + { + class TextureBinder + { + public: + template + TextureBinder(const PtrStepSz& arr, const struct texture& tex) : texref(&tex) + { + cudaChannelFormatDesc desc = cudaCreateChannelDesc(); + cudaSafeCall( cudaBindTexture2D(0, tex, arr.data, desc, arr.cols, arr.rows, arr.step) ); + } + + template + TextureBinder(const PtrSz& arr, const struct texture &tex) : texref(&tex) + { + cudaChannelFormatDesc desc = cudaCreateChannelDesc(); + cudaSafeCall( cudaBindTexture(0, tex, arr.data, desc, arr.size * arr.elemSize()) ); + } + + template + TextureBinder(const A& arr, const struct texture& tex, const cudaChannelFormatDesc& desc) : texref(&tex) + { + cudaSafeCall( cudaBindTexture2D(0, tex, arr.data, desc, arr.cols, arr.rows, arr.step) ); + } + + + ~TextureBinder() + { + cudaSafeCall( cudaUnbindTexture(texref) ); + } + private: + const struct textureReference *texref; + }; + } + + namespace device + { + using pcl::gpu::TextureBinder; + } +} + +#endif /* OPENCV_GPU_TEXTURE_BINDER_HPP_*/ \ No newline at end of file From c8a54f67d4df0e64d44914b4ca37d6d7d5ce3824 Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Wed, 22 Aug 2012 20:26:32 +0400 Subject: [PATCH 059/163] minor warning fix --- modules/gpu/src/cuda/bf_radius_match.cu | 4 ++-- modules/gpu/src/cuda/canny.cu | 4 ++-- modules/gpu/src/cuda/column_filter.cu | 2 +- modules/gpu/src/cuda/fast.cu | 4 ++-- modules/gpu/src/cuda/hist.cu | 2 +- modules/gpu/src/cuda/integral_image.cu | 4 ++-- modules/gpu/src/cuda/matrix_reductions.cu | 16 ++++++++-------- modules/gpu/src/cuda/pyrlk.cu | 8 ++++---- modules/gpu/src/cuda/row_filter.cu | 2 +- .../gpu/src/nvidia/NPP_staging/NPP_staging.cu | 2 +- 10 files changed, 24 insertions(+), 24 deletions(-) diff --git a/modules/gpu/src/cuda/bf_radius_match.cu b/modules/gpu/src/cuda/bf_radius_match.cu index 0aa71913b2..c6cba928c1 100644 --- a/modules/gpu/src/cuda/bf_radius_match.cu +++ b/modules/gpu/src/cuda/bf_radius_match.cu @@ -56,7 +56,7 @@ namespace cv { namespace gpu { namespace device __global__ void matchUnrolled(const DevMem2D_ query, int imgIdx, const DevMem2D_ train, float maxDistance, const Mask mask, PtrStepi bestTrainIdx, PtrStepi bestImgIdx, PtrStepf bestDistance, unsigned int* nMatches, int maxCount) { - #if __CUDA_ARCH__ >= 110 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) extern __shared__ int smem[]; @@ -168,7 +168,7 @@ namespace cv { namespace gpu { namespace device __global__ void match(const DevMem2D_ query, int imgIdx, const DevMem2D_ train, float maxDistance, const Mask mask, PtrStepi bestTrainIdx, PtrStepi bestImgIdx, PtrStepf bestDistance, unsigned int* nMatches, int maxCount) { - #if __CUDA_ARCH__ >= 110 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) extern __shared__ int smem[]; diff --git a/modules/gpu/src/cuda/canny.cu b/modules/gpu/src/cuda/canny.cu index f9dd490bf6..95028c2eaf 100644 --- a/modules/gpu/src/cuda/canny.cu +++ b/modules/gpu/src/cuda/canny.cu @@ -261,7 +261,7 @@ namespace cv { namespace gpu { namespace device __global__ void edgesHysteresisLocal(PtrStepi map, ushort2* st, int rows, int cols) { - #if __CUDA_ARCH__ >= 120 + #if defined (__CUDA_ARCH__) && (__CUDA_ARCH__ >= 120) __shared__ int smem[18][18]; @@ -358,7 +358,7 @@ namespace cv { namespace gpu { namespace device __global__ void edgesHysteresisGlobal(PtrStepi map, ushort2* st1, ushort2* st2, int rows, int cols, int count) { - #if __CUDA_ARCH__ >= 120 + #if defined (__CUDA_ARCH__) && __CUDA_ARCH__ >= 120 const int stack_size = 512; diff --git a/modules/gpu/src/cuda/column_filter.cu b/modules/gpu/src/cuda/column_filter.cu index 624bd3fbc0..fb52d6e989 100644 --- a/modules/gpu/src/cuda/column_filter.cu +++ b/modules/gpu/src/cuda/column_filter.cu @@ -64,7 +64,7 @@ namespace cv { namespace gpu { namespace device template __global__ void linearColumnFilter(const DevMem2D_ src, PtrStep dst, const int anchor, const B brd) { - #if __CUDA_ARCH__ >= 200 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 200) const int BLOCK_DIM_X = 16; const int BLOCK_DIM_Y = 16; const int PATCH_PER_BLOCK = 4; diff --git a/modules/gpu/src/cuda/fast.cu b/modules/gpu/src/cuda/fast.cu index 8f904cd985..a511e8f35f 100644 --- a/modules/gpu/src/cuda/fast.cu +++ b/modules/gpu/src/cuda/fast.cu @@ -223,7 +223,7 @@ namespace cv { namespace gpu { namespace device template __global__ void calcKeypoints(const DevMem2Db img, const Mask mask, short2* kpLoc, const unsigned int maxKeypoints, PtrStepi score, const int threshold) { - #if __CUDA_ARCH__ >= 110 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) const int j = threadIdx.x + blockIdx.x * blockDim.x + 3; const int i = threadIdx.y + blockIdx.y * blockDim.y + 3; @@ -325,7 +325,7 @@ namespace cv { namespace gpu { namespace device __global__ void nonmaxSupression(const short2* kpLoc, int count, const DevMem2Di scoreMat, short2* locFinal, float* responseFinal) { - #if __CUDA_ARCH__ >= 110 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) const int kpIdx = threadIdx.x + blockIdx.x * blockDim.x; diff --git a/modules/gpu/src/cuda/hist.cu b/modules/gpu/src/cuda/hist.cu index a7f45719ea..0a08f82f41 100644 --- a/modules/gpu/src/cuda/hist.cu +++ b/modules/gpu/src/cuda/hist.cu @@ -63,7 +63,7 @@ namespace cv { namespace gpu { namespace device #define MERGE_THREADBLOCK_SIZE 256 - #define USE_SMEM_ATOMICS (__CUDA_ARCH__ >= 120) + #define USE_SMEM_ATOMICS (defined (__CUDA_ARCH__) && (__CUDA_ARCH__ >= 120)) namespace hist { diff --git a/modules/gpu/src/cuda/integral_image.cu b/modules/gpu/src/cuda/integral_image.cu index ead0ddefec..5cb777dd92 100644 --- a/modules/gpu/src/cuda/integral_image.cu +++ b/modules/gpu/src/cuda/integral_image.cu @@ -59,7 +59,7 @@ namespace cv { namespace gpu { namespace device __global__ void shfl_integral_horizontal(const PtrStep_ img, PtrStep_ integral) { - #if __CUDA_ARCH__ >= 300 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 300) __shared__ int sums[128]; const int id = threadIdx.x; @@ -299,7 +299,7 @@ namespace cv { namespace gpu { namespace device // block sums. __global__ void shfl_integral_vertical(DevMem2D_ integral) { - #if __CUDA_ARCH__ >= 300 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 300) __shared__ unsigned int sums[32][9]; const int tidx = blockIdx.x * blockDim.x + threadIdx.x; diff --git a/modules/gpu/src/cuda/matrix_reductions.cu b/modules/gpu/src/cuda/matrix_reductions.cu index a0be65c3cd..d9b1b5cba4 100644 --- a/modules/gpu/src/cuda/matrix_reductions.cu +++ b/modules/gpu/src/cuda/matrix_reductions.cu @@ -215,7 +215,7 @@ namespace cv { namespace gpu { namespace device maxval[blockIdx.y * gridDim.x + blockIdx.x] = (T)smaxval[0]; } - #if __CUDA_ARCH__ >= 110 + #if defined (__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) __shared__ bool is_last; if (tid == 0) @@ -535,7 +535,7 @@ namespace cv { namespace gpu { namespace device findMinMaxLocInSmem(sminval, smaxval, sminloc, smaxloc, tid); - #if __CUDA_ARCH__ >= 110 + #if defined (__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) __shared__ bool is_last; if (tid == 0) @@ -841,7 +841,7 @@ namespace cv { namespace gpu { namespace device sumInSmem(scount, tid); - #if __CUDA_ARCH__ >= 110 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) __shared__ bool is_last; if (tid == 0) @@ -1034,7 +1034,7 @@ namespace cv { namespace gpu { namespace device sumInSmem(smem, tid); - #if __CUDA_ARCH__ >= 110 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) __shared__ bool is_last; if (tid == 0) @@ -1115,7 +1115,7 @@ namespace cv { namespace gpu { namespace device sumInSmem(smem, tid); sumInSmem(smem + nthreads, tid); - #if __CUDA_ARCH__ >= 110 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) __shared__ bool is_last; if (tid == 0) @@ -1222,7 +1222,7 @@ namespace cv { namespace gpu { namespace device sumInSmem(smem + nthreads, tid); sumInSmem(smem + 2 * nthreads, tid); - #if __CUDA_ARCH__ >= 110 + #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 110 __shared__ bool is_last; if (tid == 0) @@ -1339,7 +1339,7 @@ namespace cv { namespace gpu { namespace device sumInSmem(smem + 2 * nthreads, tid); sumInSmem(smem + 3 * nthreads, tid); - #if __CUDA_ARCH__ >= 110 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) __shared__ bool is_last; if (tid == 0) @@ -1975,7 +1975,7 @@ namespace cv { namespace gpu { namespace device for (int c = 0; c < cn; ++c) myVal[c] = op.startValue(); - #if __CUDA_ARCH__ >= 200 + #if defined (__CUDA_ARCH__) && __CUDA_ARCH__ >= 200 // For cc >= 2.0 prefer L1 cache for (int x = threadIdx.x; x < src.cols; x += 256) diff --git a/modules/gpu/src/cuda/pyrlk.cu b/modules/gpu/src/cuda/pyrlk.cu index b06d607687..271660515b 100644 --- a/modules/gpu/src/cuda/pyrlk.cu +++ b/modules/gpu/src/cuda/pyrlk.cu @@ -82,7 +82,7 @@ namespace cv { namespace gpu { namespace device smem3[tid] = val3; __syncthreads(); -#if __CUDA_ARCH__ > 110 +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ > 110) if (tid < 128) { smem1[tid] = val1 += smem1[tid + 128]; @@ -138,7 +138,7 @@ namespace cv { namespace gpu { namespace device smem2[tid] = val2; __syncthreads(); -#if __CUDA_ARCH__ > 110 +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ > 110) if (tid < 128) { smem1[tid] = val1 += smem1[tid + 128]; @@ -184,7 +184,7 @@ namespace cv { namespace gpu { namespace device smem1[tid] = val1; __syncthreads(); -#if __CUDA_ARCH__ > 110 +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ > 110) if (tid < 128) { smem1[tid] = val1 += smem1[tid + 128]; @@ -271,7 +271,7 @@ namespace cv { namespace gpu { namespace device template __global__ void lkSparse(const float2* prevPts, float2* nextPts, uchar* status, float* err, const int level, const int rows, const int cols) { -#if __CUDA_ARCH__ <= 110 +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ <= 110) __shared__ float smem1[128]; __shared__ float smem2[128]; __shared__ float smem3[128]; diff --git a/modules/gpu/src/cuda/row_filter.cu b/modules/gpu/src/cuda/row_filter.cu index 8963212a23..d40af71496 100644 --- a/modules/gpu/src/cuda/row_filter.cu +++ b/modules/gpu/src/cuda/row_filter.cu @@ -64,7 +64,7 @@ namespace cv { namespace gpu { namespace device template __global__ void linearRowFilter(const DevMem2D_ src, PtrStep dst, const int anchor, const B brd) { - #if __CUDA_ARCH__ >= 200 + #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 200) const int BLOCK_DIM_X = 32; const int BLOCK_DIM_Y = 8; const int PATCH_PER_BLOCK = 4; diff --git a/modules/gpu/src/nvidia/NPP_staging/NPP_staging.cu b/modules/gpu/src/nvidia/NPP_staging/NPP_staging.cu index f75453930b..0e6aca0889 100644 --- a/modules/gpu/src/nvidia/NPP_staging/NPP_staging.cu +++ b/modules/gpu/src/nvidia/NPP_staging/NPP_staging.cu @@ -2070,7 +2070,7 @@ NCVStatus nppiStInterpolateFrames(const NppStInterpolationState *pState) //============================================================================== -#if __CUDA_ARCH__ < 200 +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ < 200) // FP32 atomic add static __forceinline__ __device__ float _atomicAdd(float *addr, float val) From fc307c87dc8c8b247a186292533b7436fa73eac5 Mon Sep 17 00:00:00 2001 From: Vsevolod Glumov Date: Thu, 23 Aug 2012 14:56:02 +0400 Subject: [PATCH 060/163] Improved the public 'non-optimized' duplicates of 'Tegra-optimized' functions. --- ...mera_calibration_and_3d_reconstruction.rst | 18 +- modules/calib3d/doc/pics/stereo_undistort.jpg | Bin 123022 -> 123443 bytes modules/core/doc/basic_structures.rst | 72 ++-- modules/core/doc/operations_on_arrays.rst | 320 +++++++++--------- .../doc/feature_detection_and_description.rst | 10 +- modules/imgproc/doc/feature_detection.rst | 12 +- modules/imgproc/doc/filtering.rst | 185 +++++----- .../imgproc/doc/geometric_transformations.rst | 46 +-- .../doc/miscellaneous_transformations.rst | 40 +-- modules/stitching/doc/matching.rst | 6 +- .../motion_analysis_and_object_tracking.rst | 50 +-- 11 files changed, 380 insertions(+), 379 deletions(-) diff --git a/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst b/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst index ea4839a79f..887accd95c 100644 --- a/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst +++ b/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst @@ -502,27 +502,27 @@ Sample usage of detecting and drawing chessboard corners: :: findCirclesGrid ------------------- -Finds the centers in the grid of circles. +Finds centers in the grid of circles. .. ocv:function:: bool findCirclesGrid( InputArray image, Size patternSize, OutputArray centers, int flags=CALIB_CB_SYMMETRIC_GRID, const Ptr &blobDetector = new SimpleBlobDetector() ) .. ocv:pyfunction:: cv2.findCirclesGridDefault(image, patternSize[, centers[, flags]]) -> retval, centers - :param image: Grid view of source circles. It must be an 8-bit grayscale or color image. + :param image: grid view of input circles; it must be an 8-bit grayscale or color image. - :param patternSize: Number of circles per a grid row and column ``( patternSize = Size(points_per_row, points_per_colum) )`` . + :param patternSize: number of circles per row and column ``( patternSize = Size(points_per_row, points_per_colum) )``. - :param centers: Output array of detected centers. + :param centers: output array of detected centers. - :param flags: Various operation flags that can be one of the following values: + :param flags: various operation flags that can be one of the following values: - * **CALIB_CB_SYMMETRIC_GRID** Use symmetric pattern of circles. + * **CALIB_CB_SYMMETRIC_GRID** uses symmetric pattern of circles. - * **CALIB_CB_ASYMMETRIC_GRID** Use asymmetric pattern of circles. + * **CALIB_CB_ASYMMETRIC_GRID** uses asymmetric pattern of circles. - * **CALIB_CB_CLUSTERING** Use a special algorithm for grid detection. It is more robust to perspective distortions but much more sensitive to background clutter. + * **CALIB_CB_CLUSTERING** uses a special algorithm for grid detection. It is more robust to perspective distortions but much more sensitive to background clutter. - :param blobDetector: FeatureDetector that finds blobs like dark circles on light background + :param blobDetector: feature detector that finds blobs like dark circles on light background. The function attempts to determine diff --git a/modules/calib3d/doc/pics/stereo_undistort.jpg b/modules/calib3d/doc/pics/stereo_undistort.jpg index 25de335dbf88cafe9151a8e85d63924496a609b3..9079739a35af68f560f8cffe404be5598554b924 100644 GIT binary patch delta 562 zcmZWl%SyvQ6un7nE8Qw}(Jn&Vh|o-uBG`}=)GBTQ;zC>rX_D4x^B|d$xaz`%J5l-r z{RI(mCkXurS3>=fIC(S{92n-@Gv}WBc>Jus&a3tKD_+3IabyhuR26msU>z#c@5a{T zf@;7Ti79fgs2wP!mawuv<+vPVuJMGBkB zB!Uwfu}mt#w+efyo-s$RZ!&wFz=>?P#xRWR8w2UQcao=*NMZAelQ0aqu+6#t5DA@5 z2k{~j#TJpYf;$ImQOgOoGnb`N&kS_m^04JPOk%9{-7!{JHmOvctWiTR3VCCHlvXix zWR6VRbZ|h%n+T|IC&{v*OToB*W9m5Vyzom$IMjw{g_hBOwTzOMR$9y!kg{Y0-I|Pw VZFXz%&rAKSaj!Pt)h2Z?{{>$RjA#G= delta 171 zcmdmdguU+|yU70={~s_2c)5AHF)%VRGI#(X!)9xy?b7uR85&$GGSe6se0>?T7#J8h z7+4vF7?^=9Mj&Khlwx27vl$q?7^UItAVv+S8YTvY_DlvAsG2As4FW*pLAs$d(*h=# Z3Z{ky%rG|NcaWmy53<`o$TB(~0RX~J7>@t| diff --git a/modules/core/doc/basic_structures.rst b/modules/core/doc/basic_structures.rst index a2d2b5431d..e77ee4f577 100644 --- a/modules/core/doc/basic_structures.rst +++ b/modules/core/doc/basic_structures.rst @@ -778,7 +778,7 @@ Here are examples of matrix expressions: Below is the formal description of the ``Mat`` methods. Mat::Mat ------------- +-------- Various Mat constructors .. ocv:function:: Mat::Mat() @@ -861,7 +861,7 @@ often the default constructor is enough, and the proper matrix will be allocated Mat::~Mat ------------- +--------- The Mat destructor. .. ocv:function:: Mat::~Mat() @@ -870,7 +870,7 @@ The matrix destructor calls :ocv:func:`Mat::release` . Mat::operator = -------------------- +--------------- Provides matrix assignment operators. .. ocv:function:: Mat& Mat::operator = (const Mat& m) @@ -888,7 +888,7 @@ Provides matrix assignment operators. These are available assignment operators. Since they all are very different, make sure to read the operator parameters description. Mat::row ------------- +-------- Creates a matrix header for the specified matrix row. .. ocv:function:: Mat Mat::row(int y) const @@ -923,7 +923,7 @@ The method makes a new header for the specified matrix row and returns it. This A.row(j).copyTo(A.row(i)); Mat::col ------------- +-------- Creates a matrix header for the specified matrix column. .. ocv:function:: Mat Mat::col(int x) const @@ -935,7 +935,7 @@ The method makes a new header for the specified matrix column and returns it. Th Mat::rowRange ------------------ +------------- Creates a matrix header for the specified row span. .. ocv:function:: Mat Mat::rowRange(int startrow, int endrow) const @@ -953,7 +953,7 @@ The method makes a new header for the specified row span of the matrix. Similarl :ocv:func:`Mat::col` , this is an O(1) operation. Mat::colRange ------------------ +------------- Creates a matrix header for the specified row span. .. ocv:function:: Mat Mat::colRange(int startcol, int endcol) const @@ -971,7 +971,7 @@ The method makes a new header for the specified column span of the matrix. Simil :ocv:func:`Mat::col` , this is an O(1) operation. Mat::diag -------------- +--------- Extracts a diagonal from a matrix, or creates a diagonal matrix. .. ocv:function:: Mat Mat::diag( int d=0 ) const @@ -991,7 +991,7 @@ The method makes a new header for the specified matrix diagonal. The new matrix :ocv:func:`Mat::col` , this is an O(1) operation. Mat::clone --------------- +---------- Creates a full copy of the array and the underlying data. .. ocv:function:: Mat Mat::clone() const @@ -1000,7 +1000,7 @@ The method creates a full copy of the array. The original ``step[]`` is not take Mat::copyTo ---------------- +----------- Copies the matrix to another one. .. ocv:function:: void Mat::copyTo( OutputArray m ) const @@ -1022,18 +1022,18 @@ When the operation mask is specified, and the ``Mat::create`` call shown above r .. _Mat::convertTo: Mat::convertTo ------------------- +-------------- Converts an array to another data type with optional scaling. .. ocv:function:: void Mat::convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const - :param m: Destination matrix. If it does not have a proper size or type before the operation, it is reallocated. + :param m: output matrix; if it does not have a proper size or type before the operation, it is reallocated. - :param rtype: Desired destination matrix type or, rather, the depth since the number of channels are the same as the source has. If ``rtype`` is negative, the destination matrix will have the same type as the source. + :param rtype: desired output matrix type or, rather, the depth since the number of channels are the same as the input has; if ``rtype`` is negative, the output matrix will have the same type as the input. - :param alpha: Optional scale factor. + :param alpha: optional scale factor. - :param beta: Optional delta added to the scaled values. + :param beta: optional delta added to the scaled values. The method converts source pixel values to the target data type. ``saturate_cast<>`` is applied at the end to avoid possible overflows: @@ -1043,7 +1043,7 @@ The method converts source pixel values to the target data type. ``saturate_cast Mat::assignTo ------------------ +------------- Provides a functional form of ``convertTo``. .. ocv:function:: void Mat::assignTo( Mat& m, int type=-1 ) const @@ -1056,7 +1056,7 @@ This is an internally used method called by the :ref:`MatrixExpressions` engine. Mat::setTo --------------- +---------- Sets all or some of the array elements to the specified value. .. ocv:function:: Mat& Mat::setTo( InputArray value, InputArray mask=noArray() ) @@ -1067,7 +1067,7 @@ Sets all or some of the array elements to the specified value. Mat::reshape ----------------- +------------ Changes the shape and/or the number of channels of a 2D matrix without copying the data. .. ocv:function:: Mat Mat::reshape(int cn, int rows=0) const @@ -1100,7 +1100,7 @@ For example, if there is a set of 3D points stored as an STL vector, and you wan Mat::t ----------- +------ Transposes a matrix. .. ocv:function:: MatExpr Mat::t() const @@ -1112,7 +1112,7 @@ The method performs matrix transposition by means of matrix expressions. It does Mat::inv ------------- +-------- Inverses a matrix. .. ocv:function:: MatExpr Mat::inv(int method=DECOMP_LU) const @@ -1129,7 +1129,7 @@ The method performs a matrix inversion by means of matrix expressions. This mean Mat::mul ------------- +-------- Performs an element-wise multiplication or division of the two matrices. .. ocv:function:: MatExpr Mat::mul(InputArray m, double scale=1) const @@ -1146,7 +1146,7 @@ Example: :: Mat::cross --------------- +---------- Computes a cross-product of two 3-element vectors. .. ocv:function:: Mat Mat::cross(InputArray m) const @@ -1157,18 +1157,18 @@ The method computes a cross-product of two 3-element vectors. The vectors must b Mat::dot ------------- +-------- Computes a dot-product of two vectors. .. ocv:function:: double Mat::dot(InputArray m) const - :param m: Another dot-product operand. + :param m: another dot-product operand. The method computes a dot-product of two matrices. If the matrices are not single-column or single-row vectors, the top-to-bottom left-to-right scan ordering is used to treat them as 1D vectors. The vectors must have the same size and type. If the matrices have more than one channel, the dot products from all the channels are summed together. Mat::zeros --------------- +---------- Returns a zero array of the specified size and type. .. ocv:function:: static MatExpr Mat::zeros(int rows, int cols, int type) @@ -1443,7 +1443,7 @@ The operators make a new header for the specified sub-array of ``*this`` . They Mat::operator CvMat ------------------------ +------------------- Creates the ``CvMat`` header for the matrix. .. ocv:function:: Mat::operator CvMat() const @@ -1462,7 +1462,7 @@ where ``mycvOldFunc`` is a function written to work with OpenCV 1.x data structu Mat::operator IplImage --------------------------- +---------------------- Creates the ``IplImage`` header for the matrix. .. ocv:function:: Mat::operator IplImage() const @@ -1470,7 +1470,7 @@ Creates the ``IplImage`` header for the matrix. The operator creates the ``IplImage`` header for the matrix without copying the underlying data. You should make sure than the original matrix is not deallocated while the ``IplImage`` header is used. Similarly to ``Mat::operator CvMat`` , the operator is useful for intermixing the new and the old OpenCV API's. Mat::total --------------- +---------- Returns the total number of array elements. .. ocv:function:: size_t Mat::total() const @@ -1478,7 +1478,7 @@ Returns the total number of array elements. The method returns the number of array elements (a number of pixels if the array represents an image). Mat::isContinuous ---------------------- +----------------- Reports whether the matrix is continuous or not. .. ocv:function:: bool Mat::isContinuous() const @@ -1576,7 +1576,7 @@ The method returns a matrix element type. This is an identifier compatible with Mat::depth --------------- +---------- Returns the depth of a matrix element. .. ocv:function:: int Mat::depth() const @@ -1599,7 +1599,7 @@ The method returns the identifier of the matrix element depth (the type of each Mat::channels ------------------ +------------- Returns the number of matrix channels. .. ocv:function:: int Mat::channels() const @@ -1608,7 +1608,7 @@ The method returns the number of matrix channels. Mat::step1 --------------- +---------- Returns a normalized step. .. ocv:function:: size_t Mat::step1( int i=0 ) const @@ -1618,7 +1618,7 @@ The method returns a matrix step divided by Mat::size -------------- +--------- Returns a matrix size. .. ocv:function:: Size Mat::size() const @@ -1627,7 +1627,7 @@ The method returns a matrix size: ``Size(cols, rows)`` . When the matrix is more Mat::empty --------------- +---------- Returns ``true`` if the array has no elements. .. ocv:function:: bool Mat::empty() const @@ -1636,7 +1636,7 @@ The method returns ``true`` if ``Mat::total()`` is 0 or if ``Mat::data`` is NULL Mat::ptr ------------- +-------- Returns a pointer to the specified matrix row. .. ocv:function:: uchar* Mat::ptr(int i0=0) @@ -1654,7 +1654,7 @@ The methods return ``uchar*`` or typed pointer to the specified matrix row. See Mat::at ------------ +------- Returns a reference to the specified array element. .. ocv:function:: template T& Mat::at(int i) const diff --git a/modules/core/doc/operations_on_arrays.rst b/modules/core/doc/operations_on_arrays.rst index dada2cf724..ed2409df7b 100644 --- a/modules/core/doc/operations_on_arrays.rst +++ b/modules/core/doc/operations_on_arrays.rst @@ -5,7 +5,7 @@ Operations on Arrays abs --- -Computes an absolute value of each matrix element. +Calculates an absolute value of each matrix element. .. ocv:function:: MatExpr abs( const Mat& m ) .. ocv:function:: MatExpr abs( const MatExpr& e ) @@ -27,8 +27,8 @@ The output matrix has the same size and the same type as the input one except fo absdiff ------------ -Computes the per-element absolute difference between two arrays or between an array and a scalar. +------- +Calculates the per-element absolute difference between two arrays or between an array and a scalar. .. ocv:function:: void absdiff(InputArray src1, InputArray src2, OutputArray dst) @@ -39,13 +39,13 @@ Computes the per-element absolute difference between two arrays or between an ar .. ocv:pyoldfunction:: cv.AbsDiff(src1, src2, dst)-> None .. ocv:pyoldfunction:: cv.AbsDiffS(src, dst, value)-> None - :param src1: First input array or a scalar. + :param src1: first input array or a scalar. - :param src2: Second input array or a scalar. + :param src2: second input array or a scalar. - :param dst: Destination array that has the same size and type as ``src1`` (or ``src2``). + :param dst: output array that has the same size and type as input arrays. -The function ``absdiff`` computes: +The function ``absdiff`` calculates: * Absolute difference between two arrays when they have the same size and type: @@ -76,9 +76,9 @@ The function ``absdiff`` computes: add -------- +--- -Computes the per-element sum of two arrays or an array and a scalar. +Calculates the per-element sum of two arrays or an array and a scalar. .. ocv:function:: void add(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray(), int dtype=-1) @@ -89,17 +89,17 @@ Computes the per-element sum of two arrays or an array and a scalar. .. ocv:pyoldfunction:: cv.Add(src1, src2, dst, mask=None)-> None .. ocv:pyoldfunction:: cv.AddS(src, value, dst, mask=None)-> None - :param src1: First source array or a scalar. + :param src1: first input array or a scalar. - :param src2: Second source array or a scalar. + :param src2: second input array or a scalar. - :param dst: Destination array that has the same size and number of channels as the input array(s). The depth is defined by ``dtype`` or ``src1``/``src2``. + :param dst: output array that has the same size and number of channels as the input array(s); the depth is defined by ``dtype`` or ``src1``/``src2``. - :param mask: Optional operation mask, 8-bit single channel array, that specifies elements of the destination array to be changed. + :param mask: optional operation mask – 8-bit single channel array, that specifies elements of the destination array to be changed. - :param dtype: Optional depth of the output array. See the discussion below. + :param dtype: optional depth of the output array (see the discussion below). -The function ``add`` computes: +The function ``add`` calculates: * Sum of two arrays when both input arrays have the same size and the same number of channels: @@ -129,7 +129,7 @@ The first function in the list above can be replaced with matrix expressions: :: dst = src1 + src2; dst += src1; // equivalent to add(dst, src1, dst); -The input arrays and the destination array can all have the same or different depths. For example, you can add a 16-bit unsigned array to a 8-bit signed array and store the sum as a 32-bit floating-point array. Depth of the output array is determined by the ``dtype`` parameter. In the second and third cases above, as well as in the first case, when ``src1.depth() == src2.depth()``, ``dtype`` can be set to the default ``-1``. In this case, the output array will have the same depth as the input array, be it ``src1``, ``src2`` or both. +The input arrays and the output array can all have the same or different depths. For example, you can add a 16-bit unsigned array to a 8-bit signed array and store the sum as a 32-bit floating-point array. Depth of the output array is determined by the ``dtype`` parameter. In the second and third cases above, as well as in the first case, when ``src1.depth() == src2.depth()``, ``dtype`` can be set to the default ``-1``. In this case, the output array will have the same depth as the input array, be it ``src1``, ``src2`` or both. .. note:: Saturation is not applied when the output array has the depth ``CV_32S``. You may even get result of an incorrect sign in the case of overflow. @@ -144,8 +144,8 @@ The input arrays and the destination array can all have the same or different de addWeighted ---------------- -Computes the weighted sum of two arrays. +----------- +Calculates the weighted sum of two arrays. .. ocv:function:: void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1) @@ -154,19 +154,19 @@ Computes the weighted sum of two arrays. .. ocv:cfunction:: void cvAddWeighted(const CvArr* src1, double alpha, const CvArr* src2, double beta, double gamma, CvArr* dst) .. ocv:pyoldfunction:: cv.AddWeighted(src1, alpha, src2, beta, gamma, dst)-> None - :param src1: First source array. + :param src1: first source array. - :param alpha: Weight for the first array elements. + :param alpha: weight of the first array elements. - :param src2: Second source array of the same size and channel number as ``src1`` . + :param src2: second source array of the same size and channel number as ``src1``. - :param beta: Weight for the second array elements. + :param beta: weight of the second array elements. - :param dst: Destination array that has the same size and number of channels as the input arrays. + :param dst: output array that has the same size and number of channels as the input arrays. - :param gamma: Scalar added to each sum. + :param gamma: scalar added to each sum. - :param dtype: Optional depth of the destination array. When both input arrays have the same depth, ``dtype`` can be set to ``-1``, which will be equivalent to ``src1.depth()``. + :param dtype: optional depth of the destination array; when both input arrays have the same depth, ``dtype`` can be set to ``-1``, which will be equivalent to ``src1.depth()``. The function ``addWeighted`` calculates the weighted sum of two arrays as follows: @@ -205,15 +205,15 @@ Calculates the per-element bit-wise conjunction of two arrays or an array and a .. ocv:pyoldfunction:: cv.And(src1, src2, dst, mask=None)-> None .. ocv:pyoldfunction:: cv.AndS(src, value, dst, mask=None)-> None - :param src1: First source array or a scalar. + :param src1: first input array or a scalar. - :param src2: Second source array or a scalar. + :param src2: second input array or a scalar. - :param dst: Destination array that has the same size and type as the input array(s). + :param dst: output array that has the same size and type as the input arrays. - :param mask: Optional operation mask, 8-bit single channel array, that specifies elements of the destination array to be changed. + :param mask: optional operation mask, 8-bit single channel array, that specifies elements of the destination array to be changed. -The function computes the per-element bit-wise logical conjunction for: +The function calculates the per-element bit-wise logical conjunction for: * Two arrays when ``src1`` and ``src2`` have the same size: @@ -252,13 +252,13 @@ Inverts every bit of an array. .. ocv:cfunction:: void cvNot(const CvArr* src, CvArr* dst) .. ocv:pyoldfunction:: cv.Not(src, dst)-> None - :param src: Source array. + :param src: input array. - :param dst: Destination array that has the same size and type as the input array. + :param dst: output array that has the same size and type as the input array. - :param mask: Optional operation mask, 8-bit single channel array, that specifies elements of the destination array to be changed. + :param mask: optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed. -The function computes per-element bit-wise inversion of the source array: +The function calculates per-element bit-wise inversion of the source array: .. math:: @@ -281,15 +281,15 @@ Calculates the per-element bit-wise disjunction of two arrays or an array and a .. ocv:pyoldfunction:: cv.Or(src1, src2, dst, mask=None)-> None .. ocv:pyoldfunction:: cv.OrS(src, value, dst, mask=None)-> None - :param src1: First source array or a scalar. + :param src1: first input array or a scalar. - :param src2: Second source array or a scalar. + :param src2: second input array or a scalar. - :param dst: Destination array that has the same size and type as the input array(s). + :param dst: output array that has the same size and type as the input arrays. - :param mask: Optional operation mask, 8-bit single channel array, that specifies elements of the destination array to be changed. + :param mask: optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed. -The function computes the per-element bit-wise logical disjunction for: +The function calculates the per-element bit-wise logical disjunction for: * Two arrays when ``src1`` and ``src2`` have the same size: @@ -329,15 +329,15 @@ Calculates the per-element bit-wise "exclusive or" operation on two arrays or an .. ocv:pyoldfunction:: cv.Xor(src1, src2, dst, mask=None)-> None .. ocv:pyoldfunction:: cv.XorS(src, value, dst, mask=None)-> None - :param src1: First source array or a scalar. + :param src1: first input array or a scalar. - :param src2: Second source array or a scalar. + :param src2: second input array or a scalar. - :param dst: Destination array that has the same size and type as the input array(s). + :param dst: output array that has the same size and type as the input arrays. - :param mask: Optional operation mask, 8-bit single channel array, that specifies elements of the destination array to be changed. + :param mask: optional operation mask, 8-bit single channel array, that specifies elements of the destination array to be changed. -The function computes the per-element bit-wise logical "exclusive-or" operation for: +The function calculates the per-element bit-wise logical "exclusive-or" operation for: * Two arrays when ``src1`` and ``src2`` have the same size: @@ -404,7 +404,7 @@ Calculates the covariance matrix of a set of vectors. ``covar`` will be a square matrix of the same size as the total number of elements in each input vector. One and only one of ``CV_COVAR_SCRAMBLED`` and ``CV_COVAR_NORMAL`` must be specified. - * **CV_COVAR_USE_AVG** If the flag is specified, the function does not calculate ``mean`` from the input vectors but, instead, uses the passed ``mean`` vector. This is useful if ``mean`` has been pre-computed or known in advance, or if the covariance matrix is calculated by parts. In this case, ``mean`` is not a mean vector of the input sub-set of vectors but rather the mean vector of the whole set. + * **CV_COVAR_USE_AVG** If the flag is specified, the function does not calculate ``mean`` from the input vectors but, instead, uses the passed ``mean`` vector. This is useful if ``mean`` has been pre-calculated or known in advance, or if the covariance matrix is calculated by parts. In this case, ``mean`` is not a mean vector of the input sub-set of vectors but rather the mean vector of the whole set. * **CV_COVAR_SCALE** If the flag is specified, the covariance matrix is scaled. In the "normal" mode, ``scale`` is ``1./nsamples`` . In the "scrambled" mode, ``scale`` is the reciprocal of the total number of elements in each input vector. By default (if the flag is not specified), the covariance matrix is not scaled ( ``scale=1`` ). @@ -498,20 +498,20 @@ Performs the per-element comparison of two arrays or an array and scalar value. .. ocv:pyoldfunction:: cv.CmpS(src, value, dst, cmpOp)-> None - :param src1: First source array or a scalar (in the case of ``cvCmp``, ``cv.Cmp``, ``cvCmpS``, ``cv.CmpS`` it is always an array). When it is array, it must have a single channel. + :param src1: first input array or a scalar (in the case of ``cvCmp``, ``cv.Cmp``, ``cvCmpS``, ``cv.CmpS`` it is always an array); when it is an array, it must have a single channel. - :param src2: Second source array or a scalar (in the case of ``cvCmp`` and ``cv.Cmp`` it is always an array; in the case of ``cvCmpS``, ``cv.CmpS`` it is always a scalar). When it is array, it must have a single channel. + :param src2: second input array or a scalar (in the case of ``cvCmp`` and ``cv.Cmp`` it is always an array; in the case of ``cvCmpS``, ``cv.CmpS`` it is always a scalar); when it is an array, it must have a single channel. - :param dst: Destination array that has the same size as the input array(s) and type= ``CV_8UC1`` . + :param dst: output array that has the same size as the input arrays and type= ``CV_8UC1`` . - :param cmpop: Flag specifying the relation between the elements to be checked. + :param cmpop: a flag, that specifies correspondence between the arrays: - * **CMP_EQ** ``src1`` equal to ``src2``. - * **CMP_GT** ``src1`` greater than ``src2``. - * **CMP_GE** ``src1`` greater than or equal to ``src2``. - * **CMP_LT** ``src1`` less than ``src2``. - * **CMP_LE** ``src1`` less than or equal to ``src2``. - * **CMP_NE** ``src1`` not equal to ``src2``. + * **CMP_EQ** ``src1`` is equal to ``src2``. + * **CMP_GT** ``src1`` is greater than ``src2``. + * **CMP_GE** ``src1`` is greater than or equal to ``src2``. + * **CMP_LT** ``src1`` is less than ``src2``. + * **CMP_LE** ``src1`` is less than or equal to ``src2``. + * **CMP_NE** ``src1`` is unequal to ``src2``. The function compares: @@ -587,7 +587,7 @@ The function ``completeSymm`` copies the lower half of a square matrix to its an convertScaleAbs --------------- -Scales, computes absolute values, and converts the result to 8-bit. +Scales, calculates absolute values, and converts the result to 8-bit. .. ocv:function:: void convertScaleAbs(InputArray src, OutputArray dst, double alpha=1, double beta=0) @@ -611,7 +611,7 @@ On each element of the input array, the function ``convertScaleAbs`` performs th \texttt{dst} (I)= \texttt{saturate\_cast} (| \texttt{src} (I)* \texttt{alpha} + \texttt{beta} |) -In case of multi-channel arrays, the function processes each channel independently. When the output is not 8-bit, the operation can be emulated by calling the ``Mat::convertTo`` method (or by using matrix expressions) and then by computing an absolute value of the result. For example: :: +In case of multi-channel arrays, the function processes each channel independently. When the output is not 8-bit, the operation can be emulated by calling the ``Mat::convertTo`` method (or by using matrix expressions) and then by calculating an absolute value of the result. For example: :: Mat_ A(30,30); randu(A, Scalar(-100), Scalar(100)); @@ -640,7 +640,7 @@ Counts non-zero array elements. .. ocv:pyoldfunction:: cv.CountNonZero(arr)-> int - :param src: Single-channel array. + :param src: single-channel array. The function returns the number of non-zero elements in ``src`` : @@ -664,13 +664,13 @@ Converts ``CvMat``, ``IplImage`` , or ``CvMatND`` to ``Mat``. .. ocv:function:: Mat cvarrToMat( const CvArr* arr, bool copyData=false, bool allowND=true, int coiMode=0 ) - :param arr: Source ``CvMat``, ``IplImage`` , or ``CvMatND`` . + :param arr: input ``CvMat``, ``IplImage`` , or ``CvMatND``. - :param copyData: When it is false (default value), no data is copied and only the new header is created. In this case, the original array should not be deallocated while the new matrix header is used. If the parameter is true, all the data is copied and you may deallocate the original array right after the conversion. + :param copyData: when false (default value), no data is copied and only the new header is created, in this case, the original array should not be deallocated while the new matrix header is used; if the parameter is true, all the data is copied and you may deallocate the original array right after the conversion. - :param allowND: When it is true (default value), ``CvMatND`` is converted to 2-dimensional ``Mat``, if it is possible (see the discussion below). If it is not possible, or when the parameter is false, the function will report an error. + :param allowND: when true (default value), ``CvMatND`` is converted to 2-dimensional ``Mat``, if it is possible (see the discussion below); if it is not possible, or when the parameter is false, the function will report an error. - :param coiMode: Parameter specifying how the IplImage COI (when set) is handled. + :param coiMode: parameter specifying how the IplImage COI (when set) is handled. * If ``coiMode=0`` and COI is set, the function reports an error. @@ -722,7 +722,7 @@ The last parameter, ``coiMode`` , specifies how to deal with an image with COI s :ocv:func:`mixChannels` dct -------- +--- Performs a forward or inverse discrete Cosine transform of 1D or 2D array. .. ocv:function:: void dct(InputArray src, OutputArray dst, int flags=0) @@ -806,7 +806,7 @@ The function chooses the mode of operation by looking at the flags and size of t Currently ``dct`` supports even-size arrays (2, 4, 6 ...). For data analysis and approximation, you can pad the array when necessary. Also, the function performance depends very much, and not monotonically, on the array size (see - :ocv:func:`getOptimalDFTSize` ). In the current implementation DCT of a vector of size ``N`` is computed via DFT of a vector of size ``N/2`` . Thus, the optimal DCT size ``N1 >= N`` can be computed as: :: + :ocv:func:`getOptimalDFTSize` ). In the current implementation DCT of a vector of size ``N`` is calculated via DFT of a vector of size ``N/2`` . Thus, the optimal DCT size ``N1 >= N`` can be calculated as: :: size_t getOptimalDCTSize(size_t N) { return 2*getOptimalDFTSize((N+1)/2); } N1 = getOptimalDCTSize(N); @@ -842,7 +842,7 @@ Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating- * **DFT_REAL_OUTPUT** performs an inverse transformation of a 1D or 2D complex array. The result is normally a complex array of the same size. However, if the source array has conjugate-complex symmetry (for example, it is a result of forward transformation with ``DFT_COMPLEX_OUTPUT`` flag), the output is a real array. While the function itself does not check whether the input is symmetrical or not, you can pass the flag and then the function will assume the symmetry and produce the real output array. Note that when the input is packed into a real array and inverse transformation is executed, the function treats the input as a packed complex-conjugate symmetrical array. So, the output will also be a real array. - :param nonzeroRows: When the parameter is not zero, the function assumes that only the first ``nonzeroRows`` rows of the input array ( ``DFT_INVERSE`` is not set) or only the first ``nonzeroRows`` of the output array ( ``DFT_INVERSE`` is set) contain non-zeros. Thus, the function can handle the rest of the rows more efficiently and save some time. This technique is very useful for computing array cross-correlation or convolution using DFT. + :param nonzeroRows: When the parameter is not zero, the function assumes that only the first ``nonzeroRows`` rows of the input array ( ``DFT_INVERSE`` is not set) or only the first ``nonzeroRows`` of the output array ( ``DFT_INVERSE`` is set) contain non-zeros. Thus, the function can handle the rest of the rows more efficiently and save some time. This technique is very useful for calculating array cross-correlation or convolution using DFT. The function performs one of the following: @@ -907,16 +907,16 @@ So, the function chooses an operation mode depending on the flags and size of th If ``DFT_SCALE`` is set, the scaling is done after the transformation. -Unlike :ocv:func:`dct` , the function supports arrays of arbitrary size. But only those arrays are processed efficiently, whose sizes can be factorized in a product of small prime numbers (2, 3, and 5 in the current implementation). Such an efficient DFT size can be computed using the :ocv:func:`getOptimalDFTSize` method. +Unlike :ocv:func:`dct` , the function supports arrays of arbitrary size. But only those arrays are processed efficiently, whose sizes can be factorized in a product of small prime numbers (2, 3, and 5 in the current implementation). Such an efficient DFT size can be calculated using the :ocv:func:`getOptimalDFTSize` method. -The sample below illustrates how to compute a DFT-based convolution of two 2D real arrays: :: +The sample below illustrates how to calculate a DFT-based convolution of two 2D real arrays: :: void convolveDFT(InputArray A, InputArray B, OutputArray C) { // reallocate the output array if needed C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type()); Size dftSize; - // compute the size of DFT transform + // calculate the size of DFT transform dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1); dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1); @@ -958,12 +958,12 @@ To optimize this sample, consider the following approaches: Since ``nonzeroRows != 0`` is passed to the forward transform calls and since ``A`` and ``B`` are copied to the top-left corners of ``tempA`` and ``tempB``, respectively, it is not necessary to clear the whole ``tempA`` and ``tempB``. It is only necessary to clear the ``tempA.cols - A.cols`` ( ``tempB.cols - B.cols``) rightmost columns of the matrices. * - This DFT-based convolution does not have to be applied to the whole big arrays, especially if ``B`` is significantly smaller than ``A`` or vice versa. Instead, you can compute convolution by parts. To do this, you need to split the destination array ``C`` into multiple tiles. For each tile, estimate which parts of ``A`` and ``B`` are required to compute convolution in this tile. If the tiles in ``C`` are too small, the speed will decrease a lot because of repeated work. In the ultimate case, when each tile in ``C`` is a single pixel, the algorithm becomes equivalent to the naive convolution algorithm. If the tiles are too big, the temporary arrays ``tempA`` and ``tempB`` become too big and there is also a slowdown because of bad cache locality. So, there is an optimal tile size somewhere in the middle. + This DFT-based convolution does not have to be applied to the whole big arrays, especially if ``B`` is significantly smaller than ``A`` or vice versa. Instead, you can calculate convolution by parts. To do this, you need to split the destination array ``C`` into multiple tiles. For each tile, estimate which parts of ``A`` and ``B`` are required to calculate convolution in this tile. If the tiles in ``C`` are too small, the speed will decrease a lot because of repeated work. In the ultimate case, when each tile in ``C`` is a single pixel, the algorithm becomes equivalent to the naive convolution algorithm. If the tiles are too big, the temporary arrays ``tempA`` and ``tempB`` become too big and there is also a slowdown because of bad cache locality. So, there is an optimal tile size somewhere in the middle. * - If different tiles in ``C`` can be computed in parallel and, thus, the convolution is done by parts, the loop can be threaded. + If different tiles in ``C`` can be calculated in parallel and, thus, the convolution is done by parts, the loop can be threaded. -All of the above improvements have been implemented in :ocv:func:`matchTemplate` and :ocv:func:`filter2D` . Therefore, by using them, you can get the performance even better than with the above theoretically optimal implementation. Though, those two functions actually compute cross-correlation, not convolution, so you need to "flip" the second convolution operand ``B`` vertically and horizontally using :ocv:func:`flip` . +All of the above improvements have been implemented in :ocv:func:`matchTemplate` and :ocv:func:`filter2D` . Therefore, by using them, you can get the performance even better than with the above theoretically optimal implementation. Though, those two functions actually calculate cross-correlation, not convolution, so you need to "flip" the second convolution operand ``B`` vertically and horizontally using :ocv:func:`flip` . .. seealso:: :ocv:func:`dct` , :ocv:func:`getOptimalDFTSize` , :ocv:func:`mulSpectrums`, :ocv:func:`filter2D` , :ocv:func:`matchTemplate` , :ocv:func:`flip` , :ocv:func:`cartToPolar` , :ocv:func:`magnitude` , :ocv:func:`phase` @@ -1032,10 +1032,10 @@ Returns the determinant of a square floating-point matrix. :param mtx: Input matrix that must have ``CV_32FC1`` or ``CV_64FC1`` type and square size. -The function ``determinant`` computes and returns the determinant of the specified matrix. For small matrices ( ``mtx.cols=mtx.rows<=3`` ), +The function ``determinant`` calculates and returns the determinant of the specified matrix. For small matrices ( ``mtx.cols=mtx.rows<=3`` ), the direct method is used. For larger matrices, the function uses LU factorization with partial pivoting. -For symmetric positively-determined matrices, it is also possible to use :ocv:func:`eigen` decomposition to compute the determinant. +For symmetric positively-determined matrices, it is also possible to use :ocv:func:`eigen` decomposition to calculate the determinant. .. seealso:: @@ -1049,13 +1049,13 @@ For symmetric positively-determined matrices, it is also possible to use :ocv:fu eigen ----- -Computes eigenvalues and eigenvectors of a symmetric matrix. +Calculates eigenvalues and eigenvectors of a symmetric matrix. .. ocv:function:: bool eigen(InputArray src, OutputArray eigenvalues, int lowindex=-1, int highindex=-1) .. ocv:function:: bool eigen(InputArray src, OutputArray eigenvalues, OutputArray eigenvectors, int lowindex=-1,int highindex=-1) -.. ocv:pyfunction:: cv2.eigen(src, computeEigenvectors[, eigenvalues[, eigenvectors]]) -> retval, eigenvalues, eigenvectors +.. ocv:pyfunction:: cv2.eigen(src, calculateEigenvectors[, eigenvalues[, eigenvectors]]) -> retval, eigenvalues, eigenvectors .. ocv:cfunction:: void cvEigenVV( CvArr* mat, CvArr* evects, CvArr* evals, double eps=0, int lowindex=-1, int highindex=-1 ) @@ -1071,7 +1071,7 @@ Computes eigenvalues and eigenvectors of a symmetric matrix. :param highindex: Optional index of smallest eigenvalue/-vector to calculate. The parameter is ignored in the current implementation. -The functions ``eigen`` compute just eigenvalues, or eigenvalues and eigenvectors of the symmetric matrix ``src`` : :: +The functions ``eigen`` calculate just eigenvalues, or eigenvalues and eigenvectors of the symmetric matrix ``src`` : :: src*eigenvectors.row(i).t() = eigenvalues.at(i)*eigenvectors.row(i).t() @@ -1301,14 +1301,14 @@ Returns the optimal DFT size for a given vector size. :param vecsize: Vector size. -DFT performance is not a monotonic function of a vector size. Therefore, when you compute convolution of two arrays or perform the spectral analysis of an array, it usually makes sense to pad the input data with zeros to get a bit larger array that can be transformed much faster than the original one. +DFT performance is not a monotonic function of a vector size. Therefore, when you calculate convolution of two arrays or perform the spectral analysis of an array, it usually makes sense to pad the input data with zeros to get a bit larger array that can be transformed much faster than the original one. Arrays whose size is a power-of-two (2, 4, 8, 16, 32, ...) are the fastest to process. Though, the arrays whose size is a product of 2's, 3's, and 5's (for example, 300 = 5*5*3*2*2) are also processed quite efficiently. -The function ``getOptimalDFTSize`` returns the minimum number ``N`` that is greater than or equal to ``vecsize`` so that the DFT of a vector of size ``N`` can be computed efficiently. In the current implementation ``N`` = 2 :sup:`p` * 3 :sup:`q` * 5 :sup:`r` for some integer ``p``, ``q``, ``r``. +The function ``getOptimalDFTSize`` returns the minimum number ``N`` that is greater than or equal to ``vecsize`` so that the DFT of a vector of size ``N`` can be processed efficiently. In the current implementation ``N`` = 2 :sup:`p` * 3 :sup:`q` * 5 :sup:`r` for some integer ``p``, ``q``, ``r``. The function returns a negative number if ``vecsize`` is too large (very close to ``INT_MAX`` ). -While the function cannot be used directly to estimate the optimal vector size for DCT transform (since the current DCT implementation supports only even-size vectors), it can be easily computed as ``getOptimalDFTSize((vecsize+1)/2)*2``. +While the function cannot be used directly to estimate the optimal vector size for DCT transform (since the current DCT implementation supports only even-size vectors), it can be easily processed as ``getOptimalDFTSize((vecsize+1)/2)*2``. .. seealso:: :ocv:func:`dft` , :ocv:func:`dct` , :ocv:func:`idft` , :ocv:func:`idct` , :ocv:func:`mulSpectrums` @@ -1316,7 +1316,7 @@ While the function cannot be used directly to estimate the optimal vector size f idct ---- -Computes the inverse Discrete Cosine Transform of a 1D or 2D array. +Calculates the inverse Discrete Cosine Transform of a 1D or 2D array. .. ocv:function:: void idct(InputArray src, OutputArray dst, int flags=0) @@ -1341,19 +1341,19 @@ Computes the inverse Discrete Cosine Transform of a 1D or 2D array. idft ---- -Computes the inverse Discrete Fourier Transform of a 1D or 2D array. +Calculates the inverse Discrete Fourier Transform of a 1D or 2D array. .. ocv:function:: void idft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0) .. ocv:pyfunction:: cv2.idft(src[, dst[, flags[, nonzeroRows]]]) -> dst - :param src: Source floating-point real or complex array. + :param src: input floating-point real or complex array. - :param dst: Destination array whose size and type depend on the ``flags`` . + :param dst: output array whose size and type depend on the ``flags`` . - :param flags: Operation flags. See :ocv:func:`dft` . + :param flags: operation flags (see :ocv:func:`dft`). - :param nonzeroRows: Number of ``dst`` rows to compute. The rest of the rows have undefined content. See the convolution sample in :ocv:func:`dft` description. + :param nonzeroRows: number of ``dst`` rows to process; the rest of the rows have undefined content (see the convolution sample in :ocv:func:`dft` description. ``idft(src, dst, flags)`` is equivalent to ``dft(src, dst, flags | DFT_INVERSE)`` . @@ -1384,13 +1384,13 @@ Checks if array elements lie between the elements of two other arrays. .. ocv:pyoldfunction:: cv.InRange(src, lower, upper, dst)-> None .. ocv:pyoldfunction:: cv.InRangeS(src, lower, upper, dst)-> None - :param src: First source array. + :param src: first input array. - :param lowerb: Inclusive lower boundary array or a scalar. + :param lowerb: inclusive lower boundary array or a scalar. - :param upperb: Inclusive upper boundary array or a scalar. + :param upperb: inclusive upper boundary array or a scalar. - :param dst: Destination array of the same size as ``src`` and ``CV_8U`` type. + :param dst: output array of the same size as ``src`` and ``CV_8U`` type. The function checks the range as follows: @@ -1438,9 +1438,9 @@ Finds the inverse or pseudo-inverse of a matrix. * **DECOMP_CHOLESKY** Cholesky decomposition. The matrix must be symmetrical and positively defined. The function ``invert`` inverts the matrix ``src`` and stores the result in ``dst`` . -When the matrix ``src`` is singular or non-square, the function computes the pseudo-inverse matrix (the ``dst`` matrix) so that ``norm(src*dst - I)`` is minimal, where I is an identity matrix. +When the matrix ``src`` is singular or non-square, the function calculates the pseudo-inverse matrix (the ``dst`` matrix) so that ``norm(src*dst - I)`` is minimal, where I is an identity matrix. -In case of the ``DECOMP_LU`` method, the function returns non-zero value if the inverse has been successfully computed and 0 if ``src`` is singular. +In case of the ``DECOMP_LU`` method, the function returns non-zero value if the inverse has been successfully calculated and 0 if ``src`` is singular. In case of the ``DECOMP_SVD`` method, the function returns the inverse condition number of ``src`` (the ratio of the smallest singular value to the largest singular value) and 0 if ``src`` is singular. The SVD method calculates a pseudo-inverse matrix if ``src`` is singular. @@ -1607,15 +1607,15 @@ Calculates per-element maximum of two arrays or an array and a scalar. .. ocv:pyoldfunction:: cv.Max(src1, src2, dst)-> None .. ocv:pyoldfunction:: cv.MaxS(src, value, dst)-> None - :param src1: First source array. + :param src1: first input array. - :param src2: Second source array of the same size and type as ``src1`` . + :param src2: second input array of the same size and type as ``src1`` . - :param value: Real scalar value. + :param value: real scalar value. - :param dst: Destination array of the same size and type as ``src1`` . + :param dst: output array of the same size and type as ``src1`` . -The functions ``max`` compute the per-element maximum of two arrays: +The functions ``max`` calculate the per-element maximum of two arrays: .. math:: @@ -1653,11 +1653,11 @@ Calculates an average (mean) of array elements. .. ocv:pyoldfunction:: cv.Avg(arr, mask=None) -> scalar - :param src: Source array that should have from 1 to 4 channels so that the result can be stored in :ocv:class:`Scalar_` . + :param src: input array that should have from 1 to 4 channels so that the result can be stored in :ocv:class:`Scalar_` . - :param mask: Optional operation mask. + :param mask: optional operation mask. -The function ``mean`` computes the mean value ``M`` of array elements, independently for each channel, and return it: +The function ``mean`` calculates the mean value ``M`` of array elements, independently for each channel, and return it: .. math:: @@ -1686,15 +1686,15 @@ Calculates a mean and standard deviation of array elements. .. ocv:pyoldfunction:: cv.AvgSdv(arr, mask=None) -> (mean, stdDev) - :param src: Source array that should have from 1 to 4 channels so that the results can be stored in :ocv:class:`Scalar_` 's. + :param src: input array that should have from 1 to 4 channels so that the results can be stored in :ocv:class:`Scalar_` 's. - :param mean: Output parameter: computed mean value. + :param mean: output parameter: calculated mean value. - :param stddev: Output parameter: computed standard deviation. + :param stddev: output parameter: calculateded standard deviation. - :param mask: Optional operation mask. + :param mask: optional operation mask. -The function ``meanStdDev`` computes the mean and the standard deviation ``M`` of array elements independently for each channel and returns it via the output parameters: +The function ``meanStdDev`` calculates the mean and the standard deviation ``M`` of array elements independently for each channel and returns it via the output parameters: .. math:: @@ -1702,7 +1702,7 @@ The function ``meanStdDev`` computes the mean and the standard deviation ``M`` o When all the mask elements are 0's, the functions return ``mean=stddev=Scalar::all(0)`` . -.. note:: The computed standard deviation is only the diagonal of the complete normalized covariance matrix. If the full matrix is needed, you can reshape the multi-channel array ``M x N`` to the single-channel array ``M*N x mtx.channels()`` (only possible when the matrix is continuous) and then pass the matrix to :ocv:func:`calcCovarMatrix` . +.. note:: The calculated standard deviation is only the diagonal of the complete normalized covariance matrix. If the full matrix is needed, you can reshape the multi-channel array ``M x N`` to the single-channel array ``M*N x mtx.channels()`` (only possible when the matrix is continuous) and then pass the matrix to :ocv:func:`calcCovarMatrix` . .. seealso:: @@ -1716,7 +1716,7 @@ When all the mask elements are 0's, the functions return ``mean=stddev=Scalar::a merge ----- -Composes a multi-channel array from several single-channel arrays. +Creates one multichannel array out of several single-channel ones. .. ocv:function:: void merge(const Mat* mv, size_t count, OutputArray dst) @@ -1727,11 +1727,11 @@ Composes a multi-channel array from several single-channel arrays. .. ocv:cfunction:: void cvMerge(const CvArr* src0, const CvArr* src1, const CvArr* src2, const CvArr* src3, CvArr* dst) .. ocv:pyoldfunction:: cv.Merge(src0, src1, src2, src3, dst)-> None - :param mv: Source array or vector of matrices to be merged. All the matrices in ``mv`` must have the same size and the same depth. + :param mv: input array or vector of matrices to be merged; all the matrices in ``mv`` must have the same size and the same depth. - :param count: Number of source matrices when ``mv`` is a plain C array. It must be greater than zero. + :param count: number of source matrices when ``mv`` is a plain C array; it must be greater than zero. - :param dst: Destination array of the same size and the same depth as ``mv[0]`` . The number of channels will be the total number of channels in the matrix array. + :param dst: output array of the same size and the same depth as ``mv[0]``; The number of channels will be the total number of channels in the matrix array. The functions ``merge`` merge several arrays to make a single multi-channel array. That is, each element of the output array will be a concatenation of the elements of the input arrays, where elements of i-th input array are treated as ``mv[i].channels()``-element vectors. @@ -1749,7 +1749,7 @@ The function min --- -Calculates per-element minimum of two arrays or array and a scalar. +Calculates per-element minimum of two arrays or an array and a scalar. .. ocv:function:: MatExpr min( const Mat& a, const Mat& b ) @@ -1770,15 +1770,15 @@ Calculates per-element minimum of two arrays or array and a scalar. .. ocv:pyoldfunction:: cv.Min(src1, src2, dst)-> None .. ocv:pyoldfunction:: cv.MinS(src, value, dst)-> None - :param src1: First source array. + :param src1: first input array. - :param src2: Second source array of the same size and type as ``src1`` . + :param src2: second input array of the same size and type as ``src1`` . - :param value: Real scalar value. + :param value: real scalar value. - :param dst: Destination array of the same size and type as ``src1`` . + :param dst: output array of the same size and type as ``src1`` . -The functions ``min`` compute the per-element minimum of two arrays: +The functions ``min`` calculate the per-element minimum of two arrays: .. math:: @@ -1850,17 +1850,17 @@ Finds the global minimum and maximum in an array. .. ocv:pyoldfunction:: cv.MinMaxLoc(arr, mask=None)-> (minVal, maxVal, minLoc, maxLoc) - :param src: Source single-channel array. + :param src: input single-channel array. - :param minVal: Pointer to the returned minimum value. ``NULL`` is used if not required. + :param minVal: pointer to the returned minimum value; ``NULL`` is used if not required. - :param maxVal: Pointer to the returned maximum value. ``NULL`` is used if not required. + :param maxVal: pointer to the returned maximum value; ``NULL`` is used if not required. - :param minLoc: Pointer to the returned minimum location (in 2D case). ``NULL`` is used if not required. + :param minLoc: pointer to the returned minimum location (in 2D case); ``NULL`` is used if not required. - :param maxLoc: Pointer to the returned maximum location (in 2D case). ``NULL`` is used if not required. + :param maxLoc: pointer to the returned maximum location (in 2D case); ``NULL`` is used if not required. - :param mask: Optional mask used to select a sub-array. + :param mask: optional mask used to select a sub-array. The functions ``minMaxLoc`` find the minimum and maximum element values and their positions. The extremums are searched across the whole array or, if ``mask`` is not an empty array, in the specified array region. @@ -2056,7 +2056,7 @@ if ``aTa=true`` , and \texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} ) ( \texttt{src} - \texttt{delta} )^T -otherwise. The function is used to compute the covariance matrix. With zero delta, it can be used as a faster substitute for general matrix product ``A*B`` when ``B=A'`` +otherwise. The function is used to calculate the covariance matrix. With zero delta, it can be used as a faster substitute for general matrix product ``A*B`` when ``B=A'`` .. seealso:: @@ -2084,13 +2084,13 @@ Calculates an absolute array norm, an absolute difference norm, or a relative di .. ocv:pyoldfunction:: cv.Norm(arr1, arr2, normType=CV_L2, mask=None) -> float - :param src1: First source array. + :param src1: first input array. - :param src2: Second source array of the same size and the same type as ``src1`` . + :param src2: second input array of the same size and the same type as ``src1``. - :param normType: Type of the norm. See the details below. + :param normType: type of the norm (see the details below). - :param mask: Optional operation mask. It must have the same size as ``src1`` and ``CV_8UC1`` type. + :param mask: optional operation mask; it must have the same size as ``src1`` and ``CV_8UC1`` type. The functions ``norm`` calculate an absolute norm of ``src1`` (when there is no ``src2`` ): @@ -2118,7 +2118,7 @@ or The functions ``norm`` return the calculated norm. -When the ``mask`` parameter is specified and it is not empty, the norm is computed only over the region specified by the mask. +When the ``mask`` parameter is specified and it is not empty, the norm is calculated only over the region specified by the mask. A multi-channel source arrays are treated as a single-channel, that is, the results for all channels are combined. @@ -2162,7 +2162,7 @@ The functions ``normalize`` scale and shift the source array elements so that \min _I \texttt{dst} (I)= \texttt{alpha} , \, \, \max _I \texttt{dst} (I)= \texttt{beta} when ``normType=NORM_MINMAX`` (for dense arrays only). -The optional mask specifies a sub-array to be normalized. This means that the norm or min-n-max are computed over the sub-array, and then this sub-array is modified to be normalized. If you want to only use the mask to compute the norm or min-max but modify the whole array, you can use +The optional mask specifies a sub-array to be normalized. This means that the norm or min-n-max are calculated over the sub-array, and then this sub-array is modified to be normalized. If you want to only use the mask to calculate the norm or min-max but modify the whole array, you can use :ocv:func:`norm` and :ocv:func:`Mat::convertTo`. @@ -2182,10 +2182,10 @@ PCA Principal Component Analysis class. -The class is used to compute a special basis for a set of vectors. The basis will consist of eigenvectors of the covariance matrix computed from the input set of vectors. The class ``PCA`` can also transform vectors to/from the new coordinate space defined by the basis. Usually, in this new coordinate system, each vector from the original set (and any linear combination of such vectors) can be quite accurately approximated by taking its first few components, corresponding to the eigenvectors of the largest eigenvalues of the covariance matrix. Geometrically it means that you compute a projection of the vector to a subspace formed by a few eigenvectors corresponding to the dominant eigenvalues of the covariance matrix. And usually such a projection is very close to the original vector. So, you can represent the original vector from a high-dimensional space with a much shorter vector consisting of the projected vector's coordinates in the subspace. Such a transformation is also known as Karhunen-Loeve Transform, or KLT. See +The class is used to calculate a special basis for a set of vectors. The basis will consist of eigenvectors of the covariance matrix calculated from the input set of vectors. The class ``PCA`` can also transform vectors to/from the new coordinate space defined by the basis. Usually, in this new coordinate system, each vector from the original set (and any linear combination of such vectors) can be quite accurately approximated by taking its first few components, corresponding to the eigenvectors of the largest eigenvalues of the covariance matrix. Geometrically it means that you calculate a projection of the vector to a subspace formed by a few eigenvectors corresponding to the dominant eigenvalues of the covariance matrix. And usually such a projection is very close to the original vector. So, you can represent the original vector from a high-dimensional space with a much shorter vector consisting of the projected vector's coordinates in the subspace. Such a transformation is also known as Karhunen-Loeve Transform, or KLT. See http://en.wikipedia.org/wiki/Principal\_component\_analysis . -The sample below is the function that takes two matrices. The first function stores a set of vectors (a row per vector) that is used to compute PCA. The second function stores another "test" set of vectors (a row per vector). First, these vectors are compressed with PCA, then reconstructed back, and then the reconstruction error norm is computed and printed for each vector. :: +The sample below is the function that takes two matrices. The first function stores a set of vectors (a row per vector) that is used to calculate PCA. The second function stores another "test" set of vectors (a row per vector). First, these vectors are compressed with PCA, then reconstructed back, and then the reconstruction error norm is computed and printed for each vector. :: PCA compressPCA(InputArray pcaset, int maxComponents, const Mat& testset, OutputArray compressed) @@ -2376,15 +2376,15 @@ Calculates the rotation angle of 2D vectors. .. ocv:pyfunction:: cv2.phase(x, y[, angle[, angleInDegrees]]) -> angle - :param x: Source floating-point array of x-coordinates of 2D vectors. + :param x: input floating-point array of x-coordinates of 2D vectors. - :param y: Source array of y-coordinates of 2D vectors. It must have the same size and the same type as ``x`` . + :param y: input array of y-coordinates of 2D vectors; it must have the same size and the same type as ``x``. - :param angle: Destination array of vector angles. It has the same size and same type as ``x`` . + :param angle: output array of vector angles; it has the same size and same type as ``x`` . - :param angleInDegrees: When it is true, the function computes the angle in degrees. Otherwise, they are measured in radians. + :param angleInDegrees: when true, the function calculates the angle in degrees, otherwise, they are measured in radians. -The function ``phase`` computes the rotation angle of each 2D vector that is formed from the corresponding elements of ``x`` and ``y`` : +The function ``phase`` calculates the rotation angle of each 2D vector that is formed from the corresponding elements of ``x`` and ``y`` : .. math:: @@ -2395,7 +2395,7 @@ The angle estimation accuracy is about 0.3 degrees. When ``x(I)=y(I)=0`` , the c polarToCart ----------- -Computes x and y coordinates of 2D vectors from their magnitude and angle. +Calculates x and y coordinates of 2D vectors from their magnitude and angle. .. ocv:function:: void polarToCart(InputArray magnitude, InputArray angle, OutputArray x, OutputArray y, bool angleInDegrees=false) @@ -2415,7 +2415,7 @@ Computes x and y coordinates of 2D vectors from their magnitude and angle. :param angleInDegrees: When it is true, the input angles are measured in degrees. Otherwise. they are measured in radians. -The function ``polarToCart`` computes the Cartesian coordinates of each 2D vector represented by the corresponding elements of ``magnitude`` and ``angle`` : +The function ``polarToCart`` calculates the Cartesian coordinates of each 2D vector represented by the corresponding elements of ``magnitude`` and ``angle`` : .. math:: @@ -2714,23 +2714,23 @@ Reduces a matrix to a vector. .. ocv:cfunction:: void cvReduce(const CvArr* src, CvArr* dst, int dim=-1, int op=CV_REDUCE_SUM) .. ocv:pyoldfunction:: cv.Reduce(src, dst, dim=-1, op=CV_REDUCE_SUM)-> None - :param src: Source 2D matrix. + :param src: input 2D matrix. - :param dst: Destination vector. Its size and type is defined by ``dim`` and ``dtype`` parameters. + :param dst: output vector. Its size and type is defined by ``dim`` and ``dtype`` parameters. - :param dim: Dimension index along which the matrix is reduced. 0 means that the matrix is reduced to a single row. 1 means that the matrix is reduced to a single column. + :param dim: dimension index along which the matrix is reduced. 0 means that the matrix is reduced to a single row. 1 means that the matrix is reduced to a single column. - :param rtype: Reduction operation that could be one of the following: + :param rtype: reduction operation that could be one of the following: - * **CV_REDUCE_SUM** The output is the sum of all rows/columns of the matrix. + * **CV_REDUCE_SUM**: the output is the sum of all rows/columns of the matrix. - * **CV_REDUCE_AVG** The output is the mean vector of all rows/columns of the matrix. + * **CV_REDUCE_AVG**: the output is the mean vector of all rows/columns of the matrix. - * **CV_REDUCE_MAX** The output is the maximum (column/row-wise) of all rows/columns of the matrix. + * **CV_REDUCE_MAX**: the output is the maximum (column/row-wise) of all rows/columns of the matrix. - * **CV_REDUCE_MIN** The output is the minimum (column/row-wise) of all rows/columns of the matrix. + * **CV_REDUCE_MIN**: the output is the minimum (column/row-wise) of all rows/columns of the matrix. - :param dtype: When it is negative, the destination vector will have the same type as the source matrix. Otherwise, its type will be ``CV_MAKE_TYPE(CV_MAT_DEPTH(dtype), src.channels())`` . + :param dtype: when negative, the destination vector will have the same type as the source matrix, otherwise, its type will be ``CV_MAKE_TYPE(CV_MAT_DEPTH(dtype), src.channels())``. The function ``reduce`` reduces the matrix to a vector by treating the matrix rows/columns as a set of 1D vectors and performing the specified operation on the vectors until a single row/column is obtained. For example, the function can be used to compute horizontal and vertical projections of a raster image. In case of ``CV_REDUCE_SUM`` and ``CV_REDUCE_AVG`` , the output may have a larger element bit-depth to preserve accuracy. And multi-channel arrays are also supported in these two reduction modes. @@ -3048,9 +3048,9 @@ Divides a multi-channel array into several single-channel arrays. .. ocv:pyoldfunction:: cv.Split(src, dst0, dst1, dst2, dst3)-> None - :param src: Source multi-channel array. + :param src: input multi-channel array. - :param mv: Destination array or vector of arrays. In the first variant of the function the number of arrays must match ``src.channels()`` . The arrays themselves are reallocated, if needed. + :param mv: output array or vector of arrays; in the first variant of the function the number of arrays must match ``src.channels()``; the arrays themselves are reallocated, if needed. The functions ``split`` split a multi-channel array into separate single-channel arrays: @@ -3109,17 +3109,17 @@ Calculates the per-element difference between two arrays or array and a scalar. .. ocv:pyoldfunction:: cv.SubRS(src, value, dst, mask=None) -> None .. ocv:pyoldfunction:: cv.SubS(src, value, dst, mask=None) -> None - :param src1: First source array or a scalar. + :param src1: first input array or a scalar. - :param src2: Second source array or a scalar. + :param src2: second input array or a scalar. - :param dst: Destination array of the same size and the same number of channels as the input array. + :param dst: output array of the same size and the same number of channels as the input array. - :param mask: Optional operation mask. This is an 8-bit single channel array that specifies elements of the destination array to be changed. + :param mask: optional operation mask; this is an 8-bit single channel array that specifies elements of the destination array to be changed. - :param dtype: Optional depth of the output array. See the details below. + :param dtype: optional depth of the output array (see the details below). -The function ``subtract`` computes: +The function ``subtract`` calculates: * Difference between two arrays, when both input arrays have the same size and the same number of channels: @@ -3156,7 +3156,7 @@ The first function in the list above can be replaced with matrix expressions: :: dst = src1 - src2; dst -= src1; // equivalent to subtract(dst, src1, dst); -The input arrays and the destination array can all have the same or different depths. For example, you can subtract to 8-bit unsigned arrays and store the difference in a 16-bit signed array. Depth of the output array is determined by ``dtype`` parameter. In the second and third cases above, as well as in the first case, when ``src1.depth() == src2.depth()``, ``dtype`` can be set to the default ``-1``. In this case the output array will have the same depth as the input array, be it ``src1``, ``src2`` or both. +The input arrays and the output array can all have the same or different depths. For example, you can subtract to 8-bit unsigned arrays and store the difference in a 16-bit signed array. Depth of the output array is determined by ``dtype`` parameter. In the second and third cases above, as well as in the first case, when ``src1.depth() == src2.depth()``, ``dtype`` can be set to the default ``-1``. In this case the output array will have the same depth as the input array, be it ``src1``, ``src2`` or both. .. note:: Saturation is not applied when the output array has the depth ``CV_32S``. You may even get result of an incorrect sign in the case of overflow. @@ -3245,11 +3245,11 @@ Performs SVD of a matrix :param src: Decomposed matrix - :param w: Computed singular values + :param w: calculated singular values - :param u: Computed left singular vectors + :param u: calculated left singular vectors - :param V: Computed right singular vectors + :param V: calculated right singular vectors :param vt: Transposed matrix of right singular values @@ -3305,7 +3305,7 @@ Performs a singular value back substitution. :param dst: Found solution of the system. -The method computes a back substitution for the specified right-hand side: +The method calculates a back substitution for the specified right-hand side: .. math:: @@ -3329,7 +3329,7 @@ Calculates the sum of array elements. .. ocv:pyoldfunction:: cv.Sum(arr) -> scalar - :param arr: Source array that must have from 1 to 4 channels. + :param arr: input array that must have from 1 to 4 channels. The functions ``sum`` calculate and return the sum of array elements, independently for each channel. diff --git a/modules/features2d/doc/feature_detection_and_description.rst b/modules/features2d/doc/feature_detection_and_description.rst index 8c284e63bd..6560827806 100644 --- a/modules/features2d/doc/feature_detection_and_description.rst +++ b/modules/features2d/doc/feature_detection_and_description.rst @@ -4,18 +4,18 @@ Feature Detection and Description .. highlight:: cpp FAST --------- +---- Detects corners using the FAST algorithm .. ocv:function:: void FAST( InputArray image, vector& keypoints, int threshold, bool nonmaxSupression=true, type=FastFeatureDetector::TYPE_9_16 ) - :param image: Image where keypoints (corners) are detected. + :param image: grayscale image where keypoints (corners) are detected. - :param keypoints: Keypoints detected on the image. + :param keypoints: keypoints detected on the image. - :param threshold: Threshold on difference between intensity of the central pixel and pixels on a circle around this pixel. See the algorithm description below. + :param threshold: threshold on difference between intensity of the central pixel and pixels of a circle around this pixel. - :param nonmaxSupression: If it is true, non-maximum suppression is applied to detected corners (keypoints). + :param nonmaxSupression: if true, non-maximum suppression is applied to detected corners (keypoints). :param type: one of the three neighborhoods as defined in the paper: ``FastFeatureDetector::TYPE_9_16``, ``FastFeatureDetector::TYPE_7_12``, ``FastFeatureDetector::TYPE_5_8`` diff --git a/modules/imgproc/doc/feature_detection.rst b/modules/imgproc/doc/feature_detection.rst index f5fba807d0..df1a193076 100644 --- a/modules/imgproc/doc/feature_detection.rst +++ b/modules/imgproc/doc/feature_detection.rst @@ -17,17 +17,17 @@ Finds edges in an image using the [Canny86]_ algorithm. .. ocv:pyoldfunction:: cv.Canny(image, edges, threshold1, threshold2, aperture_size=3) -> None - :param image: Single-channel 8-bit input image. + :param image: single-channel 8-bit input image. - :param edges: Output edge map. It has the same size and type as ``image`` . + :param edges: output edge map; it has the same size and type as ``image`` . - :param threshold1: First threshold for the hysteresis procedure. + :param threshold1: first threshold for the hysteresis procedure. - :param threshold2: Second threshold for the hysteresis procedure. + :param threshold2: second threshold for the hysteresis procedure. - :param apertureSize: Aperture size for the :ocv:func:`Sobel` operator. + :param apertureSize: aperture size for the :ocv:func:`Sobel` operator. - :param L2gradient: Flag indicating whether a more accurate :math:`L_2` norm :math:`=\sqrt{(dI/dx)^2 + (dI/dy)^2}` should be used to compute the image gradient magnitude ( ``L2gradient=true`` ), or a faster default :math:`L_1` norm :math:`=|dI/dx|+|dI/dy|` is enough ( ``L2gradient=false`` ). + :param L2gradient: a flag, indicating whether a more accurate :math:`L_2` norm :math:`=\sqrt{(dI/dx)^2 + (dI/dy)^2}` should be used to calculate the image gradient magnitude ( ``L2gradient=true`` ), or whether the default :math:`L_1` norm :math:`=|dI/dx|+|dI/dy|` is enough ( ``L2gradient=false`` ). The function finds edges in the input image ``image`` and marks them in the output map ``edges`` using the Canny algorithm. The smallest value between ``threshold1`` and ``threshold2`` is used for edge linking. The largest value is used to find initial segments of strong edges. See http://en.wikipedia.org/wiki/Canny_edge_detector diff --git a/modules/imgproc/doc/filtering.rst b/modules/imgproc/doc/filtering.rst index 8b7378043a..5f4e0438f3 100644 --- a/modules/imgproc/doc/filtering.rst +++ b/modules/imgproc/doc/filtering.rst @@ -411,22 +411,22 @@ This filter does not work inplace. blur --------- -Smoothes an image using the normalized box filter. +---- +Blurs an image using the normalized box filter. .. ocv:function:: void blur( InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT ) .. ocv:pyfunction:: cv2.blur(src, ksize[, dst[, anchor[, borderType]]]) -> dst - :param src: Source image. The image can have any number of channels, which are processed independently. The depth should be ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F`` or ``CV_64F``. + :param src: input image; it can have any number of channels, which are processed independently, but the depth should be ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F`` or ``CV_64F``. - :param dst: Destination image of the same size and type as ``src`` . + :param dst: output image of the same size and type as ``src``. - :param ksize: Smoothing kernel size. + :param ksize: blurring kernel size. - :param anchor: Anchor point. The default value ``Point(-1,-1)`` means that the anchor is at the kernel center. + :param anchor: anchor point; default value ``Point(-1,-1)`` means that the anchor is at the kernel center. - :param borderType: Border mode used to extrapolate pixels outside of the image. + :param borderType: border mode used to extrapolate pixels outside of the image. The function smoothes an image using the kernel: @@ -445,7 +445,7 @@ The call ``blur(src, dst, ksize, anchor, borderType)`` is equivalent to ``boxFil borderInterpolate ---------------------- +----------------- Computes the source location of an extrapolated pixel. .. ocv:function:: int borderInterpolate( int p, int len, int borderType ) @@ -476,24 +476,24 @@ Normally, the function is not called directly. It is used inside boxFilter -------------- -Smoothes an image using the box filter. +--------- +Blurs an image using the box filter. .. ocv:function:: void boxFilter( InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-1,-1), bool normalize=true, int borderType=BORDER_DEFAULT ) .. ocv:pyfunction:: cv2.boxFilter(src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]]) -> dst - :param src: Source image. + :param src: input image. - :param dst: Destination image of the same size and type as ``src`` . + :param dst: output image of the same size and type as ``src``. - :param ksize: Smoothing kernel size. + :param ksize: blurring kernel size. - :param anchor: Anchor point. The default value ``Point(-1,-1)`` means that the anchor is at the kernel center. + :param anchor: anchor point; default value ``Point(-1,-1)`` means that the anchor is at the kernel center. - :param normalize: Flag specifying whether the kernel is normalized by its area or not. + :param normalize: flag, specifying whether the kernel is normalized by its area or not. - :param borderType: Border mode used to extrapolate pixels outside of the image. + :param borderType: border mode used to extrapolate pixels outside of the image. The function smoothes an image using the kernel: @@ -520,7 +520,7 @@ Unnormalized box filter is useful for computing various integral characteristics buildPyramid ----------------- +------------ Constructs the Gaussian pyramid for an image. .. ocv:function:: void buildPyramid( InputArray src, OutputArrayOfArrays dst, int maxlevel, int borderType=BORDER_DEFAULT ) @@ -537,7 +537,7 @@ The function constructs a vector of images and builds the Gaussian pyramid by re copyMakeBorder ------------------- +-------------- Forms a border around an image. .. ocv:function:: void copyMakeBorder( InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar& value=Scalar() ) @@ -828,7 +828,7 @@ The functions construct primitive separable linear filtering operations or a fil dilate ----------- +------ Dilates an image by using a specific structuring element. .. ocv:function:: void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() ) @@ -838,19 +838,19 @@ Dilates an image by using a specific structuring element. .. ocv:cfunction:: void cvDilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 ) .. ocv:pyoldfunction:: cv.Dilate(src, dst, element=None, iterations=1)-> None - :param src: Source image. The number of channels can be arbitrary. The depth should be one of ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F` or ``CV_64F``. + :param src: input image; the number of channels can be arbitrary, but the depth should be one of ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F` or ``CV_64F``. - :param dst: Destination image of the same size and type as ``src`` . + :param dst: output image of the same size and type as ``src``. - :param element: Structuring element used for dilation. If ``element=Mat()`` , a ``3 x 3`` rectangular structuring element is used. + :param element: structuring element used for dilation; if ``element=Mat()`` , a ``3 x 3`` rectangular structuring element is used. - :param anchor: Position of the anchor within the element. The default value ``(-1, -1)`` means that the anchor is at the element center. + :param anchor: position of the anchor within the element; default value ``(-1, -1)`` means that the anchor is at the element center. - :param iterations: Number of times dilation is applied. + :param iterations: number of times dilation is applied. - :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` for details. + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). - :param borderValue: Border value in case of a constant border. The default value has a special meaning. See :ocv:func:`createMorphologyFilter` for details. + :param borderValue: border value in case of a constant border (see :ocv:func:`createMorphologyFilter` for details). The function dilates the source image using the specified structuring element that determines the shape of a pixel neighborhood over which the maximum is taken: @@ -868,7 +868,7 @@ The function supports the in-place mode. Dilation can be applied several ( ``ite erode ---------- +----- Erodes an image by using a specific structuring element. .. ocv:function:: void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() ) @@ -878,19 +878,19 @@ Erodes an image by using a specific structuring element. .. ocv:cfunction:: void cvErode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1) .. ocv:pyoldfunction:: cv.Erode(src, dst, element=None, iterations=1)-> None - :param src: Source image. The number of channels can be arbitrary. The depth should be one of ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F` or ``CV_64F``. + :param src: input image; the number of channels can be arbitrary, but the depth should be one of ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F` or ``CV_64F``. - :param dst: Destination image of the same size and type as ``src``. + :param dst: output image of the same size and type as ``src``. - :param element: Structuring element used for erosion. If ``element=Mat()`` , a ``3 x 3`` rectangular structuring element is used. + :param element: structuring element used for erosion; if ``element=Mat()`` , a ``3 x 3`` rectangular structuring element is used. - :param anchor: Position of the anchor within the element. The default value ``(-1, -1)`` means that the anchor is at the element center. + :param anchor: position of the anchor within the element; default value ``(-1, -1)`` means that the anchor is at the element center. - :param iterations: Number of times erosion is applied. + :param iterations: number of times erosion is applied. - :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` for details. + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). - :param borderValue: Border value in case of a constant border. The default value has a special meaning. See :ocv:func:`createMorphologyFilter` for details. + :param borderValue: border value in case of a constant border (see :ocv:func:`createMorphologyFilter` for details). The function erodes the source image using the specified structuring element that determines the shape of a pixel neighborhood over which the minimum is taken: @@ -909,7 +909,7 @@ The function supports the in-place mode. Erosion can be applied several ( ``iter filter2D ------------- +-------- Convolves an image with the kernel. .. ocv:function:: void filter2D( InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT ) @@ -920,25 +920,26 @@ Convolves an image with the kernel. .. ocv:pyoldfunction:: cv.Filter2D(src, dst, kernel, anchor=(-1, -1))-> None - :param src: Source image. + :param src: input image. - :param dst: Destination image of the same size and the same number of channels as ``src`` . + :param dst: output image of the same size and the same number of channels as ``src``. - :param ddepth: Desired depth of the destination image. If it is negative, it will be the same as ``src.depth()`` . The following combination of ``src.depth()`` and ``ddepth`` are supported: + + :param ddepth: desired depth of the destination image; if it is negative, it will be the same as ``src.depth()``; the following combinations of ``src.depth()`` and ``ddepth`` are supported: * ``src.depth()`` = ``CV_8U``, ``ddepth`` = -1/``CV_16S``/``CV_32F``/``CV_64F`` * ``src.depth()`` = ``CV_16U``/``CV_16S``, ``ddepth`` = -1/``CV_32F``/``CV_64F`` * ``src.depth()`` = ``CV_32F``, ``ddepth`` = -1/``CV_32F``/``CV_64F`` * ``src.depth()`` = ``CV_64F``, ``ddepth`` = -1/``CV_64F`` - when ``ddepth=-1``, the destination image will have the same depth as the source. + when ``ddepth=-1``, the output image will have the same depth as the source. - :param kernel: Convolution kernel (or rather a correlation kernel), a single-channel floating point matrix. If you want to apply different kernels to different channels, split the image into separate color planes using :ocv:func:`split` and process them individually. + :param kernel: convolution kernel (or rather a correlation kernel), a single-channel floating point matrix; if you want to apply different kernels to different channels, split the image into separate color planes using :ocv:func:`split` and process them individually. - :param anchor: Anchor of the kernel that indicates the relative position of a filtered point within the kernel. The anchor should lie within the kernel. The special default value (-1,-1) means that the anchor is at the kernel center. + :param anchor: anchor of the kernel that indicates the relative position of a filtered point within the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor is at the kernel center. - :param delta: Optional value added to the filtered pixels before storing them in ``dst`` . + :param delta: optional value added to the filtered pixels before storing them in ``dst``. - :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` for details. + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). The function applies an arbitrary linear filter to an image. In-place operation is supported. When the aperture is partially outside the image, the function interpolates outlier pixel values according to the specified border mode. @@ -963,24 +964,24 @@ The function uses the DFT-based algorithm in case of sufficiently large kernels GaussianBlur ----------------- -Smoothes an image using a Gaussian filter. +------------ +Blurs an image using a Gaussian filter. .. ocv:function:: void GaussianBlur( InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT ) .. ocv:pyfunction:: cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) -> dst - :param src: Source image. The image can have any number of channels, which are processed independently. The depth should be ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F`` or ``CV_64F``. + :param src: input image; the image can have any number of channels, which are processed independently, but the depth should be ``CV_8U``, ``CV_16U``, ``CV_16S``, ``CV_32F`` or ``CV_64F``. - :param dst: Destination image of the same size and type as ``src`` . + :param dst: output image of the same size and type as ``src``. :param ksize: Gaussian kernel size. ``ksize.width`` and ``ksize.height`` can differ but they both must be positive and odd. Or, they can be zero's and then they are computed from ``sigma*`` . :param sigmaX: Gaussian kernel standard deviation in X direction. - :param sigmaY: Gaussian kernel standard deviation in Y direction. If ``sigmaY`` is zero, it is set to be equal to ``sigmaX`` . If both sigmas are zeros, they are computed from ``ksize.width`` and ``ksize.height`` , respectively. See :ocv:func:`getGaussianKernel` for details. To fully control the result regardless of possible future modifications of all this semantics, it is recommended to specify all of ``ksize`` , ``sigmaX`` , and ``sigmaY`` . + :param sigmaY: Gaussian kernel standard deviation in Y direction; if ``sigmaY`` is zero, it is set to be equal to ``sigmaX``, if both sigmas are zeros, they are computed from ``ksize.width`` and ``ksize.height`` , respectively (see :ocv:func:`getGaussianKernel` for details); to fully control the result regardless of possible future modifications of all this semantics, it is recommended to specify all of ``ksize``, ``sigmaX``, and ``sigmaY``. - :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` for details. + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). The function convolves the source image with the specified Gaussian kernel. In-place filtering is supported. @@ -995,7 +996,7 @@ The function convolves the source image with the specified Gaussian kernel. In-p getDerivKernels -------------------- +--------------- Returns filter coefficients for computing spatial image derivatives. .. ocv:function:: void getDerivKernels( OutputArray kx, OutputArray ky, int dx, int dy, int ksize, bool normalize=false, int ktype=CV_32F ) @@ -1026,7 +1027,7 @@ The function computes and returns the filter coefficients for spatial image deri getGaussianKernel ---------------------- +----------------- Returns Gaussian filter coefficients. .. ocv:function:: Mat getGaussianKernel( int ksize, double sigma, int ktype=CV_64F ) @@ -1066,7 +1067,7 @@ Two of such generated kernels can be passed to getKernelType ------------------ +------------- Returns the kernel type. .. ocv:function:: int getKernelType(InputArray kernel, Point anchor) @@ -1089,7 +1090,7 @@ The function analyzes the kernel coefficients and returns the corresponding kern getStructuringElement -------------------------- +--------------------- Returns a structuring element of the specified size and shape for morphological operations. .. ocv:function:: Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1)) @@ -1142,18 +1143,18 @@ The function constructs and returns the structuring element that can be further medianBlur --------------- -Smoothes an image using the median filter. +---------- +Blurs an image using the median filter. .. ocv:function:: void medianBlur( InputArray src, OutputArray dst, int ksize ) .. ocv:pyfunction:: cv2.medianBlur(src, ksize[, dst]) -> dst - :param src: Source 1-, 3-, or 4-channel image. When ``ksize`` is 3 or 5, the image depth should be ``CV_8U`` , ``CV_16U`` , or ``CV_32F`` . For larger aperture sizes, it can only be ``CV_8U`` . + :param src: input 1-, 3-, or 4-channel image; when ``ksize`` is 3 or 5, the image depth should be ``CV_8U``, ``CV_16U``, or ``CV_32F``, for larger aperture sizes, it can only be ``CV_8U``. - :param dst: Destination array of the same size and type as ``src`` . + :param dst: destination array of the same size and type as ``src``. - :param ksize: Aperture linear size. It must be odd and greater than 1, for example: 3, 5, 7 ... + :param ksize: aperture linear size; it must be odd and greater than 1, for example: 3, 5, 7 ... The function smoothes an image using the median filter with the :math:`\texttt{ksize} \times \texttt{ksize}` aperture. Each channel of a multi-channel image is processed independently. In-place operation is supported. @@ -1168,7 +1169,7 @@ The function smoothes an image using the median filter with the morphologyEx ----------------- +------------ Performs advanced morphological transformations. .. ocv:function:: void morphologyEx( InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() ) @@ -1244,7 +1245,7 @@ Any of the operations can be done in-place. In case of multi-channel images, eac Laplacian -------------- +--------- Calculates the Laplacian of an image. .. ocv:function:: void Laplacian( InputArray src, OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, int borderType=BORDER_DEFAULT ) @@ -1290,8 +1291,8 @@ This is done when ``ksize > 1`` . When ``ksize == 1`` , the Laplacian is compute pyrDown ------------ -Smoothes an image and downsamples it. +------- +Blurs an image and downsamples it. .. ocv:function:: void pyrDown( InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT ) @@ -1301,11 +1302,11 @@ Smoothes an image and downsamples it. .. ocv:pyoldfunction:: cv.PyrDown(src, dst, filter=CV_GAUSSIAN_5X5) -> None - :param src: Source image. + :param src: input image. - :param dst: Destination image. It has the specified size and the same type as ``src`` . + :param dst: output image; it has the specified size and the same type as ``src``. - :param dstsize: Size of the destination image. By default, it is computed as ``Size((src.cols+1)/2, (src.rows+1)/2)`` . But in any case, the following conditions should be satisfied: + :param dstsize: size of the output image; by default, it is computed as ``Size((src.cols+1)/2, (src.rows+1)/2)``, but in any case, the following conditions should be satisfied: .. math:: @@ -1323,8 +1324,8 @@ Then, it downsamples the image by rejecting even rows and columns. pyrUp ---------- -Upsamples an image and then smoothes it. +----- +Upsamples an image and then blurs it. .. ocv:function:: void pyrUp( InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT ) @@ -1334,18 +1335,18 @@ Upsamples an image and then smoothes it. .. ocv:pyoldfunction:: cv.PyrUp(src, dst, filter=CV_GAUSSIAN_5X5) -> None - :param src: Source image. + :param src: input image. - :param dst: Destination image. It has the specified size and the same type as ``src`` . + :param dst: output image. It has the specified size and the same type as ``src`` . - :param dstsize: Size of the destination image. By default, it is computed as ``Size(src.cols*2, (src.rows*2)`` . But in any case, the following conditions should be satisfied: + :param dstsize: size of the output image; by default, it is computed as ``Size(src.cols*2, (src.rows*2)``, but in any case, the following conditions should be satisfied: .. math:: \begin{array}{l} | \texttt{dstsize.width} -src.cols*2| \leq ( \texttt{dstsize.width} \mod 2) \\ | \texttt{dstsize.height} -src.rows*2| \leq ( \texttt{dstsize.height} \mod 2) \end{array} -The function performs the upsampling step of the Gaussian pyramid construction though it can actually be used to construct the Laplacian pyramid. First, it upsamples the source image by injecting even zero rows and columns and then convolves the result with the same kernel as in +The function performs the upsampling step of the Gaussian pyramid construction, though it can actually be used to construct the Laplacian pyramid. First, it upsamples the source image by injecting even zero rows and columns and then convolves the result with the same kernel as in :ocv:func:`pyrDown` multiplied by 4. @@ -1399,7 +1400,7 @@ When ``maxLevel > 0``, the gaussian pyramid of ``maxLevel+1`` levels is built, a sepFilter2D ---------------- +----------- Applies a separable linear filter to an image. .. ocv:function:: void sepFilter2D( InputArray src, OutputArray dst, int ddepth, InputArray kernelX, InputArray kernelY, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT ) @@ -1493,7 +1494,7 @@ The function smooths an image using one of several methods. Every of the methods Sobel ---------- +----- Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator. .. ocv:function:: void Sobel( InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize=3, double scale=1, double delta=0, int borderType=BORDER_DEFAULT ) @@ -1504,29 +1505,29 @@ Calculates the first, second, third, or mixed image derivatives using an extende .. ocv:pyoldfunction:: cv.Sobel(src, dst, xorder, yorder, apertureSize=3)-> None - :param src: Source image. + :param src: input image. - :param dst: Destination image of the same size and the same number of channels as ``src`` . + :param dst: output image of the same size and the same number of channels as ``src`` . - :param ddepth: Destination image depth. The following combination of ``src.depth()`` and ``ddepth`` are supported: + :param ddepth: output image depth; the following combinations of ``src.depth()`` and ``ddepth`` are supported: * ``src.depth()`` = ``CV_8U``, ``ddepth`` = -1/``CV_16S``/``CV_32F``/``CV_64F`` * ``src.depth()`` = ``CV_16U``/``CV_16S``, ``ddepth`` = -1/``CV_32F``/``CV_64F`` * ``src.depth()`` = ``CV_32F``, ``ddepth`` = -1/``CV_32F``/``CV_64F`` * ``src.depth()`` = ``CV_64F``, ``ddepth`` = -1/``CV_64F`` - when ``ddepth=-1``, the destination image will have the same depth as the source. In the case of 8-bit input images it will result in truncated derivatives. + when ``ddepth=-1``, the destination image will have the same depth as the source; in the case of 8-bit input images it will result in truncated derivatives. - :param xorder: Order of the derivative x. + :param xorder: order of the derivative x. - :param yorder: Order of the derivative y. + :param yorder: order of the derivative y. - :param ksize: Size of the extended Sobel kernel. It must be 1, 3, 5, or 7. + :param ksize: size of the extended Sobel kernel; it must be 1, 3, 5, or 7. - :param scale: Optional scale factor for the computed derivative values. By default, no scaling is applied. See :ocv:func:`getDerivKernels` for details. + :param scale: optional scale factor for the computed derivative values; by default, no scaling is applied (see :ocv:func:`getDerivKernels` for details). - :param delta: Optional delta value that is added to the results prior to storing them in ``dst`` . + :param delta: optional delta value that is added to the results prior to storing them in ``dst``. - :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` for details. + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). In all cases except one, the :math:`\texttt{ksize} \times @@ -1580,28 +1581,28 @@ The second case corresponds to a kernel of: Scharr ----------- +------ Calculates the first x- or y- image derivative using Scharr operator. .. ocv:function:: void Scharr( InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale=1, double delta=0, int borderType=BORDER_DEFAULT ) .. ocv:pyfunction:: cv2.Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]]) -> dst - :param src: Source image. + :param src: input image. - :param dst: Destination image of the same size and the same number of channels as ``src``. + :param dst: output image of the same size and the same number of channels as ``src``. - :param ddepth: Destination image depth. See :ocv:func:`Sobel` for the list of supported combination of ``src.depth()`` and ``ddepth``. + :param ddepth: output image depth (see :ocv:func:`Sobel` for the list of supported combination of ``src.depth()`` and ``ddepth``). - :param dx: Order of the derivative x. + :param dx: order of the derivative x. - :param dy: Order of the derivative y. + :param dy: order of the derivative y. - :param scale: Optional scale factor for the computed derivative values. By default, no scaling is applied. See :ocv:func:`getDerivKernels` for details. + :param scale: optional scale factor for the computed derivative values; by default, no scaling is applied (see :ocv:func:`getDerivKernels` for details). - :param delta: Optional delta value that is added to the results prior to storing them in ``dst``. + :param delta: optional delta value that is added to the results prior to storing them in ``dst``. - :param borderType: Pixel extrapolation method. See :ocv:func:`borderInterpolate` for details. + :param borderType: pixel extrapolation method (see :ocv:func:`borderInterpolate` for details). The function computes the first x- or y- spatial image derivative using the Scharr operator. The call diff --git a/modules/imgproc/doc/geometric_transformations.rst b/modules/imgproc/doc/geometric_transformations.rst index 998a077040..c48da01d7e 100644 --- a/modules/imgproc/doc/geometric_transformations.rst +++ b/modules/imgproc/doc/geometric_transformations.rst @@ -356,7 +356,7 @@ This function cannot operate in-place. resize ----------- +------ Resizes an image. .. ocv:function:: void resize( InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR ) @@ -366,11 +366,11 @@ Resizes an image. .. ocv:cfunction:: void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR ) .. ocv:pyoldfunction:: cv.Resize(src, dst, interpolation=CV_INTER_LINEAR)-> None - :param src: Source image. + :param src: input image. - :param dst: Destination image. It has the size ``dsize`` (when it is non-zero) or the size computed from ``src.size()`` , ``fx`` , and ``fy`` . The type of ``dst`` is the same as of ``src`` . + :param dst: output image; it has the size ``dsize`` (when it is non-zero) or the size computed from ``src.size()``, ``fx``, and ``fy``; the type of ``dst`` is the same as of ``src``. - :param dsize: Destination image size. If it is zero, it is computed as: + :param dsize: output image size; if it equals zero, it is computed as: .. math:: @@ -379,19 +379,19 @@ Resizes an image. Either ``dsize`` or both ``fx`` and ``fy`` must be non-zero. - :param fx: Scale factor along the horizontal axis. When it is 0, it is computed as + :param fx: scale factor along the horizontal axis; when it equals 0, it is computed as .. math:: \texttt{(double)dsize.width/src.cols} - :param fy: Scale factor along the vertical axis. When it is 0, it is computed as + :param fy: scale factor along the vertical axis; when it equals 0, it is computed as .. math:: \texttt{(double)dsize.height/src.rows} - :param interpolation: Interpolation method: + :param interpolation: interpolation method: * **INTER_NEAREST** - a nearest-neighbor interpolation @@ -425,7 +425,7 @@ To shrink an image, it will generally look best with CV_INTER_AREA interpolation warpAffine --------------- +---------- Applies an affine transformation to an image. .. ocv:function:: void warpAffine( InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar()) @@ -440,19 +440,19 @@ Applies an affine transformation to an image. .. ocv:pyoldfunction:: cv.GetQuadrangleSubPix(src, dst, mapMatrix)-> None - :param src: Source image. + :param src: input image. - :param dst: Destination image that has the size ``dsize`` and the same type as ``src`` . + :param dst: output image that has the size ``dsize`` and the same type as ``src`` . - :param M: :math:`2\times 3` transformation matrix. + :param M: :math:`2\times 3` transformation matrix. - :param dsize: Size of the destination image. + :param dsize: size of the output image. - :param flags: Combination of interpolation methods (see :ocv:func:`resize` ) and the optional flag ``WARP_INVERSE_MAP`` that means that ``M`` is the inverse transformation ( :math:`\texttt{dst}\rightarrow\texttt{src}` ). + :param flags: combination of interpolation methods (see :ocv:func:`resize` ) and the optional flag ``WARP_INVERSE_MAP`` that means that ``M`` is the inverse transformation ( :math:`\texttt{dst}\rightarrow\texttt{src}` ). - :param borderMode: Pixel extrapolation method (see :ocv:func:`borderInterpolate` ). When \ ``borderMode=BORDER_TRANSPARENT`` , it means that the pixels in the destination image corresponding to the "outliers" in the source image are not modified by the function. + :param borderMode: pixel extrapolation method (see :ocv:func:`borderInterpolate`); when \ ``borderMode=BORDER_TRANSPARENT`` , it means that the pixels in the destination image corresponding to the "outliers" in the source image are not modified by the function. - :param borderValue: Value used in case of a constant border. By default, it is 0. + :param borderValue: value used in case of a constant border; by default, it is 0. The function ``warpAffine`` transforms the source image using the specified matrix: @@ -476,7 +476,7 @@ The function cannot operate in-place. .. note:: ``cvGetQuadrangleSubPix`` is similar to ``cvWarpAffine``, but the outliers are extrapolated using replication border mode. warpPerspective -------------------- +--------------- Applies a perspective transformation to an image. .. ocv:function:: void warpPerspective( InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar()) @@ -487,19 +487,19 @@ Applies a perspective transformation to an image. .. ocv:pyoldfunction:: cv.WarpPerspective(src, dst, mapMatrix, flags=CV_INNER_LINEAR+CV_WARP_FILL_OUTLIERS, fillval=(0, 0, 0, 0))-> None - :param src: Source image. + :param src: input image. - :param dst: Destination image that has the size ``dsize`` and the same type as ``src`` . + :param dst: output image that has the size ``dsize`` and the same type as ``src`` . :param M: :math:`3\times 3` transformation matrix. - :param dsize: Size of the destination image. + :param dsize: size of the output image. - :param flags: Combination of interpolation methods (see :ocv:func:`resize` ) and the optional flag ``WARP_INVERSE_MAP`` that means that ``M`` is the inverse transformation ( :math:`\texttt{dst}\rightarrow\texttt{src}` ). + :param flags: combination of interpolation methods (``INTER_LINEAR`` or ``INTER_NEAREST``) and the optional flag ``WARP_INVERSE_MAP``, that sets ``M`` as the inverse transformation ( :math:`\texttt{dst}\rightarrow\texttt{src}` ). - :param borderMode: Pixel extrapolation method (see :ocv:func:`borderInterpolate` ). When \ ``borderMode=BORDER_TRANSPARENT`` , it means that the pixels in the destination image that corresponds to the "outliers" in the source image are not modified by the function. + :param borderMode: pixel extrapolation method (``BORDER_CONSTANT`` or ``BORDER_REPLICATE``). - :param borderValue: Value used in case of a constant border. By default, it is 0. + :param borderValue: value used in case of a constant border; by default, it equals 0. The function ``warpPerspective`` transforms the source image using the specified matrix: @@ -524,7 +524,7 @@ The function cannot operate in-place. initUndistortRectifyMap ---------------------------- +----------------------- Computes the undistortion and rectification transformation map. .. ocv:function:: void initUndistortRectifyMap( InputArray cameraMatrix, InputArray distCoeffs, InputArray R, InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2 ) diff --git a/modules/imgproc/doc/miscellaneous_transformations.rst b/modules/imgproc/doc/miscellaneous_transformations.rst index 2707e3babb..9b0ee6d0ab 100644 --- a/modules/imgproc/doc/miscellaneous_transformations.rst +++ b/modules/imgproc/doc/miscellaneous_transformations.rst @@ -71,7 +71,7 @@ The function can process the image in-place. cvtColor ------------- +-------- Converts an image from one color space to another. .. ocv:function:: void cvtColor( InputArray src, OutputArray dst, int code, int dstCn=0 ) @@ -81,13 +81,13 @@ Converts an image from one color space to another. .. ocv:cfunction:: void cvCvtColor( const CvArr* src, CvArr* dst, int code ) .. ocv:pyoldfunction:: cv.CvtColor(src, dst, code)-> None - :param src: Source image: 8-bit unsigned, 16-bit unsigned ( ``CV_16UC...`` ), or single-precision floating-point. + :param src: input image: 8-bit unsigned, 16-bit unsigned ( ``CV_16UC...`` ), or single-precision floating-point. - :param dst: Destination image of the same size and depth as ``src`` . + :param dst: output image of the same size and depth as ``src``. - :param code: Color space conversion code. See the description below. + :param code: color space conversion code (see the description below). - :param dstCn: Number of channels in the destination image. If the parameter is 0, the number of the channels is derived automatically from ``src`` and ``code`` . + :param dstCn: number of channels in the destination image; if the parameter is 0, the number of the channels is derived automatically from ``src`` and ``code`` . The function converts an input image from one color space to another. In case of a transformation to-from RGB color space, the order of the channels should be specified explicitly (RGB or BGR). @@ -408,7 +408,7 @@ The function can do the following transformations: distanceTransform ---------------------- +----------------- Calculates the distance to the closest zero pixel for each pixel of the source image. .. ocv:function:: void distanceTransform( InputArray src, OutputArray dst, int distanceType, int maskSize ) @@ -481,7 +481,7 @@ That is, the function provides a very fast way to compute the Voronoi diagram fo Currently, the second variant can use only the approximate distance transform algorithm, i.e. ``maskSize=CV_DIST_MASK_PRECISE`` is not supported yet. floodFill -------------- +--------- Fills a connected component with the given color. .. ocv:function:: int floodFill( InputOutputArray image, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 ) @@ -586,7 +586,7 @@ Use these functions to either mark a connected component with the specified colo integral ------------- +-------- Calculates the integral of an image. .. ocv:function:: void integral( InputArray src, OutputArray sum, int sdepth=-1 ) @@ -605,15 +605,15 @@ Calculates the integral of an image. .. ocv:pyoldfunction:: cv.Integral(image, sum, sqsum=None, tiltedSum=None)-> None - :param image: Source image as :math:`W \times H` , 8-bit or floating-point (32f or 64f). + :param image: input image as :math:`W \times H`, 8-bit or floating-point (32f or 64f). - :param sum: Integral image as :math:`(W+1)\times (H+1)` , 32-bit integer or floating-point (32f or 64f). + :param sum: integral image as :math:`(W+1)\times (H+1)` , 32-bit integer or floating-point (32f or 64f). - :param sqsum: Integral image for squared pixel values. It is :math:`(W+1)\times (H+1)`, double-precision floating-point (64f) array. + :param sqsum: integral image for squared pixel values; it is :math:`(W+1)\times (H+1)`, double-precision floating-point (64f) array. - :param tilted: Integral for the image rotated by 45 degrees. It is :math:`(W+1)\times (H+1)` array with the same data type as ``sum``. + :param tilted: integral for the image rotated by 45 degrees; it is :math:`(W+1)\times (H+1)` array with the same data type as ``sum``. - :param sdepth: Desired depth of the integral and the tilted integral images, ``CV_32S``, ``CV_32F``, or ``CV_64F``. + :param sdepth: desired depth of the integral and the tilted integral images, ``CV_32S``, ``CV_32F``, or ``CV_64F``. The functions calculate one or more integral images for the source image as follows: @@ -646,7 +646,7 @@ As a practical example, the next figure shows the calculation of the integral of threshold -------------- +--------- Applies a fixed-level threshold to each array element. .. ocv:function:: double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type ) @@ -657,15 +657,15 @@ Applies a fixed-level threshold to each array element. .. ocv:pyoldfunction:: cv.Threshold(src, dst, threshold, maxValue, thresholdType)-> None - :param src: Source array (single-channel, 8-bit or 32-bit floating point). + :param src: input array (single-channel, 8-bit or 32-bit floating point). - :param dst: Destination array of the same size and type as ``src`` . + :param dst: output array of the same size and type as ``src``. - :param thresh: Threshold value. + :param thresh: treshold value. - :param maxval: Maximum value to use with the ``THRESH_BINARY`` and ``THRESH_BINARY_INV`` thresholding types. + :param maxval: maximum value to use with the ``THRESH_BINARY`` and ``THRESH_BINARY_INV`` thresholding types. - :param type: Thresholding type (see the details below). + :param type: thresholding type (see the details below). The function applies fixed-level thresholding to a single-channel array. The function is typically used to get a @@ -724,7 +724,7 @@ Currently, the Otsu's method is implemented only for 8-bit images. watershed -------------- +--------- Performs a marker-based image segmentation using the watershed algorithm. .. ocv:function:: void watershed( InputArray image, InputOutputArray markers ) diff --git a/modules/stitching/doc/matching.rst b/modules/stitching/doc/matching.rst index c58eb2cc7d..2f9dabf728 100644 --- a/modules/stitching/doc/matching.rst +++ b/modules/stitching/doc/matching.rst @@ -204,11 +204,11 @@ This method must implement matching logic in order to make the wrappers `detail: .. ocv:function:: void detail::FeaturesMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info) - :param features1: First image features + :param features1: first image features - :param features2: Second image features + :param features2: second image features - :param matches_info: Found matches + :param matches_info: found matches detail::BestOf2NearestMatcher ----------------------------- diff --git a/modules/video/doc/motion_analysis_and_object_tracking.rst b/modules/video/doc/motion_analysis_and_object_tracking.rst index aa4e200c90..6c196c2ff1 100644 --- a/modules/video/doc/motion_analysis_and_object_tracking.rst +++ b/modules/video/doc/motion_analysis_and_object_tracking.rst @@ -15,30 +15,30 @@ Calculates an optical flow for a sparse feature set using the iterative Lucas-Ka .. ocv:cfunction:: void cvCalcOpticalFlowPyrLK( const CvArr* prev, const CvArr* curr, CvArr* prev_pyr, CvArr* curr_pyr, const CvPoint2D32f* prev_features, CvPoint2D32f* curr_features, int count, CvSize win_size, int level, char* status, float* track_error, CvTermCriteria criteria, int flags ) .. ocv:pyoldfunction:: cv.CalcOpticalFlowPyrLK(prev, curr, prevPyr, currPyr, prevFeatures, winSize, level, criteria, flags, guesses=None) -> (currFeatures, status, track_error) - :param prevImg: First 8-bit input image or pyramid constructed by :ocv:func:`buildOpticalFlowPyramid`. + :param prevImg: first 8-bit input image or pyramid constructed by :ocv:func:`buildOpticalFlowPyramid`. - :param nextImg: Second input image or pyramid of the same size and the same type as ``prevImg``. + :param nextImg: second input image or pyramid of the same size and the same type as ``prevImg``. - :param prevPts: Vector of 2D points for which the flow needs to be found. The point coordinates must be single-precision floating-point numbers. + :param prevPts: vector of 2D points for which the flow needs to be found; point coordinates must be single-precision floating-point numbers. - :param nextPts: Output vector of 2D points (with single-precision floating-point coordinates) containing the calculated new positions of input features in the second image. When ``OPTFLOW_USE_INITIAL_FLOW`` flag is passed, the vector must have the same size as in the input. + :param nextPts: output vector of 2D points (with single-precision floating-point coordinates) containing the calculated new positions of input features in the second image; when ``OPTFLOW_USE_INITIAL_FLOW`` flag is passed, the vector must have the same size as in the input. - :param status: Output status vector. Each element of the vector is set to 1 if the flow for the corresponding features has been found. Otherwise, it is set to 0. + :param status: output status vector; each element of the vector is set to 1 if the flow for the corresponding features has been found, otherwise, it is set to 0. - :param err: Output vector of errors. Each element of the vector is set to a error for the corresponding feature. A type of the error measure can be set in ``flags`` parameter. If the flow wasn't found then the error is not defined (use the ``status`` parameter to find such cases). + :param err: output vector of errors; each element of the vector is set to an error for the corresponding feature, type of the error measure can be set in ``flags`` parameter; if the flow wasn't found then the error is not defined (use the ``status`` parameter to find such cases). - :param winSize: Size of the search window at each pyramid level. + :param winSize: size of the search window at each pyramid level. - :param maxLevel: 0-based maximal pyramid level number. If set to 0, pyramids are not used (single level). If set to 1, two levels are used, and so on. If pyramids are passed to input then algorithm will use as many levels as pyramids have but no more than ``maxLevel``. + :param maxLevel: 0-based maximal pyramid level number; if set to 0, pyramids are not used (single level), if set to 1, two levels are used, and so on; if pyramids are passed to input then algorithm will use as many levels as pyramids have but no more than ``maxLevel``. - :param criteria: Parameter specifying the termination criteria of the iterative search algorithm (after the specified maximum number of iterations ``criteria.maxCount`` or when the search window moves by less than ``criteria.epsilon`` . + :param criteria: parameter, specifying the termination criteria of the iterative search algorithm (after the specified maximum number of iterations ``criteria.maxCount`` or when the search window moves by less than ``criteria.epsilon``. - :param flags: Operation flags: + :param flags: operation flags: - * **OPTFLOW_USE_INITIAL_FLOW** Use initial estimations stored in ``nextPts`` . If the flag is not set, then ``prevPts`` is copied to ``nextPts`` and is considered as the initial estimate. - * **OPTFLOW_LK_GET_MIN_EIGENVALS** Use minimum eigen values as a error measure (see ``minEigThreshold`` description). If the flag is not set, then L1 distance between patches around the original and a moved point divided by number of pixels in a window is used as a error measure. + * **OPTFLOW_USE_INITIAL_FLOW** uses initial estimations, stored in ``nextPts``; if the flag is not set, then ``prevPts`` is copied to ``nextPts`` and is considered the initial estimate. + * **OPTFLOW_LK_GET_MIN_EIGENVALS** use minimum eigen values as an error measure (see ``minEigThreshold`` description); if the flag is not set, then L1 distance between patches around the original and a moved point, divided by number of pixels in a window, is used as a error measure. - :param minEigThreshold: The algorithm computes a minimum eigen value of a 2x2 normal matrix of optical flow equations (this matrix is called a spatial gradient matrix in [Bouguet00]_) divided by number of pixels in a window. If this value is less then ``minEigThreshold`` then a corresponding feature is filtered out and its flow is not computed. So it allows to remove bad points earlier and speed up the computation. + :param minEigThreshold: the algorithm calculates the minimum eigen value of a 2x2 normal matrix of optical flow equations (this matrix is called a spatial gradient matrix in [Bouguet00]_), divided by number of pixels in a window; if this value is less than ``minEigThreshold``, then a corresponding feature is filtered out and its flow is not processed, so it allows to remove bad points and get a performance boost. The function implements a sparse iterative version of the Lucas-Kanade optical flow in pyramids. See [Bouguet00]_. The function is parallelized with the TBB library. @@ -79,29 +79,29 @@ Computes a dense optical flow using the Gunnar Farneback's algorithm. .. ocv:pyfunction:: cv2.calcOpticalFlowFarneback(prev, next, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags[, flow]) -> flow - :param prev: First 8-bit single-channel input image. + :param prev: first 8-bit single-channel input image. - :param next: Second input image of the same size and the same type as ``prev`` . + :param next: second input image of the same size and the same type as ``prev``. - :param flow: Computed flow image that has the same size as ``prev`` and type ``CV_32FC2`` . + :param flow: computed flow image that has the same size as ``prev`` and type ``CV_32FC2``. - :param pyr_scale: Parameter specifying the image scale (<1) to build pyramids for each image. ``pyr_scale=0.5`` means a classical pyramid, where each next layer is twice smaller than the previous one. + :param pyr_scale: parameter, specifying the image scale (<1) to build pyramids for each image; ``pyr_scale=0.5`` means a classical pyramid, where each next layer is twice smaller than the previous one. - :param levels: Number of pyramid layers including the initial image. ``levels=1`` means that no extra layers are created and only the original images are used. + :param levels: number of pyramid layers including the initial image; ``levels=1`` means that no extra layers are created and only the original images are used. - :param winsize: Averaging window size. Larger values increase the algorithm robustness to image noise and give more chances for fast motion detection, but yield more blurred motion field. + :param winsize: averaging window size; larger values increase the algorithm robustness to image noise and give more chances for fast motion detection, but yield more blurred motion field. - :param iterations: Number of iterations the algorithm does at each pyramid level. + :param iterations: number of iterations the algorithm does at each pyramid level. - :param poly_n: Size of the pixel neighborhood used to find polynomial expansion in each pixel. Larger values mean that the image will be approximated with smoother surfaces, yielding more robust algorithm and more blurred motion field. Typically, ``poly_n`` =5 or 7. + :param poly_n: size of the pixel neighborhood used to find polynomial expansion in each pixel; larger values mean that the image will be approximated with smoother surfaces, yielding more robust algorithm and more blurred motion field, typically ``poly_n`` =5 or 7. - :param poly_sigma: Standard deviation of the Gaussian that is used to smooth derivatives used as a basis for the polynomial expansion. For ``poly_n=5`` , you can set ``poly_sigma=1.1`` . For ``poly_n=7`` , a good value would be ``poly_sigma=1.5`` . + :param poly_sigma: standard deviation of the Gaussian that is used to smooth derivatives used as a basis for the polynomial expansion; for ``poly_n=5``, you can set ``poly_sigma=1.1``, for ``poly_n=7``, a good value would be ``poly_sigma=1.5``. - :param flags: Operation flags that can be a combination of the following: + :param flags: operation flags that can be a combination of the following: - * **OPTFLOW_USE_INITIAL_FLOW** Use the input ``flow`` as an initial flow approximation. + * **OPTFLOW_USE_INITIAL_FLOW** uses the input ``flow`` as an initial flow approximation. - * **OPTFLOW_FARNEBACK_GAUSSIAN** Use the Gaussian :math:`\texttt{winsize}\times\texttt{winsize}` filter instead of a box filter of the same size for optical flow estimation. Usually, this option gives z more accurate flow than with a box filter, at the cost of lower speed. Normally, ``winsize`` for a Gaussian window should be set to a larger value to achieve the same level of robustness. + * **OPTFLOW_FARNEBACK_GAUSSIAN** uses the Gaussian :math:`\texttt{winsize}\times\texttt{winsize}` filter instead of a box filter of the same size for optical flow estimation; usually, this option gives z more accurate flow than with a box filter, at the cost of lower speed; normally, ``winsize`` for a Gaussian window should be set to a larger value to achieve the same level of robustness. The function finds an optical flow for each ``prev`` pixel using the [Farneback2003]_ algorithm so that From 1baf5209c4df292922f78e2757321c359f8b28e8 Mon Sep 17 00:00:00 2001 From: Vincent Rabaud Date: Thu, 23 Aug 2012 14:20:31 +0200 Subject: [PATCH 061/163] fix the compile bug --- modules/core/include/opencv2/core/operations.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/core/include/opencv2/core/operations.hpp b/modules/core/include/opencv2/core/operations.hpp index fe9caa41ba..932d9fbd8b 100644 --- a/modules/core/include/opencv2/core/operations.hpp +++ b/modules/core/include/opencv2/core/operations.hpp @@ -1077,9 +1077,9 @@ double norm(const Matx<_Tp, m, n>& M) template static inline double norm(const Matx<_Tp, m, n>& M, int normType) { - return normType == NORM_INF ? (double)normInf<_Tp, DataType<_Tp>::work_type>(M.val, m*n) : - normType == NORM_L1 ? (double)normL1<_Tp, DataType<_Tp>::work_type>(M.val, m*n) : - std::sqrt((double)normL2Sqr<_Tp, DataType<_Tp>::work_type>(M.val, m*n)); + return normType == NORM_INF ? (double)normInf<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n) : + normType == NORM_L1 ? (double)normL1<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n) : + std::sqrt((double)normL2Sqr<_Tp, typename DataType<_Tp>::work_type>(M.val, m*n)); } From 290030d030dc27fa4cdf476cf06d7c912c51cf36 Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Thu, 23 Aug 2012 14:05:25 +0400 Subject: [PATCH 062/163] possibility to enable /mp compiler flag from cmake fixed MCVC warnings --- CMakeLists.txt | 3 ++- cmake/OpenCVCompilerOptions.cmake | 5 +++++ modules/gpu/src/cascadeclassifier.cpp | 2 +- modules/gpu/src/cuda/ccomponetns.cu | 15 ++++++++++----- modules/gpu/src/cuda/resize.cu | 4 ++-- modules/gpu/src/fgd_bgfg.cpp | 2 +- modules/gpu/src/graphcuts.cpp | 8 ++------ modules/gpu/src/hough.cpp | 2 +- modules/imgproc/perf/perf_remap.cpp | 12 ++++++------ 9 files changed, 30 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d893f1c74d..8efc48e1c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,6 +197,8 @@ OCV_OPTION(ENABLE_SSE41 "Enable SSE4.1 instructions" OCV_OPTION(ENABLE_SSE42 "Enable SSE4.2 instructions" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_NOISY_WARNINGS "Show all warnings even if they are too noisy" OFF ) OCV_OPTION(OPENCV_WARNINGS_ARE_ERRORS "Treat warnings as errors" OFF ) +OCV_OPTION(ENABLE_MULTI_PROCESSOR_COMPILATION "Enabling multi-processory compilation" OFF IF MSVC) + # uncategorized options # =================================================== @@ -758,7 +760,6 @@ if(HAVE_CUDA) status(" Use CUBLAS:" HAVE_CUBLAS THEN YES ELSE NO) status(" NVIDIA GPU arch:" ${OPENCV_CUDA_ARCH_BIN}) status(" NVIDIA PTX archs:" ${OPENCV_CUDA_ARCH_BIN}) - status(" NVIDIA GPU features:" ${OPENCV_CUDA_ARCH_FEATURES}) endif() # ========================== python ========================== diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake index 2cfcbf50cd..b3d71c8c8d 100644 --- a/cmake/OpenCVCompilerOptions.cmake +++ b/cmake/OpenCVCompilerOptions.cmake @@ -283,3 +283,8 @@ if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251") #class 'std::XXX' needs to have dll-interface to be used by clients of YYY endif() endif() + + +if (MSVC AND ENABLE_MULTI_PROCESSOR_COMPILATION) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") +endif() diff --git a/modules/gpu/src/cascadeclassifier.cpp b/modules/gpu/src/cascadeclassifier.cpp index 570cb7a806..b5958697c9 100644 --- a/modules/gpu/src/cascadeclassifier.cpp +++ b/modules/gpu/src/cascadeclassifier.cpp @@ -155,7 +155,7 @@ public: cv::Size ncvMinSize = this->getClassifierCvSize(); - if (ncvMinSize.width < (unsigned)minSize.width && ncvMinSize.height < (unsigned)minSize.height) + if (ncvMinSize.width < minSize.width && ncvMinSize.height < minSize.height) { ncvMinSize.width = minSize.width; ncvMinSize.height = minSize.height; diff --git a/modules/gpu/src/cuda/ccomponetns.cu b/modules/gpu/src/cuda/ccomponetns.cu index 07f2410caa..076fdcc125 100644 --- a/modules/gpu/src/cuda/ccomponetns.cu +++ b/modules/gpu/src/cuda/ccomponetns.cu @@ -43,6 +43,7 @@ #include #include #include + #include #include @@ -128,7 +129,8 @@ namespace cv { namespace gpu { namespace device template struct InInterval { - __host__ __device__ __forceinline__ InInterval(const float4& _lo, const float4& _hi) : lo(-_lo.x), hi(_hi.x) {}; + typedef typename VecTraits::elem_type E; + __host__ __device__ __forceinline__ InInterval(const float4& _lo, const float4& _hi) : lo((E)(-_lo.x)), hi((E)_hi.x) {}; T lo, hi; template __device__ __forceinline__ bool operator() (const I& a, const I& b) const @@ -138,10 +140,12 @@ namespace cv { namespace gpu { namespace device } }; + template struct InInterval { + typedef typename VecTraits::elem_type E; __host__ __device__ __forceinline__ InInterval(const float4& _lo, const float4& _hi) - : lo (VecTraits::make(-_lo.x, -_lo.y, -_lo.z)), hi (VecTraits::make(_hi.x, _hi.y, _hi.z)){}; + : lo (VecTraits::make((E)(-_lo.x), (E)(-_lo.y), (E)(-_lo.z))), hi (VecTraits::make((E)_hi.x, (E)_hi.y, (E)_hi.z)){}; T lo, hi; template __device__ __forceinline__ bool operator() (const I& a, const I& b) const @@ -155,8 +159,9 @@ namespace cv { namespace gpu { namespace device template struct InInterval { + typedef typename VecTraits::elem_type E; __host__ __device__ __forceinline__ InInterval(const float4& _lo, const float4& _hi) - : lo (VecTraits::make(-_lo.x, -_lo.y, -_lo.z, -_lo.w)), hi (VecTraits::make(_hi.x, _hi.y, _hi.z, -_hi.w)){}; + : lo (VecTraits::make((E)(-_lo.x), (E)(-_lo.y), (E)(-_lo.z), (E)(-_lo.w))), hi (VecTraits::make((E)_hi.x, (E)_hi.y, (E)_hi.z, (E)_hi.w)){}; T lo, hi; template __device__ __forceinline__ bool operator() (const I& a, const I& b) const @@ -499,11 +504,11 @@ namespace cv { namespace gpu { namespace device int tileSizeX = TILE_COLS, tileSizeY = TILE_ROWS; while (grid.x > 1 || grid.y > 1) { - dim3 mergeGrid(ceilf(grid.x / 2.0), ceilf(grid.y / 2.0)); + dim3 mergeGrid((int)ceilf(grid.x / 2.f), (int)ceilf(grid.y / 2.f)); dim3 mergeBlock(STA_SIZE_MERGE_X, STA_SIZE_MERGE_Y); // debug log // std::cout << "merging: " << grid.y << " x " << grid.x << " ---> " << mergeGrid.y << " x " << mergeGrid.x << " for tiles: " << tileSizeY << " x " << tileSizeX << std::endl; - crossMerge<<>>(2, 2, tileSizeY, tileSizeX, edges, comps, ceilf(grid.y / 2.0) - grid.y / 2, ceilf(grid.x / 2.0) - grid.x / 2); + crossMerge<<>>(2, 2, tileSizeY, tileSizeX, edges, comps, (int)ceilf(grid.y / 2.f) - grid.y / 2, (int)ceilf(grid.x / 2.f) - grid.x / 2); tileSizeX <<= 1; tileSizeY <<= 1; grid = mergeGrid; diff --git a/modules/gpu/src/cuda/resize.cu b/modules/gpu/src/cuda/resize.cu index e0c8caefb4..edf0522709 100644 --- a/modules/gpu/src/cuda/resize.cu +++ b/modules/gpu/src/cuda/resize.cu @@ -226,8 +226,8 @@ namespace cv { namespace gpu { namespace device (void)srcWhole; (void)xoff; (void)yoff; - int iscale_x = round(fx); - int iscale_y = round(fy); + int iscale_x = (int)round(fx); + int iscale_y = (int)round(fy); if( std::abs(fx - iscale_x) < FLT_MIN && std::abs(fy - iscale_y) < FLT_MIN) ResizeDispatcherStream::call(src, fx, fy, dst, stream); diff --git a/modules/gpu/src/fgd_bgfg.cpp b/modules/gpu/src/fgd_bgfg.cpp index a136c31d90..27a791287b 100644 --- a/modules/gpu/src/fgd_bgfg.cpp +++ b/modules/gpu/src/fgd_bgfg.cpp @@ -412,7 +412,7 @@ namespace changeMask.setTo(cv::Scalar::all(0)); - funcs[prevFrame.channels() - 1][curFrame.channels() - 1](prevFrame, curFrame, make_uchar3(bestThres[0], bestThres[1], bestThres[2]), changeMask, 0); + funcs[prevFrame.channels() - 1][curFrame.channels() - 1](prevFrame, curFrame, make_uchar3((uchar)bestThres[0], (uchar)bestThres[1], (uchar)bestThres[2]), changeMask, 0); } // performs change detection for Foreground detection algorithm diff --git a/modules/gpu/src/graphcuts.cpp b/modules/gpu/src/graphcuts.cpp index fc3ac1edf0..6b5d7b3bac 100644 --- a/modules/gpu/src/graphcuts.cpp +++ b/modules/gpu/src/graphcuts.cpp @@ -63,15 +63,11 @@ namespace cv { namespace gpu { namespace device } }}} - -float4 scalarToCudaType(const cv::Scalar& in) +static float4 scalarToCudaType(const cv::Scalar& in) { - float4 res; - res.x = in[0]; res.y = in[1]; res.z = in[2]; res.w = in[3]; - return res; + return make_float4((float)in[0], (float)in[1], (float)in[2], (float)in[3]); } - void cv::gpu::connectivityMask(const GpuMat& image, GpuMat& mask, const cv::Scalar& lo, const cv::Scalar& hi, Stream& s) { CV_Assert(!image.empty()); diff --git a/modules/gpu/src/hough.cpp b/modules/gpu/src/hough.cpp index 3b683ff40c..b2007ec089 100644 --- a/modules/gpu/src/hough.cpp +++ b/modules/gpu/src/hough.cpp @@ -112,7 +112,7 @@ void cv::gpu::HoughLinesGet(const GpuMat& accum, GpuMat& lines, float rho, float ensureSizeIsEnough(2, maxLines, CV_32FC2, lines); - int count = linesGetResult_gpu(accum, lines.ptr(0), lines.ptr(1), maxLines, rho, theta, threshold, doSort); + int count = linesGetResult_gpu(accum, lines.ptr(0), lines.ptr(1), maxLines, rho, theta, (float)threshold, doSort); if (count > 0) lines.cols = count; diff --git a/modules/imgproc/perf/perf_remap.cpp b/modules/imgproc/perf/perf_remap.cpp index e789296735..4429e5e4e2 100644 --- a/modules/imgproc/perf/perf_remap.cpp +++ b/modules/imgproc/perf/perf_remap.cpp @@ -44,16 +44,16 @@ PERF_TEST_P( TestRemap, Remap, switch (map1_type) { case CV_32FC1: - map1.at(j, i) = src.cols - i; - map2.at(j, i) = j; + map1.at(j, i) = (float)(src.cols - i); + map2.at(j, i) = (float)j; break; case CV_32FC2: - map1.at(j, i)[0] = src.cols - i; - map1.at(j, i)[1] = j; + map1.at(j, i)[0] = (float)(src.cols - i); + map1.at(j, i)[1] = (float)j; break; case CV_16SC2: - map1.at(j, i)[0] = src.cols - i; - map1.at(j, i)[1] = j; + map1.at(j, i)[0] = (float)(src.cols - i); + map1.at(j, i)[1] = (float)j; break; default: CV_Assert(0); From e60a50c43c9ed43e4e52b3729a4baa225822b399 Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Thu, 23 Aug 2012 15:46:19 +0400 Subject: [PATCH 063/163] removed /EHa flag for cuda compilation --- cmake/OpenCVDetectCUDA.cmake | 23 +++++++++++++++++------ modules/gpu/CMakeLists.txt | 3 ++- modules/gpu/test/test_labeling.cpp | 7 ++++--- modules/imgproc/perf/perf_remap.cpp | 4 ++-- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake index 43e9c819af..aa33fe18ab 100644 --- a/cmake/OpenCVDetectCUDA.cmake +++ b/cmake/OpenCVDetectCUDA.cmake @@ -77,7 +77,17 @@ if(CUDA_FOUND) unset(CUDA_npp_LIBRARY CACHE) find_cuda_helper_libs(npp) - macro(OCV_CUDA_COMPILE VAR) + macro(ocv_cuda_compile VAR) + foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG) + set(${var}_backup_in_cuda_compile_ "${${var}}") + + # we reomove /EHa as it leasd warnings under windows + string(REPLACE "/EHa" "" ${var} "${${var}}") + + # we remove -ggdb3 flag as it leads to preprocessor errors when compiling CUDA files (CUDA 4.1) + string(REPLACE "-ggdb3" "" ${var} "${${var}}") + endforeach() + if (BUILD_SHARED_LIBS) set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler -DCVAPI_EXPORTS) endif() @@ -94,11 +104,12 @@ if(CUDA_FOUND) ocv_warnings_disable(CMAKE_CXX_FLAGS -Wunused-but-set-variable) endif() - # we remove -ggdb3 flag as it leads to preprocessor errors when compiling CUDA files (CUDA 4.1) - set(CMAKE_CXX_FLAGS_DEBUG_ ${CMAKE_CXX_FLAGS_DEBUG}) - string(REPLACE "-ggdb3" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) - CUDA_COMPILE(${VAR} ${ARGN}) - set(CMAKE_CXX_DEBUG_FLAGS ${CMAKE_CXX_FLAGS_DEBUG_}) + CUDA_COMPILE(${VAR} ${ARGN}) + + foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG) + set(${var} "${${var}_backup_in_cuda_compile_}") + unset(${var}_backup_in_cuda_compile_) + endforeach() endmacro() else() unset(CUDA_ARCH_BIN CACHE) diff --git a/modules/gpu/CMakeLists.txt b/modules/gpu/CMakeLists.txt index 5d2c440fe5..9963ea754a 100644 --- a/modules/gpu/CMakeLists.txt +++ b/modules/gpu/CMakeLists.txt @@ -44,8 +44,9 @@ if (HAVE_CUDA) set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler /wd4251) endif() endif() - + ocv_cuda_compile(cuda_objs ${lib_cuda} ${ncv_cuda}) + #CUDA_BUILD_CLEAN_TARGET() set(cuda_link_libs ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY}) diff --git a/modules/gpu/test/test_labeling.cpp b/modules/gpu/test/test_labeling.cpp index d32dbc1a2f..4eccbf93d6 100644 --- a/modules/gpu/test/test_labeling.cpp +++ b/modules/gpu/test/test_labeling.cpp @@ -87,6 +87,7 @@ namespace { unsigned char* source = (unsigned char*)image.data; int width = image.cols; int height = image.rows; + int step1 = (int)image.step1(); for (int j = 0; j < image.rows; ++j) for (int i = 0; i < image.cols; ++i) @@ -102,7 +103,7 @@ namespace { while (top >= stack) { int* dl = &dist_labels[p.y * pitch + p.x]; - unsigned char* sp = &source[p.y * image.step1() + p.x]; + unsigned char* sp = &source[p.y * step1 + p.x]; dl[0] = cc; @@ -115,11 +116,11 @@ namespace { *top++ = dot::make(p.x - 1, p.y); //bottom - if( p.y < (height - 1) && dl[+pitch] == -1 && inInt(sp[0], sp[+image.step1()])) + if( p.y < (height - 1) && dl[+pitch] == -1 && inInt(sp[0], sp[+step1])) *top++ = dot::make(p.x, p.y + 1); //top - if( p.y > 0 && dl[-pitch] == -1 && inInt(sp[0], sp[-image.step1()])) + if( p.y > 0 && dl[-pitch] == -1 && inInt(sp[0], sp[-step1])) *top++ = dot::make(p.x, p.y - 1); p = *--top; diff --git a/modules/imgproc/perf/perf_remap.cpp b/modules/imgproc/perf/perf_remap.cpp index 4429e5e4e2..62e02e9285 100644 --- a/modules/imgproc/perf/perf_remap.cpp +++ b/modules/imgproc/perf/perf_remap.cpp @@ -52,8 +52,8 @@ PERF_TEST_P( TestRemap, Remap, map1.at(j, i)[1] = (float)j; break; case CV_16SC2: - map1.at(j, i)[0] = (float)(src.cols - i); - map1.at(j, i)[1] = (float)j; + map1.at(j, i)[0] = (short)(src.cols - i); + map1.at(j, i)[1] = (short)j; break; default: CV_Assert(0); From c3f277b7bc47256ef9466d996f9736fde8a6c704 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 23 Aug 2012 16:54:48 +0400 Subject: [PATCH 064/163] gpu version of HoughCircles --- modules/gpu/doc/image_processing.rst | 98 +++++----- modules/gpu/include/opencv2/gpu/gpu.hpp | 25 ++- modules/gpu/perf/perf_imgproc.cpp | 71 ++++++- modules/gpu/perf/utility.hpp | 2 +- modules/gpu/src/cuda/hough.cu | 234 +++++++++++++++++++++--- modules/gpu/src/hough.cpp | 209 +++++++++++++++++---- modules/gpu/test/test_imgproc.cpp | 75 +++++++- 7 files changed, 596 insertions(+), 118 deletions(-) diff --git a/modules/gpu/doc/image_processing.rst b/modules/gpu/doc/image_processing.rst index eb2561ec4d..858b707bae 100644 --- a/modules/gpu/doc/image_processing.rst +++ b/modules/gpu/doc/image_processing.rst @@ -893,7 +893,7 @@ Finds lines in a binary image using the classical Hough transform. .. ocv:function:: void gpu::HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096) -.. ocv:function:: void gpu::HoughLines(const GpuMat& src, GpuMat& lines, GpuMat& accum, GpuMat& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096) +.. ocv:function:: void gpu::HoughLines(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096) :param src: 8-bit, single-channel binary source image. @@ -909,60 +909,12 @@ Finds lines in a binary image using the classical Hough transform. :param maxLines: Maximum number of output lines. - :param accum: Optional buffer for accumulator to avoid extra memory allocations (for many calls with the same sizes). - :param buf: Optional buffer to avoid extra memory allocations (for many calls with the same sizes). .. seealso:: :ocv:func:`HoughLines` -gpu::HoughLinesTransform ------------------------- -Performs classical Hough transform for line detection. - -.. ocv:function:: void gpu::HoughLinesTransform(const GpuMat& src, GpuMat& accum, GpuMat& buf, float rho, float theta) - - :param src: 8-bit, single-channel binary source image. - - :param accum: Output accumulator array. - - :param buf: Buffer to avoid extra memory allocations (for many calls with the same sizes). - - :param rho: Distance resolution of the accumulator in pixels. - - :param theta: Angle resolution of the accumulator in radians. - - :param threshold: Accumulator threshold parameter. Only those lines are returned that get enough votes ( :math:`>\texttt{threshold}` ). - -.. seealso:: :ocv:func:`gpu::HoughLines` - - - -gpu::HoughLinesGet ------------------- -Finds lines in Hough space. - -.. ocv:function:: void gpu::HoughLinesGet(const GpuMat& accum, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096) - - :param accum: Accumulator array. - - :param lines: Output vector of lines. Each line is represented by a two-element vector :math:`(\rho, \theta)` . :math:`\rho` is the distance from the coordinate origin :math:`(0,0)` (top-left corner of the image). :math:`\theta` is the line rotation angle in radians ( :math:`0 \sim \textrm{vertical line}, \pi/2 \sim \textrm{horizontal line}` ). - - :param rho: Distance resolution of the accumulator in pixels. - - :param theta: Angle resolution of the accumulator in radians. - - :param threshold: Accumulator threshold parameter. Only those lines are returned that get enough votes ( :math:`>\texttt{threshold}` ). - - :param doSort: Performs lines sort by votes. - - :param maxLines: Maximum number of output lines. - -.. seealso:: :ocv:func:`gpu::HoughLines` - - - gpu::HoughLinesDownload ----------------------- Downloads results from :ocv:func:`gpu::HoughLines` to host memory. @@ -976,3 +928,51 @@ Downloads results from :ocv:func:`gpu::HoughLines` to host memory. :param h_votes: Optional output array for line's votes. .. seealso:: :ocv:func:`gpu::HoughLines` + + + +gpu::HoughCircles +----------------- +Finds circles in a grayscale image using the Hough transform. + +.. ocv:function:: void gpu::HoughCircles(const GpuMat& src, GpuMat& circles, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096) + +.. ocv:function:: void gpu::HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& buf, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096) + + :param src: 8-bit, single-channel grayscale input image. + + :param circles: Output vector of found circles. Each vector is encoded as a 3-element floating-point vector :math:`(x, y, radius)` . + + :param method: Detection method to use. Currently, the only implemented method is ``CV_HOUGH_GRADIENT`` , which is basically *21HT* , described in [Yuen90]_. + + :param dp: Inverse ratio of the accumulator resolution to the image resolution. For example, if ``dp=1`` , the accumulator has the same resolution as the input image. If ``dp=2`` , the accumulator has half as big width and height. + + :param minDist: Minimum distance between the centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed. + + :param cannyThreshold: The higher threshold of the two passed to the :ocv:func:`gpu::Canny` edge detector (the lower one is twice smaller). + + :param votesThreshold: The accumulator threshold for the circle centers at the detection stage. The smaller it is, the more false circles may be detected. + + :param minRadius: Minimum circle radius. + + :param maxRadius: Maximum circle radius. + + :param maxCircles: Maximum number of output circles. + + :param buf: Optional buffer to avoid extra memory allocations (for many calls with the same sizes). + +.. seealso:: :ocv:func:`HoughCircles` + + + +gpu::HoughCirclesDownload +------------------------- +Downloads results from :ocv:func:`gpu::HoughCircles` to host memory. + +.. ocv:function:: void gpu::HoughCirclesDownload(const GpuMat& d_circles, OutputArray h_circles) + + :param d_circles: Result of :ocv:func:`gpu::HoughCircles` . + + :param h_circles: Output host array. + +.. seealso:: :ocv:func:`gpu::HoughCircles` diff --git a/modules/gpu/include/opencv2/gpu/gpu.hpp b/modules/gpu/include/opencv2/gpu/gpu.hpp index c6f2e1141e..c2fcc31a2e 100644 --- a/modules/gpu/include/opencv2/gpu/gpu.hpp +++ b/modules/gpu/include/opencv2/gpu/gpu.hpp @@ -821,12 +821,31 @@ private: }; //! HoughLines + +struct HoughLinesBuf +{ + GpuMat accum; + GpuMat list; +}; + CV_EXPORTS void HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096); -CV_EXPORTS void HoughLines(const GpuMat& src, GpuMat& lines, GpuMat& accum, GpuMat& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096); -CV_EXPORTS void HoughLinesTransform(const GpuMat& src, GpuMat& accum, GpuMat& buf, float rho, float theta); -CV_EXPORTS void HoughLinesGet(const GpuMat& accum, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096); +CV_EXPORTS void HoughLines(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096); CV_EXPORTS void HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines, OutputArray h_votes = noArray()); +//! HoughCircles + +struct HoughCirclesBuf +{ + GpuMat edges; + GpuMat accum; + GpuMat list; + CannyBuf cannyBuf; +}; + +CV_EXPORTS void HoughCircles(const GpuMat& src, GpuMat& circles, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096); +CV_EXPORTS void HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& buf, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096); +CV_EXPORTS void HoughCirclesDownload(const GpuMat& d_circles, OutputArray h_circles); + ////////////////////////////// Matrix reductions ////////////////////////////// //! computes mean value and standard deviation of all or selected array elements diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index f938ca239e..ba864afc94 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -1609,14 +1609,11 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_ImagePyramidGetLayer, Combine(GPU_TYPICAL_MAT_S ////////////////////////////////////////////////////////////////////// // HoughLines -DEF_PARAM_TEST(Sz_DoSort, cv::Size, bool); - -PERF_TEST_P(Sz_DoSort, ImgProc_HoughLines, Combine(GPU_TYPICAL_MAT_SIZES, Bool())) +PERF_TEST_P(Sz, ImgProc_HoughLines, GPU_TYPICAL_MAT_SIZES) { declare.time(30.0); - const cv::Size size = GET_PARAM(0); - const bool doSort = GET_PARAM(1); + const cv::Size size = GetParam(); const float rho = 1.0f; const float theta = static_cast(CV_PI / 180.0); @@ -1638,14 +1635,13 @@ PERF_TEST_P(Sz_DoSort, ImgProc_HoughLines, Combine(GPU_TYPICAL_MAT_SIZES, Bool() { cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_lines; - cv::gpu::GpuMat d_accum; - cv::gpu::GpuMat d_buf; + cv::gpu::HoughLinesBuf d_buf; - cv::gpu::HoughLines(d_src, d_lines, d_accum, d_buf, rho, theta, threshold, doSort); + cv::gpu::HoughLines(d_src, d_lines, d_buf, rho, theta, threshold); TEST_CYCLE() { - cv::gpu::HoughLines(d_src, d_lines, d_accum, d_buf, rho, theta, threshold, doSort); + cv::gpu::HoughLines(d_src, d_lines, d_buf, rho, theta, threshold); } } else @@ -1660,4 +1656,61 @@ PERF_TEST_P(Sz_DoSort, ImgProc_HoughLines, Combine(GPU_TYPICAL_MAT_SIZES, Bool() } } +////////////////////////////////////////////////////////////////////// +// HoughCircles + +DEF_PARAM_TEST(Sz_Dp_MinDist, cv::Size, float, float); + +PERF_TEST_P(Sz_Dp_MinDist, ImgProc_HoughCircles, Combine(GPU_TYPICAL_MAT_SIZES, Values(1.0f, 2.0f, 4.0f), Values(1.0f, 10.0f))) +{ + declare.time(30.0); + + const cv::Size size = GET_PARAM(0); + const float dp = GET_PARAM(1); + const float minDist = GET_PARAM(2); + + const int minRadius = 10; + const int maxRadius = 30; + const int cannyThreshold = 100; + const int votesThreshold = 15; + + cv::RNG rng(123456789); + + cv::Mat src(size, CV_8UC1, cv::Scalar::all(0)); + + const int numCircles = rng.uniform(50, 100); + for (int i = 0; i < numCircles; ++i) + { + cv::Point center(rng.uniform(0, src.cols), rng.uniform(0, src.rows)); + const int radius = rng.uniform(minRadius, maxRadius + 1); + + cv::circle(src, center, radius, cv::Scalar::all(255), -1); + } + + if (runOnGpu) + { + cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat d_circles; + cv::gpu::HoughCirclesBuf d_buf; + + cv::gpu::HoughCircles(d_src, d_circles, d_buf, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + + TEST_CYCLE() + { + cv::gpu::HoughCircles(d_src, d_circles, d_buf, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + } + } + else + { + std::vector circles; + + cv::HoughCircles(src, circles, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + + TEST_CYCLE() + { + cv::HoughCircles(src, circles, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + } + } +} + } // namespace diff --git a/modules/gpu/perf/utility.hpp b/modules/gpu/perf/utility.hpp index 2d21fffb57..441d32adb1 100644 --- a/modules/gpu/perf/utility.hpp +++ b/modules/gpu/perf/utility.hpp @@ -40,6 +40,6 @@ typedef perf::Size_MatType Sz_Type; DEF_PARAM_TEST(Sz_Depth, cv::Size, MatDepth); DEF_PARAM_TEST(Sz_Depth_Cn, cv::Size, MatDepth, int); -#define GPU_TYPICAL_MAT_SIZES testing::Values(perf::szSXGA, perf::sz720p, perf::sz1080p) +#define GPU_TYPICAL_MAT_SIZES testing::Values(perf::sz720p, perf::szSXGA, perf::sz1080p) #endif // __OPENCV_PERF_GPU_UTILITY_HPP__ diff --git a/modules/gpu/src/cuda/hough.cu b/modules/gpu/src/cuda/hough.cu index 66433aba7e..63099d3bcc 100644 --- a/modules/gpu/src/cuda/hough.cu +++ b/modules/gpu/src/cuda/hough.cu @@ -57,7 +57,7 @@ namespace cv { namespace gpu { namespace device __global__ void buildPointList(const DevMem2Db src, unsigned int* list) { - __shared__ int s_queues[4][32 * PIXELS_PER_THREAD]; + __shared__ unsigned int s_queues[4][32 * PIXELS_PER_THREAD]; __shared__ int s_qsize[4]; __shared__ int s_globStart[4]; @@ -211,8 +211,6 @@ namespace cv { namespace gpu { namespace device const dim3 block(has20 ? 1024 : 512); const dim3 grid(accum.rows - 2); - cudaSafeCall( cudaFuncSetCacheConfig(linesAccumShared, cudaFuncCachePreferShared) ); - size_t smemSize = (accum.cols - 1) * sizeof(int); if (smemSize < sharedMemPerBlock - 1000) @@ -230,28 +228,19 @@ namespace cv { namespace gpu { namespace device __global__ void linesGetResult(const DevMem2Di accum, float2* out, int* votes, const int maxSize, const float rho, const float theta, const float threshold, const int numrho) { - __shared__ int smem[8][32]; + const int r = blockIdx.x * blockDim.x + threadIdx.x; + const int n = blockIdx.y * blockDim.y + threadIdx.y; - const int x = blockIdx.x * (blockDim.x - 2) + threadIdx.x; - const int y = blockIdx.y * (blockDim.y - 2) + threadIdx.y; - - if (x >= accum.cols || y >= accum.rows) + if (r >= accum.cols - 2 && n >= accum.rows - 2) return; - smem[threadIdx.y][threadIdx.x] = accum(y, x); - __syncthreads(); + const int curVotes = accum(n + 1, r + 1); - const int r = x - 1; - const int n = y - 1; - - if (threadIdx.x == 0 || threadIdx.x == blockDim.x - 1 || threadIdx.y == 0 || threadIdx.y == blockDim.y - 1 || r >= accum.cols - 2 || n >= accum.rows - 2) - return; - - if (smem[threadIdx.y][threadIdx.x] > threshold && - smem[threadIdx.y][threadIdx.x] > smem[threadIdx.y - 1][threadIdx.x] && - smem[threadIdx.y][threadIdx.x] >= smem[threadIdx.y + 1][threadIdx.x] && - smem[threadIdx.y][threadIdx.x] > smem[threadIdx.y][threadIdx.x - 1] && - smem[threadIdx.y][threadIdx.x] >= smem[threadIdx.y][threadIdx.x + 1]) + if (curVotes > threshold && + curVotes > accum(n + 1, r) && + curVotes >= accum(n + 1, r + 2) && + curVotes > accum(n, r + 1) && + curVotes >= accum(n + 2, r + 1)) { const float radius = (r - (numrho - 1) * 0.5f) * rho; const float angle = n * theta; @@ -260,7 +249,7 @@ namespace cv { namespace gpu { namespace device if (ind < maxSize) { out[ind] = make_float2(radius, angle); - votes[ind] = smem[threadIdx.y][threadIdx.x]; + votes[ind] = curVotes; } } } @@ -273,7 +262,9 @@ namespace cv { namespace gpu { namespace device cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); const dim3 block(32, 8); - const dim3 grid(divUp(accum.cols, block.x - 2), divUp(accum.rows, block.y - 2)); + const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y)); + + cudaSafeCall( cudaFuncSetCacheConfig(linesGetResult, cudaFuncCachePreferL1) ); linesGetResult<<>>(accum, out, votes, maxSize, rho, theta, threshold, accum.cols - 2); cudaSafeCall( cudaGetLastError() ); @@ -294,5 +285,202 @@ namespace cv { namespace gpu { namespace device return totalCount; } + + //////////////////////////////////////////////////////////////////////// + // circlesAccumCenters + + __global__ void circlesAccumCenters(const unsigned int* list, const int count, const PtrStepi dx, const PtrStepi dy, + PtrStepi accum, const int width, const int height, const int minRadius, const int maxRadius, const float idp) + { + const int SHIFT = 10; + const int ONE = 1 << SHIFT; + + const int tid = blockIdx.x * blockDim.x + threadIdx.x; + + if (tid >= count) + return; + + const unsigned int val = list[tid]; + + const int x = (val & 0xFFFF); + const int y = (val >> 16) & 0xFFFF; + + const int vx = dx(y, x); + const int vy = dy(y, x); + + if (vx == 0 && vy == 0) + return; + + const float mag = ::sqrtf(vx * vx + vy * vy); + + const int x0 = __float2int_rn((x * idp) * ONE); + const int y0 = __float2int_rn((y * idp) * ONE); + + int sx = __float2int_rn((vx * idp) * ONE / mag); + int sy = __float2int_rn((vy * idp) * ONE / mag); + + // Step from minRadius to maxRadius in both directions of the gradient + for (int k1 = 0; k1 < 2; ++k1) + { + int x1 = x0 + minRadius * sx; + int y1 = y0 + minRadius * sy; + + for (int r = minRadius; r <= maxRadius; x1 += sx, y1 += sy, ++r) + { + const int x2 = x1 >> SHIFT; + const int y2 = y1 >> SHIFT; + + if (x2 < 0 || x2 >= width || y2 < 0 || y2 >= height) + break; + + ::atomicAdd(accum.ptr(y2 + 1) + x2 + 1, 1); + } + + sx = -sx; + sy = -sy; + } + } + + void circlesAccumCenters_gpu(const unsigned int* list, int count, PtrStepi dx, PtrStepi dy, DevMem2Di accum, int minRadius, int maxRadius, float idp) + { + const dim3 block(256); + const dim3 grid(divUp(count, block.x)); + + cudaSafeCall( cudaFuncSetCacheConfig(circlesAccumCenters, cudaFuncCachePreferL1) ); + + circlesAccumCenters<<>>(list, count, dx, dy, accum, accum.cols - 2, accum.rows - 2, minRadius, maxRadius, idp); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + + //////////////////////////////////////////////////////////////////////// + // buildCentersList + + __global__ void buildCentersList(const DevMem2Di accum, unsigned int* centers, const int threshold) + { + const int x = blockIdx.x * blockDim.x + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if (x < accum.cols - 2 && y < accum.rows - 2) + { + const int top = accum(y, x + 1); + + const int left = accum(y + 1, x); + const int cur = accum(y + 1, x + 1); + const int right = accum(y + 1, x + 2); + + const int bottom = accum(y + 2, x + 1); + + if (cur > threshold && cur > top && cur >= bottom && cur > left && cur >= right) + { + const unsigned int val = (y << 16) | x; + const int idx = ::atomicAdd(&g_counter, 1); + centers[idx] = val; + } + } + } + + int buildCentersList_gpu(DevMem2Di accum, unsigned int* centers, int threshold) + { + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(32, 8); + const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y)); + + cudaSafeCall( cudaFuncSetCacheConfig(buildCentersList, cudaFuncCachePreferL1) ); + + buildCentersList<<>>(accum, centers, threshold); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + return totalCount; + } + + //////////////////////////////////////////////////////////////////////// + // circlesAccumRadius + + __global__ void circlesAccumRadius(const unsigned int* centers, const unsigned int* list, const int count, + float3* circles, const int maxCircles, const float dp, + const int minRadius, const int maxRadius, const int histSize, const int threshold) + { + extern __shared__ int smem[]; + + for (int i = threadIdx.x; i < histSize + 2; i += blockDim.x) + smem[i] = 0; + __syncthreads(); + + unsigned int val = centers[blockIdx.x]; + + float cx = (val & 0xFFFF); + float cy = (val >> 16) & 0xFFFF; + + cx = (cx + 0.5f) * dp; + cy = (cy + 0.5f) * dp; + + for (int i = threadIdx.x; i < count; i += blockDim.x) + { + val = list[i]; + + const int x = (val & 0xFFFF); + const int y = (val >> 16) & 0xFFFF; + + const float rad = ::sqrtf((cx - x) * (cx - x) + (cy - y) * (cy - y)); + if (rad >= minRadius && rad <= maxRadius) + { + const int r = __float2int_rn(rad - minRadius); + + Emulation::smem::atomicAdd(&smem[r + 1], 1); + } + } + + __syncthreads(); + + for (int i = threadIdx.x; i < histSize; i += blockDim.x) + { + const int curVotes = smem[i + 1]; + + if (curVotes >= threshold && curVotes > smem[i] && curVotes >= smem[i + 2]) + { + const int ind = ::atomicAdd(&g_counter, 1); + if (ind < maxCircles) + circles[ind] = make_float3(cx, cy, i + minRadius); + } + } + } + + int circlesAccumRadius_gpu(const unsigned int* centers, int centersCount, const unsigned int* list, int count, + float3* circles, int maxCircles, float dp, int minRadius, int maxRadius, int threshold, bool has20) + { + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(has20 ? 1024 : 512); + const dim3 grid(centersCount); + + const int histSize = ::ceil(maxRadius - minRadius + 1); + size_t smemSize = (histSize + 2) * sizeof(int); + + circlesAccumRadius<<>>(centers, list, count, circles, maxCircles, dp, minRadius, maxRadius, histSize, threshold); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + totalCount = ::min(totalCount, maxCircles); + + return totalCount; + } } }}} diff --git a/modules/gpu/src/hough.cpp b/modules/gpu/src/hough.cpp index b2007ec089..82396e3fc6 100644 --- a/modules/gpu/src/hough.cpp +++ b/modules/gpu/src/hough.cpp @@ -44,12 +44,14 @@ #if !defined (HAVE_CUDA) -void cv::gpu::HoughLinesTransform(const GpuMat&, GpuMat&, GpuMat&, float, float) { throw_nogpu(); } -void cv::gpu::HoughLinesGet(const GpuMat&, GpuMat&, float, float, int, bool, int) { throw_nogpu(); } void cv::gpu::HoughLines(const GpuMat&, GpuMat&, float, float, int, bool, int) { throw_nogpu(); } -void cv::gpu::HoughLines(const GpuMat&, GpuMat&, GpuMat&, GpuMat&, float, float, int, bool, int) { throw_nogpu(); } +void cv::gpu::HoughLines(const GpuMat&, GpuMat&, HoughLinesBuf&, float, float, int, bool, int) { throw_nogpu(); } void cv::gpu::HoughLinesDownload(const GpuMat&, OutputArray, OutputArray) { throw_nogpu(); } +void cv::gpu::HoughCircles(const GpuMat&, GpuMat&, int, float, float, int, int, int, int, int) { throw_nogpu(); } +void cv::gpu::HoughCircles(const GpuMat&, GpuMat&, HoughCirclesBuf&, int, float, float, int, int, int, int, int) { throw_nogpu(); } +void cv::gpu::HoughCirclesDownload(const GpuMat&, OutputArray) { throw_nogpu(); } + #else /* !defined (HAVE_CUDA) */ namespace cv { namespace gpu { namespace device @@ -60,6 +62,11 @@ namespace cv { namespace gpu { namespace device void linesAccum_gpu(const unsigned int* list, int count, DevMem2Di accum, float rho, float theta, size_t sharedMemPerBlock, bool has20); int linesGetResult_gpu(DevMem2Di accum, float2* out, int* votes, int maxSize, float rho, float theta, float threshold, bool doSort); + + void circlesAccumCenters_gpu(const unsigned int* list, int count, PtrStepi dx, PtrStepi dy, DevMem2Di accum, int minRadius, int maxRadius, float idp); + int buildCentersList_gpu(DevMem2Di accum, unsigned int* centers, int threshold); + int circlesAccumRadius_gpu(const unsigned int* centers, int centersCount, const unsigned int* list, int count, + float3* circles, int maxCircles, float dp, int minRadius, int maxRadius, int threshold, bool has20); } }}} @@ -68,17 +75,11 @@ namespace cv { namespace gpu { namespace device void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort, int maxLines) { - GpuMat accum, buf; - HoughLines(src, lines, accum, buf, rho, theta, threshold, doSort, maxLines); + HoughLinesBuf buf; + HoughLines(src, lines, buf, rho, theta, threshold, doSort, maxLines); } -void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, GpuMat& accum, GpuMat& buf, float rho, float theta, int threshold, bool doSort, int maxLines) -{ - HoughLinesTransform(src, accum, buf, rho, theta); - HoughLinesGet(accum, lines, rho, theta, threshold, doSort, maxLines); -} - -void cv::gpu::HoughLinesTransform(const GpuMat& src, GpuMat& accum, GpuMat& buf, float rho, float theta) +void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int threshold, bool doSort, int maxLines) { using namespace cv::gpu::device::hough; @@ -86,36 +87,31 @@ void cv::gpu::HoughLinesTransform(const GpuMat& src, GpuMat& accum, GpuMat& buf, CV_Assert(src.cols < std::numeric_limits::max()); CV_Assert(src.rows < std::numeric_limits::max()); - ensureSizeIsEnough(1, src.size().area(), CV_32SC1, buf); + ensureSizeIsEnough(1, src.size().area(), CV_32SC1, buf.list); + unsigned int* srcPoints = buf.list.ptr(); - const int count = buildPointList_gpu(src, buf.ptr()); + const int pointsCount = buildPointList_gpu(src, srcPoints); + if (pointsCount == 0) + { + lines.release(); + return; + } const int numangle = cvRound(CV_PI / theta); const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho); - CV_Assert(numangle > 0 && numrho > 0); - ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, accum); - accum.setTo(Scalar::all(0)); + ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, buf.accum); + buf.accum.setTo(Scalar::all(0)); DeviceInfo devInfo; - - if (count > 0) - linesAccum_gpu(buf.ptr(), count, accum, rho, theta, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); -} - -void cv::gpu::HoughLinesGet(const GpuMat& accum, GpuMat& lines, float rho, float theta, int threshold, bool doSort, int maxLines) -{ - using namespace cv::gpu::device::hough; - - CV_Assert(accum.type() == CV_32SC1); + linesAccum_gpu(srcPoints, pointsCount, buf.accum, rho, theta, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); ensureSizeIsEnough(2, maxLines, CV_32FC2, lines); - int count = linesGetResult_gpu(accum, lines.ptr(0), lines.ptr(1), maxLines, rho, theta, (float)threshold, doSort); - - if (count > 0) - lines.cols = count; + int linesCount = linesGetResult_gpu(buf.accum, lines.ptr(0), lines.ptr(1), maxLines, rho, theta, threshold, doSort); + if (linesCount > 0) + lines.cols = linesCount; else lines.release(); } @@ -145,4 +141,155 @@ void cv::gpu::HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines_, Ou } } +////////////////////////////////////////////////////////// +// HoughCircles + +void cv::gpu::HoughCircles(const GpuMat& src, GpuMat& circles, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles) +{ + HoughCirclesBuf buf; + HoughCircles(src, circles, buf, method, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius, maxCircles); +} + +void cv::gpu::HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& buf, int method, + float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles) +{ + using namespace cv::gpu::device::hough; + + CV_Assert(src.type() == CV_8UC1); + CV_Assert(src.cols < std::numeric_limits::max()); + CV_Assert(src.rows < std::numeric_limits::max()); + CV_Assert(method == CV_HOUGH_GRADIENT); + CV_Assert(dp > 0); + CV_Assert(minRadius > 0 && maxRadius > minRadius); + CV_Assert(cannyThreshold > 0); + CV_Assert(votesThreshold > 0); + CV_Assert(maxCircles > 0); + + const float idp = 1.0f / dp; + + cv::gpu::Canny(src, buf.cannyBuf, buf.edges, std::max(cannyThreshold / 2, 1), cannyThreshold); + + ensureSizeIsEnough(2, src.size().area(), CV_32SC1, buf.list); + unsigned int* srcPoints = buf.list.ptr(0); + unsigned int* centers = buf.list.ptr(1); + + const int pointsCount = buildPointList_gpu(buf.edges, srcPoints); + if (pointsCount == 0) + { + circles.release(); + return; + } + + ensureSizeIsEnough(cvCeil(src.rows * idp) + 2, cvCeil(src.cols * idp) + 2, CV_32SC1, buf.accum); + buf.accum.setTo(Scalar::all(0)); + + circlesAccumCenters_gpu(srcPoints, pointsCount, buf.cannyBuf.dx, buf.cannyBuf.dy, buf.accum, minRadius, maxRadius, idp); + + int centersCount = buildCentersList_gpu(buf.accum, centers, votesThreshold); + if (centersCount == 0) + { + circles.release(); + return; + } + + if (minDist > 1) + { + cv::AutoBuffer oldBuf_(centersCount); + cv::AutoBuffer newBuf_(centersCount); + int newCount = 0; + + ushort2* oldBuf = oldBuf_; + ushort2* newBuf = newBuf_; + + cudaSafeCall( cudaMemcpy(oldBuf, centers, centersCount * sizeof(ushort2), cudaMemcpyDeviceToHost) ); + + const int cellSize = cvRound(minDist); + const int gridWidth = (src.cols + cellSize - 1) / cellSize; + const int gridHeight = (src.rows + cellSize - 1) / cellSize; + + std::vector< std::vector > grid(gridWidth * gridHeight); + + minDist *= minDist; + + for (int i = 0; i < centersCount; ++i) + { + ushort2 p = oldBuf[i]; + + bool good = true; + + int xCell = static_cast(p.x / cellSize); + int yCell = static_cast(p.y / cellSize); + + int x1 = xCell - 1; + int y1 = yCell - 1; + int x2 = xCell + 1; + int y2 = yCell + 1; + + // boundary check + x1 = std::max(0, x1); + y1 = std::max(0, y1); + x2 = std::min(gridWidth - 1, x2); + y2 = std::min(gridHeight - 1, y2); + + for (int yy = y1; yy <= y2; ++yy) + { + for (int xx = x1; xx <= x2; ++xx) + { + vector& m = grid[yy * gridWidth + xx]; + + for(size_t j = 0; j < m.size(); ++j) + { + float dx = p.x - m[j].x; + float dy = p.y - m[j].y; + + if (dx * dx + dy * dy < minDist) + { + good = false; + goto break_out; + } + } + } + } + + break_out: + + if(good) + { + grid[yCell * gridWidth + xCell].push_back(p); + + newBuf[newCount++] = p; + } + } + + cudaSafeCall( cudaMemcpy(centers, newBuf, newCount * sizeof(unsigned int), cudaMemcpyHostToDevice) ); + centersCount = newCount; + } + + ensureSizeIsEnough(1, maxCircles, CV_32FC3, circles); + + DeviceInfo devInfo; + const int circlesCount = circlesAccumRadius_gpu(centers, centersCount, srcPoints, pointsCount, circles.ptr(), maxCircles, + dp, minRadius, maxRadius, votesThreshold, devInfo.supports(FEATURE_SET_COMPUTE_20)); + + if (circlesCount > 0) + circles.cols = circlesCount; + else + circles.release(); +} + +void cv::gpu::HoughCirclesDownload(const GpuMat& d_circles, cv::OutputArray h_circles_) +{ + if (d_circles.empty()) + { + h_circles_.release(); + return; + } + + CV_Assert(d_circles.rows == 1 && d_circles.type() == CV_32FC3); + + h_circles_.create(1, d_circles.cols, CV_32FC3); + Mat h_circles = h_circles_.getMat(); + d_circles.download(h_circles); +} + #endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpu/test/test_imgproc.cpp b/modules/gpu/test/test_imgproc.cpp index 06662d8d2e..2b1f55d4bf 100644 --- a/modules/gpu/test/test_imgproc.cpp +++ b/modules/gpu/test/test_imgproc.cpp @@ -1131,7 +1131,7 @@ INSTANTIATE_TEST_CASE_P(GPU_ImgProc, CornerMinEigen, testing::Combine( PARAM_TEST_CASE(HoughLines, cv::gpu::DeviceInfo, cv::Size, UseRoi) { - void generateLines(cv::Mat& img) + static void generateLines(cv::Mat& img) { img.setTo(cv::Scalar::all(0)); @@ -1141,7 +1141,7 @@ PARAM_TEST_CASE(HoughLines, cv::gpu::DeviceInfo, cv::Size, UseRoi) cv::line(img, cv::Point(img.cols, 0), cv::Point(0, img.rows), cv::Scalar::all(255)); } - void drawLines(cv::Mat& dst, const std::vector& lines) + static void drawLines(cv::Mat& dst, const std::vector& lines) { dst.setTo(cv::Scalar::all(0)); @@ -1191,6 +1191,77 @@ INSTANTIATE_TEST_CASE_P(GPU_ImgProc, HoughLines, testing::Combine( DIFFERENT_SIZES, WHOLE_SUBMAT)); +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// HoughCircles + +PARAM_TEST_CASE(HoughCircles, cv::gpu::DeviceInfo, cv::Size, UseRoi) +{ + static void drawCircles(cv::Mat& dst, const std::vector& circles, bool fill) + { + dst.setTo(cv::Scalar::all(0)); + + for (size_t i = 0; i < circles.size(); ++i) + cv::circle(dst, cv::Point(circles[i][0], circles[i][1]), circles[i][2], cv::Scalar::all(255), fill ? -1 : 1); + } +}; + +TEST_P(HoughCircles, Accuracy) +{ + const cv::gpu::DeviceInfo devInfo = GET_PARAM(0); + cv::gpu::setDevice(devInfo.deviceID()); + const cv::Size size = GET_PARAM(1); + const bool useRoi = GET_PARAM(2); + + const float dp = 2.0f; + const float minDist = 10.0f; + const int minRadius = 10; + const int maxRadius = 20; + const int cannyThreshold = 100; + const int votesThreshold = 20; + + std::vector circles_gold(4); + circles_gold[0] = cv::Vec3f(20, 20, minRadius); + circles_gold[1] = cv::Vec3f(90, 87, minRadius + 3); + circles_gold[2] = cv::Vec3f(30, 70, minRadius + 8); + circles_gold[3] = cv::Vec3f(80, 10, maxRadius); + + cv::Mat src(size, CV_8UC1); + drawCircles(src, circles_gold, true); + + cv::gpu::GpuMat d_circles; + cv::gpu::HoughCircles(loadMat(src, useRoi), d_circles, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + + std::vector circles; + cv::gpu::HoughCirclesDownload(d_circles, circles); + + ASSERT_FALSE(circles.empty()); + + for (size_t i = 0; i < circles.size(); ++i) + { + cv::Vec3f cur = circles[i]; + + bool found = false; + + for (size_t j = 0; j < circles_gold.size(); ++j) + { + cv::Vec3f gold = circles_gold[j]; + + if (std::fabs(cur[0] - gold[0]) < minDist && std::fabs(cur[1] - gold[1]) < minDist && std::fabs(cur[2] - gold[2]) < minDist) + { + found = true; + break; + } + } + + ASSERT_TRUE(found); + } +} + +INSTANTIATE_TEST_CASE_P(GPU_ImgProc, HoughCircles, testing::Combine( + ALL_DEVICES, + DIFFERENT_SIZES, + WHOLE_SUBMAT)); + } // namespace #endif // HAVE_CUDA From 8c1f9bafdc9f707d82a8155434425e119132b232 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 23 Aug 2012 17:00:12 +0400 Subject: [PATCH 065/163] fixed gpu::integral for Kepler --- modules/gpu/src/imgproc.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/gpu/src/imgproc.cpp b/modules/gpu/src/imgproc.cpp index 5b8fb9c057..eeaab7504b 100644 --- a/modules/gpu/src/imgproc.cpp +++ b/modules/gpu/src/imgproc.cpp @@ -551,13 +551,13 @@ void cv::gpu::integralBuffered(const GpuMat& src, GpuMat& sum, GpuMat& buffer, S if (info.supports(WARP_SHUFFLE_FUNCTIONS)) { - GpuMat src16; + GpuMat srcAlligned; - if (src.cols % 16 == 0) - src16 = src; + if (src.cols % 16 == 0 && src.rows % 8 == 0) + srcAlligned = src; else { - ensureSizeIsEnough(src.rows, ((src.cols + 15) / 16) * 16, src.type(), buffer); + ensureSizeIsEnough(((src.rows + 7) / 8) * 8, ((src.cols + 15) / 16) * 16, src.type(), buffer); GpuMat inner = buffer(Rect(0, 0, src.cols, src.rows)); @@ -572,21 +572,21 @@ void cv::gpu::integralBuffered(const GpuMat& src, GpuMat& sum, GpuMat& buffer, S src.copyTo(inner); } - src16 = buffer; + srcAlligned = buffer; } - sum.create(src16.rows + 1, src16.cols + 1, CV_32SC1); + sum.create(srcAlligned.rows + 1, srcAlligned.cols + 1, CV_32SC1); if (s) s.enqueueMemSet(sum, Scalar::all(0)); else sum.setTo(Scalar::all(0)); - GpuMat inner = sum(Rect(1, 1, src16.cols, src16.rows)); + GpuMat inner = sum(Rect(1, 1, srcAlligned.cols, srcAlligned.rows)); - cv::gpu::device::imgproc::shfl_integral_gpu(src16, inner, stream); + cv::gpu::device::imgproc::shfl_integral_gpu(srcAlligned, inner, stream); - if (src16.cols != src.cols) + if (srcAlligned.data != src.data) sum = sum(Rect(0, 0, src.cols + 1, src.rows + 1)); } else From 56b7ddad0909b7dd78ba132c5b07c283bfdd6a2a Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 23 Aug 2012 17:06:38 +0400 Subject: [PATCH 066/163] fixed type for threshold parameter --- modules/gpu/src/cuda/hough.cu | 4 ++-- modules/gpu/src/hough.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/gpu/src/cuda/hough.cu b/modules/gpu/src/cuda/hough.cu index 63099d3bcc..b4cb14776d 100644 --- a/modules/gpu/src/cuda/hough.cu +++ b/modules/gpu/src/cuda/hough.cu @@ -226,7 +226,7 @@ namespace cv { namespace gpu { namespace device //////////////////////////////////////////////////////////////////////// // linesGetResult - __global__ void linesGetResult(const DevMem2Di accum, float2* out, int* votes, const int maxSize, const float rho, const float theta, const float threshold, const int numrho) + __global__ void linesGetResult(const DevMem2Di accum, float2* out, int* votes, const int maxSize, const float rho, const float theta, const int threshold, const int numrho) { const int r = blockIdx.x * blockDim.x + threadIdx.x; const int n = blockIdx.y * blockDim.y + threadIdx.y; @@ -254,7 +254,7 @@ namespace cv { namespace gpu { namespace device } } - int linesGetResult_gpu(DevMem2Di accum, float2* out, int* votes, int maxSize, float rho, float theta, float threshold, bool doSort) + int linesGetResult_gpu(DevMem2Di accum, float2* out, int* votes, int maxSize, float rho, float theta, int threshold, bool doSort) { void* counterPtr; cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); diff --git a/modules/gpu/src/hough.cpp b/modules/gpu/src/hough.cpp index 82396e3fc6..57f60468ee 100644 --- a/modules/gpu/src/hough.cpp +++ b/modules/gpu/src/hough.cpp @@ -61,7 +61,7 @@ namespace cv { namespace gpu { namespace device int buildPointList_gpu(DevMem2Db src, unsigned int* list); void linesAccum_gpu(const unsigned int* list, int count, DevMem2Di accum, float rho, float theta, size_t sharedMemPerBlock, bool has20); - int linesGetResult_gpu(DevMem2Di accum, float2* out, int* votes, int maxSize, float rho, float theta, float threshold, bool doSort); + int linesGetResult_gpu(DevMem2Di accum, float2* out, int* votes, int maxSize, float rho, float theta, int threshold, bool doSort); void circlesAccumCenters_gpu(const unsigned int* list, int count, PtrStepi dx, PtrStepi dy, DevMem2Di accum, int minRadius, int maxRadius, float idp); int buildCentersList_gpu(DevMem2Di accum, unsigned int* centers, int threshold); From 70204a8e6874b8dfbf3f702cd969d7005d2241b0 Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Thu, 23 Aug 2012 17:45:50 +0400 Subject: [PATCH 067/163] Removed PtrElemStep, Marked DevMem1D as deprecated, now should use PtrStepSz now --- .../core/{devmem2d.hpp => cuda_devptrs.hpp} | 321 ++-- modules/core/include/opencv2/core/gpumat.hpp | 24 +- modules/core/src/cuda/matrix_operations.cu | 62 +- modules/core/src/gpumat.cpp | 35 +- modules/gpu/doc/data_structures.rst | 60 +- modules/gpu/include/opencv2/gpu/devmem2d.hpp | 2 +- modules/gpu/src/arithm.cpp | 4 +- modules/gpu/src/bgfg_gmg.cpp | 4 +- modules/gpu/src/bgfg_mog.cpp | 8 +- modules/gpu/src/bgfg_vibe.cpp | 4 +- modules/gpu/src/bilateral_filter.cpp | 8 +- modules/gpu/src/brute_force_matcher.cpp | 108 +- modules/gpu/src/calib3d.cpp | 4 +- modules/gpu/src/cascadeclassifier.cpp | 16 +- modules/gpu/src/color.cpp | 8 +- modules/gpu/src/cuda/NV12ToARGB.cu | 2 +- modules/gpu/src/cuda/bf_knnmatch.cu | 222 +-- modules/gpu/src/cuda/bf_match.cu | 174 +- modules/gpu/src/cuda/bf_radius_match.cu | 142 +- modules/gpu/src/cuda/bgfg_gmg.cu | 24 +- modules/gpu/src/cuda/bgfg_mog.cu | 64 +- modules/gpu/src/cuda/bgfg_vibe.cu | 20 +- modules/gpu/src/cuda/bilateral_filter.cu | 8 +- modules/gpu/src/cuda/calib3d.cu | 8 +- modules/gpu/src/cuda/ccomponetns.cu | 34 +- modules/gpu/src/cuda/color.cu | 4 +- modules/gpu/src/cuda/column_filter.cu | 20 +- modules/gpu/src/cuda/copy_make_border.cu | 58 +- modules/gpu/src/cuda/debayer.cu | 20 +- modules/gpu/src/cuda/element_operations.cu | 1676 ++++++++--------- modules/gpu/src/cuda/fast.cu | 8 +- modules/gpu/src/cuda/fgd_bgfg.cu | 78 +- modules/gpu/src/cuda/fgd_bgfg_common.hpp | 14 +- modules/gpu/src/cuda/gftt.cu | 4 +- modules/gpu/src/cuda/global_motion.cu | 4 +- modules/gpu/src/cuda/hist.cu | 8 +- modules/gpu/src/cuda/hog.cu | 48 +- modules/gpu/src/cuda/hough.cu | 18 +- modules/gpu/src/cuda/imgproc.cu | 80 +- modules/gpu/src/cuda/integral_image.cu | 8 +- modules/gpu/src/cuda/lbp.cu | 8 +- modules/gpu/src/cuda/match_template.cu | 126 +- modules/gpu/src/cuda/mathfunc.cu | 12 +- modules/gpu/src/cuda/matrix_reductions.cu | 316 ++-- modules/gpu/src/cuda/optical_flow.cu | 8 +- .../gpu/src/cuda/optical_flow_farneback.cu | 30 +- modules/gpu/src/cuda/orb.cu | 4 +- modules/gpu/src/cuda/pyr_down.cu | 54 +- modules/gpu/src/cuda/pyr_up.cu | 56 +- modules/gpu/src/cuda/pyrlk.cu | 8 +- modules/gpu/src/cuda/remap.cu | 78 +- modules/gpu/src/cuda/resize.cu | 76 +- modules/gpu/src/cuda/rgb_to_yv12.cu | 14 +- modules/gpu/src/cuda/row_filter.cu | 20 +- modules/gpu/src/cuda/split_merge.cu | 20 +- modules/gpu/src/cuda/stereobm.cu | 14 +- modules/gpu/src/cuda/stereobp.cu | 102 +- modules/gpu/src/cuda/stereocsbp.cu | 8 +- modules/gpu/src/cuda/surf.cu | 8 +- modules/gpu/src/cuda/warp.cu | 128 +- modules/gpu/src/cvt_colot_internal.h | 2 +- modules/gpu/src/element_operations.cpp | 150 +- modules/gpu/src/fast.cpp | 6 +- modules/gpu/src/fgd_bgfg.cpp | 10 +- modules/gpu/src/filtering.cpp | 10 +- modules/gpu/src/gftt.cpp | 4 +- modules/gpu/src/global_motion.cpp | 2 +- modules/gpu/src/graphcuts.cpp | 6 +- modules/gpu/src/hog.cpp | 20 +- modules/gpu/src/hough.cpp | 10 +- modules/gpu/src/imgproc.cpp | 50 +- modules/gpu/src/match_template.cpp | 74 +- modules/gpu/src/matrix_reductions.cpp | 56 +- modules/gpu/src/nvidia/core/NCVPyramid.cu | 40 +- modules/gpu/src/opencv2/gpu/device/common.hpp | 4 +- .../gpu/device/detail/transform_detail.hpp | 16 +- .../gpu/src/opencv2/gpu/device/transform.hpp | 4 +- modules/gpu/src/optical_flow.cpp | 4 +- modules/gpu/src/optical_flow_farneback.cpp | 20 +- modules/gpu/src/orb.cpp | 4 +- modules/gpu/src/pyramids.cpp | 16 +- modules/gpu/src/pyrlk.cpp | 12 +- modules/gpu/src/remap.cpp | 6 +- modules/gpu/src/resize.cpp | 8 +- modules/gpu/src/split_merge.cpp | 12 +- modules/gpu/src/stereobm.cpp | 6 +- modules/gpu/src/stereobp.cpp | 32 +- modules/gpu/src/stereocsbp.cpp | 4 +- modules/gpu/src/surf.cpp | 8 +- modules/gpu/src/video_reader.cpp | 2 +- modules/gpu/src/video_writer.cpp | 2 +- modules/gpu/src/warp.cpp | 16 +- modules/gpu/test/test_imgproc.cpp | 10 +- modules/imgproc/src/imgwarp.cpp | 28 +- modules/video/src/bgfg_gmg.cpp | 2 +- 95 files changed, 2597 insertions(+), 2563 deletions(-) rename modules/core/include/opencv2/core/{devmem2d.hpp => cuda_devptrs.hpp} (77%) diff --git a/modules/core/include/opencv2/core/devmem2d.hpp b/modules/core/include/opencv2/core/cuda_devptrs.hpp similarity index 77% rename from modules/core/include/opencv2/core/devmem2d.hpp rename to modules/core/include/opencv2/core/cuda_devptrs.hpp index 276aeb2331..257f5960e5 100644 --- a/modules/core/include/opencv2/core/devmem2d.hpp +++ b/modules/core/include/opencv2/core/cuda_devptrs.hpp @@ -1,161 +1,160 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other GpuMaterials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_CORE_DevMem2D_HPP__ -#define __OPENCV_CORE_DevMem2D_HPP__ - -#ifdef __cplusplus - -#ifdef __CUDACC__ - #define __CV_GPU_HOST_DEVICE__ __host__ __device__ __forceinline__ -#else - #define __CV_GPU_HOST_DEVICE__ -#endif - -namespace cv -{ - namespace gpu - { - // Simple lightweight structures that encapsulates information about an image on device. - // It is intended to pass to nvcc-compiled code. GpuMat depends on headers that nvcc can't compile - - template struct StaticAssert; - template <> struct StaticAssert {static __CV_GPU_HOST_DEVICE__ void check(){}}; - - template struct DevPtr - { - typedef T elem_type; - typedef int index_type; - - enum { elem_size = sizeof(elem_type) }; - - T* data; - - __CV_GPU_HOST_DEVICE__ DevPtr() : data(0) {} - __CV_GPU_HOST_DEVICE__ DevPtr(T* data_) : data(data_) {} - - __CV_GPU_HOST_DEVICE__ size_t elemSize() const { return elem_size; } - __CV_GPU_HOST_DEVICE__ operator T*() { return data; } - __CV_GPU_HOST_DEVICE__ operator const T*() const { return data; } - }; - - template struct PtrSz : public DevPtr - { - __CV_GPU_HOST_DEVICE__ PtrSz() : size(0) {} - __CV_GPU_HOST_DEVICE__ PtrSz(T* data_, size_t size_) : DevPtr(data_), size(size_) {} - - size_t size; - }; - - template struct PtrStep : public DevPtr - { - __CV_GPU_HOST_DEVICE__ PtrStep() : step(0) {} - __CV_GPU_HOST_DEVICE__ PtrStep(T* data_, size_t step_) : DevPtr(data_), step(step_) {} - - /** \brief stride between two consecutive rows in bytes. Step is stored always and everywhere in bytes!!! */ - size_t step; - - __CV_GPU_HOST_DEVICE__ T* ptr(int y = 0) { return ( T*)( ( char*)DevPtr::data + y * step); } - __CV_GPU_HOST_DEVICE__ const T* ptr(int y = 0) const { return (const T*)( (const char*)DevPtr::data + y * step); } - - __CV_GPU_HOST_DEVICE__ T& operator ()(int y, int x) { return ptr(y)[x]; } - __CV_GPU_HOST_DEVICE__ const T& operator ()(int y, int x) const { return ptr(y)[x]; } - }; - - template struct PtrStepSz : public PtrStep - { - __CV_GPU_HOST_DEVICE__ PtrStepSz() : cols(0), rows(0) {} - __CV_GPU_HOST_DEVICE__ PtrStepSz(int rows_, int cols_, T* data_, size_t step_) - : PtrStep(data_, step_), cols(cols_), rows(rows_) {} - - int cols; - int rows; - }; - - template struct DevMem2D_ : public PtrStepSz - { - DevMem2D_() {} - DevMem2D_(int rows_, int cols_, T* data_, size_t step_) : PtrStepSz(rows_, cols_, data_, step_) {} - - template - explicit DevMem2D_(const DevMem2D_& d) : PtrStepSz(d.rows, d.cols, (T*)d.data, d.step) {} - }; - - template struct PtrElemStep_ : public PtrStep - { - PtrElemStep_(const DevMem2D_& mem) : PtrStep(mem.data, mem.step) - { - StaticAssert<256 % sizeof(T) == 0>::check(); - - PtrStep::step /= PtrStep::elem_size; - } - __CV_GPU_HOST_DEVICE__ T* ptr(int y = 0) { return PtrStep::data + y * PtrStep::step; } - __CV_GPU_HOST_DEVICE__ const T* ptr(int y = 0) const { return PtrStep::data + y * PtrStep::step; } - - __CV_GPU_HOST_DEVICE__ T& operator ()(int y, int x) { return ptr(y)[x]; } - __CV_GPU_HOST_DEVICE__ const T& operator ()(int y, int x) const { return ptr(y)[x]; } - }; - - template struct PtrStep_ : public PtrStep - { - PtrStep_() {} - PtrStep_(const DevMem2D_& mem) : PtrStep(mem.data, mem.step) {} - }; - - typedef DevMem2D_ DevMem2Db; - typedef DevMem2Db DevMem2D; - typedef DevMem2D_ DevMem2Df; - typedef DevMem2D_ DevMem2Di; - - typedef PtrStep PtrStepb; - typedef PtrStep PtrStepf; - typedef PtrStep PtrStepi; - - typedef PtrElemStep_ PtrElemStep; - typedef PtrElemStep_ PtrElemStepf; - typedef PtrElemStep_ PtrElemStepi; - } -} - -#endif // __cplusplus - -#endif /* __OPENCV_GPU_DevMem2D_HPP__ */ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other GpuMaterials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_CORE_DEVPTRS_HPP__ +#define __OPENCV_CORE_DEVPTRS_HPP__ + +#ifdef __cplusplus + +#ifdef __CUDACC__ + #define __CV_GPU_HOST_DEVICE__ __host__ __device__ __forceinline__ +#else + #define __CV_GPU_HOST_DEVICE__ +#endif + +namespace cv +{ + namespace gpu + { + // Simple lightweight structures that encapsulates information about an image on device. + // It is intended to pass to nvcc-compiled code. GpuMat depends on headers that nvcc can't compile + + template struct StaticAssert; + template <> struct StaticAssert {static __CV_GPU_HOST_DEVICE__ void check(){}}; + + template struct DevPtr + { + typedef T elem_type; + typedef int index_type; + + enum { elem_size = sizeof(elem_type) }; + + T* data; + + __CV_GPU_HOST_DEVICE__ DevPtr() : data(0) {} + __CV_GPU_HOST_DEVICE__ DevPtr(T* data_) : data(data_) {} + + __CV_GPU_HOST_DEVICE__ size_t elemSize() const { return elem_size; } + __CV_GPU_HOST_DEVICE__ operator T*() { return data; } + __CV_GPU_HOST_DEVICE__ operator const T*() const { return data; } + }; + + template struct PtrSz : public DevPtr + { + __CV_GPU_HOST_DEVICE__ PtrSz() : size(0) {} + __CV_GPU_HOST_DEVICE__ PtrSz(T* data_, size_t size_) : DevPtr(data_), size(size_) {} + + size_t size; + }; + + template struct PtrStep : public DevPtr + { + __CV_GPU_HOST_DEVICE__ PtrStep() : step(0) {} + __CV_GPU_HOST_DEVICE__ PtrStep(T* data_, size_t step_) : DevPtr(data_), step(step_) {} + + /** \brief stride between two consecutive rows in bytes. Step is stored always and everywhere in bytes!!! */ + size_t step; + + __CV_GPU_HOST_DEVICE__ T* ptr(int y = 0) { return ( T*)( ( char*)DevPtr::data + y * step); } + __CV_GPU_HOST_DEVICE__ const T* ptr(int y = 0) const { return (const T*)( (const char*)DevPtr::data + y * step); } + + __CV_GPU_HOST_DEVICE__ T& operator ()(int y, int x) { return ptr(y)[x]; } + __CV_GPU_HOST_DEVICE__ const T& operator ()(int y, int x) const { return ptr(y)[x]; } + }; + + template struct PtrStepSz : public PtrStep + { + __CV_GPU_HOST_DEVICE__ PtrStepSz() : cols(0), rows(0) {} + __CV_GPU_HOST_DEVICE__ PtrStepSz(int rows_, int cols_, T* data_, size_t step_) + : PtrStep(data_, step_), cols(cols_), rows(rows_) {} + + template + explicit PtrStepSz(const PtrStepSz& d) : PtrStep((T*)d.data, d.step), cols(d.cols), rows(d.rows){} + + int cols; + int rows; + }; + + typedef PtrStepSz PtrStepSzb; + typedef PtrStepSz PtrStepSzf; + typedef PtrStepSz PtrStepSzi; + + typedef PtrStep PtrStepb; + typedef PtrStep PtrStepf; + typedef PtrStep PtrStepi; + + +#if defined __GNUC__ + #define __CV_GPU_DEPR_BEFORE__ + #define __CV_GPU_DEPR_AFTER__ __attribute__ ((deprecated)) +#elif defined(__MSVC__) //|| defined(__CUDACC__) + #pragma deprecated(DevMem2D_) + #define __CV_GPU_DEPR_BEFORE__ __declspec(deprecated) + #define __CV_GPU_DEPR_AFTER__ +#else + #define __CV_GPU_DEPR_BEFORE__ + #define __CV_GPU_DEPR_AFTER__ +#endif + + template struct __CV_GPU_DEPR_BEFORE__ DevMem2D_ : public PtrStepSz + { + DevMem2D_() {} + DevMem2D_(int rows_, int cols_, T* data_, size_t step_) : PtrStepSz(rows_, cols_, data_, step_) {} + + template + explicit __CV_GPU_DEPR_BEFORE__ DevMem2D_(const DevMem2D_& d) : PtrStepSz(d.rows, d.cols, (T*)d.data, d.step) {} + } __CV_GPU_DEPR_AFTER__ ; + + typedef DevMem2D_ DevMem2Db; + typedef DevMem2Db DevMem2D; + typedef DevMem2D_ DevMem2Df; + typedef DevMem2D_ DevMem2Di; + +//#undef __CV_GPU_DEPR_BEFORE__ +//#undef __CV_GPU_DEPR_AFTER__ + + } +} + +#endif // __cplusplus + +#endif /* __OPENCV_CORE_DEVPTRS_HPP__ */ diff --git a/modules/core/include/opencv2/core/gpumat.hpp b/modules/core/include/opencv2/core/gpumat.hpp index e09f1bc4c3..c0ae17b268 100644 --- a/modules/core/include/opencv2/core/gpumat.hpp +++ b/modules/core/include/opencv2/core/gpumat.hpp @@ -46,7 +46,7 @@ #ifdef __cplusplus #include "opencv2/core/core.hpp" -#include "opencv2/core/devmem2d.hpp" +#include "opencv2/core/cuda_devptrs.hpp" namespace cv { namespace gpu { @@ -268,10 +268,14 @@ namespace cv { namespace gpu template _Tp* ptr(int y = 0); template const _Tp* ptr(int y = 0) const; - template operator DevMem2D_<_Tp>() const; - template operator PtrStep_<_Tp>() const; + template operator PtrStepSz<_Tp>() const; template operator PtrStep<_Tp>() const; + // Deprecated function + __CV_GPU_DEPR_BEFORE__ template operator DevMem2D_<_Tp>() const __CV_GPU_DEPR_AFTER__; + #undef __CV_GPU_DEPR_BEFORE__ + #undef __CV_GPU_DEPR_AFTER__ + /*! includes several bit-fields: - the magic signature - continuity flag @@ -502,14 +506,9 @@ namespace cv { namespace gpu return *this; } - template inline GpuMat::operator DevMem2D_() const + template inline GpuMat::operator PtrStepSz() const { - return DevMem2D_(rows, cols, (T*)data, step); - } - - template inline GpuMat::operator PtrStep_() const - { - return PtrStep_(static_cast< DevMem2D_ >(*this)); + return PtrStepSz(rows, cols, (T*)data, step); } template inline GpuMat::operator PtrStep() const @@ -517,6 +516,11 @@ namespace cv { namespace gpu return PtrStep((T*)data, step); } + template inline GpuMat::operator DevMem2D_() const + { + return DevMem2D_(rows, cols, (T*)data, step); + } + inline GpuMat createContinuous(int rows, int cols, int type) { GpuMat m; diff --git a/modules/core/src/cuda/matrix_operations.cu b/modules/core/src/cuda/matrix_operations.cu index 671fa5fc31..f475136c87 100644 --- a/modules/core/src/cuda/matrix_operations.cu +++ b/modules/core/src/cuda/matrix_operations.cu @@ -44,6 +44,18 @@ #include "opencv2/gpu/device/transform.hpp" #include "opencv2/gpu/device/functional.hpp" +namespace cv { namespace gpu { namespace device +{ + void writeScalar(const uchar*); + void writeScalar(const schar*); + void writeScalar(const ushort*); + void writeScalar(const short int*); + void writeScalar(const int*); + void writeScalar(const float*); + void writeScalar(const double*); + void convert_gpu(PtrStepSzb, int, PtrStepSzb, int, double, double, cudaStream_t); +}}} + namespace cv { namespace gpu { namespace device { template struct shift_and_sizeof; @@ -59,17 +71,17 @@ namespace cv { namespace gpu { namespace device ////////////////////////////////// CopyTo ///////////////////////////////// /////////////////////////////////////////////////////////////////////////// - template void copyToWithMask(DevMem2Db src, DevMem2Db dst, int cn, DevMem2Db mask, bool colorMask, cudaStream_t stream) + template void copyToWithMask(PtrStepSzb src, PtrStepSzb dst, int cn, PtrStepSzb mask, bool colorMask, cudaStream_t stream) { if (colorMask) - cv::gpu::device::transform((DevMem2D_)src, (DevMem2D_)dst, identity(), SingleMask(mask), stream); + cv::gpu::device::transform((PtrStepSz)src, (PtrStepSz)dst, identity(), SingleMask(mask), stream); else - cv::gpu::device::transform((DevMem2D_)src, (DevMem2D_)dst, identity(), SingleMaskChannels(mask, cn), stream); + cv::gpu::device::transform((PtrStepSz)src, (PtrStepSz)dst, identity(), SingleMaskChannels(mask, cn), stream); } - void copyToWithMask_gpu(DevMem2Db src, DevMem2Db dst, size_t elemSize1, int cn, DevMem2Db mask, bool colorMask, cudaStream_t stream) + void copyToWithMask_gpu(PtrStepSzb src, PtrStepSzb dst, size_t elemSize1, int cn, PtrStepSzb mask, bool colorMask, cudaStream_t stream) { - typedef void (*func_t)(DevMem2Db src, DevMem2Db dst, int cn, DevMem2Db mask, bool colorMask, cudaStream_t stream); + typedef void (*func_t)(PtrStepSzb src, PtrStepSzb dst, int cn, PtrStepSzb mask, bool colorMask, cudaStream_t stream); static func_t tab[] = { @@ -164,7 +176,7 @@ namespace cv { namespace gpu { namespace device } } template - void set_to_gpu(DevMem2Db mat, const T* scalar, DevMem2Db mask, int channels, cudaStream_t stream) + void set_to_gpu(PtrStepSzb mat, const T* scalar, PtrStepSzb mask, int channels, cudaStream_t stream) { writeScalar(scalar); @@ -178,16 +190,16 @@ namespace cv { namespace gpu { namespace device cudaSafeCall ( cudaDeviceSynchronize() ); } - template void set_to_gpu(DevMem2Db mat, const uchar* scalar, DevMem2Db mask, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const schar* scalar, DevMem2Db mask, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const ushort* scalar, DevMem2Db mask, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const short* scalar, DevMem2Db mask, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const int* scalar, DevMem2Db mask, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const float* scalar, DevMem2Db mask, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const double* scalar, DevMem2Db mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const uchar* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const schar* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const ushort* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const short* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const int* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const float* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const double* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); template - void set_to_gpu(DevMem2Db mat, const T* scalar, int channels, cudaStream_t stream) + void set_to_gpu(PtrStepSzb mat, const T* scalar, int channels, cudaStream_t stream) { writeScalar(scalar); @@ -201,13 +213,13 @@ namespace cv { namespace gpu { namespace device cudaSafeCall ( cudaDeviceSynchronize() ); } - template void set_to_gpu(DevMem2Db mat, const uchar* scalar, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const schar* scalar, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const ushort* scalar, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const short* scalar, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const int* scalar, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const float* scalar, int channels, cudaStream_t stream); - template void set_to_gpu(DevMem2Db mat, const double* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const uchar* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const schar* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const ushort* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const short* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const int* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const float* scalar, int channels, cudaStream_t stream); + template void set_to_gpu(PtrStepSzb mat, const double* scalar, int channels, cudaStream_t stream); /////////////////////////////////////////////////////////////////////////// //////////////////////////////// ConvertTo //////////////////////////////// @@ -274,12 +286,12 @@ namespace cv { namespace gpu { namespace device }; template - void cvt_(DevMem2Db src, DevMem2Db dst, double alpha, double beta, cudaStream_t stream) + void cvt_(PtrStepSzb src, PtrStepSzb dst, double alpha, double beta, cudaStream_t stream) { cudaSafeCall( cudaSetDoubleForDevice(&alpha) ); cudaSafeCall( cudaSetDoubleForDevice(&beta) ); Convertor op(alpha, beta); - cv::gpu::device::transform((DevMem2D_)src, (DevMem2D_)dst, op, WithOutMask(), stream); + cv::gpu::device::transform((PtrStepSz)src, (PtrStepSz)dst, op, WithOutMask(), stream); } #if defined __clang__ @@ -287,9 +299,9 @@ namespace cv { namespace gpu { namespace device # pragma clang diagnostic ignored "-Wmissing-declarations" #endif - void convert_gpu(DevMem2Db src, int sdepth, DevMem2Db dst, int ddepth, double alpha, double beta, cudaStream_t stream) + void convert_gpu(PtrStepSzb src, int sdepth, PtrStepSzb dst, int ddepth, double alpha, double beta, cudaStream_t stream) { - typedef void (*caller_t)(DevMem2Db src, DevMem2Db dst, double alpha, double beta, cudaStream_t stream); + typedef void (*caller_t)(PtrStepSzb src, PtrStepSzb dst, double alpha, double beta, cudaStream_t stream); static const caller_t tab[8][8] = { diff --git a/modules/core/src/gpumat.cpp b/modules/core/src/gpumat.cpp index 105a5ff15f..07d7363868 100644 --- a/modules/core/src/gpumat.cpp +++ b/modules/core/src/gpumat.cpp @@ -761,15 +761,15 @@ namespace namespace cv { namespace gpu { namespace device { - void copyToWithMask_gpu(DevMem2Db src, DevMem2Db dst, size_t elemSize1, int cn, DevMem2Db mask, bool colorMask, cudaStream_t stream); + void copyToWithMask_gpu(PtrStepSzb src, PtrStepSzb dst, size_t elemSize1, int cn, PtrStepSzb mask, bool colorMask, cudaStream_t stream); template - void set_to_gpu(DevMem2Db mat, const T* scalar, int channels, cudaStream_t stream); + void set_to_gpu(PtrStepSzb mat, const T* scalar, int channels, cudaStream_t stream); template - void set_to_gpu(DevMem2Db mat, const T* scalar, DevMem2Db mask, int channels, cudaStream_t stream); + void set_to_gpu(PtrStepSzb mat, const T* scalar, PtrStepSzb mask, int channels, cudaStream_t stream); - void convert_gpu(DevMem2Db src, int sdepth, DevMem2Db dst, int ddepth, double alpha, double beta, cudaStream_t stream); + void convert_gpu(PtrStepSzb src, int sdepth, PtrStepSzb dst, int ddepth, double alpha, double beta, cudaStream_t stream); }}} namespace @@ -787,9 +787,22 @@ namespace } } + namespace cv { namespace gpu { - CV_EXPORTS void copyWithMask(const GpuMat& src, GpuMat& dst, const GpuMat& mask, cudaStream_t stream = 0) + CV_EXPORTS void copyWithMask(const cv::gpu::GpuMat&, cv::gpu::GpuMat&, const cv::gpu::GpuMat&, CUstream_st*); + CV_EXPORTS void convertTo(const cv::gpu::GpuMat&, cv::gpu::GpuMat&); + CV_EXPORTS void convertTo(const cv::gpu::GpuMat&, cv::gpu::GpuMat&, double, double, CUstream_st*); + CV_EXPORTS void setTo(cv::gpu::GpuMat&, cv::Scalar, CUstream_st*); + CV_EXPORTS void setTo(cv::gpu::GpuMat&, cv::Scalar, const cv::gpu::GpuMat&, CUstream_st*); + CV_EXPORTS void setTo(cv::gpu::GpuMat&, cv::Scalar); + CV_EXPORTS void setTo(cv::gpu::GpuMat&, cv::Scalar, const cv::gpu::GpuMat&); +}} + + +namespace cv { namespace gpu +{ + void copyWithMask(const GpuMat& src, GpuMat& dst, const GpuMat& mask, cudaStream_t stream = 0) { CV_Assert(src.size() == dst.size() && src.type() == dst.type()); CV_Assert(src.size() == mask.size() && mask.depth() == CV_8U && (mask.channels() == 1 || mask.channels() == src.channels())); @@ -797,17 +810,17 @@ namespace cv { namespace gpu cv::gpu::device::copyToWithMask_gpu(src.reshape(1), dst.reshape(1), src.elemSize1(), src.channels(), mask.reshape(1), mask.channels() != 1, stream); } - CV_EXPORTS void convertTo(const GpuMat& src, GpuMat& dst) + void convertTo(const GpuMat& src, GpuMat& dst) { cv::gpu::device::convert_gpu(src.reshape(1), src.depth(), dst.reshape(1), dst.depth(), 1.0, 0.0, 0); } - CV_EXPORTS void convertTo(const GpuMat& src, GpuMat& dst, double alpha, double beta, cudaStream_t stream = 0) + void convertTo(const GpuMat& src, GpuMat& dst, double alpha, double beta, cudaStream_t stream = 0) { cv::gpu::device::convert_gpu(src.reshape(1), src.depth(), dst.reshape(1), dst.depth(), alpha, beta, stream); } - CV_EXPORTS void setTo(GpuMat& src, Scalar s, cudaStream_t stream) + void setTo(GpuMat& src, Scalar s, cudaStream_t stream) { typedef void (*caller_t)(GpuMat& src, Scalar s, cudaStream_t stream); @@ -820,7 +833,7 @@ namespace cv { namespace gpu callers[src.depth()](src, s, stream); } - CV_EXPORTS void setTo(GpuMat& src, Scalar s, const GpuMat& mask, cudaStream_t stream) + void setTo(GpuMat& src, Scalar s, const GpuMat& mask, cudaStream_t stream) { typedef void (*caller_t)(GpuMat& src, Scalar s, const GpuMat& mask, cudaStream_t stream); @@ -833,12 +846,12 @@ namespace cv { namespace gpu callers[src.depth()](src, s, mask, stream); } - CV_EXPORTS void setTo(GpuMat& src, Scalar s) + void setTo(GpuMat& src, Scalar s) { setTo(src, s, 0); } - CV_EXPORTS void setTo(GpuMat& src, Scalar s, const GpuMat& mask) + void setTo(GpuMat& src, Scalar s, const GpuMat& mask) { setTo(src, s, mask, 0); } diff --git a/modules/gpu/doc/data_structures.rst b/modules/gpu/doc/data_structures.rst index 3152c510b4..68e702a793 100644 --- a/modules/gpu/doc/data_structures.rst +++ b/modules/gpu/doc/data_structures.rst @@ -5,24 +5,24 @@ Data Structures -gpu::DevMem2D\_ +gpu::PtrStepSz --------------- -.. ocv:class:: gpu::DevMem2D\_ +.. ocv:class:: gpu::PtrStepSz Lightweight class encapsulating pitched memory on a GPU and passed to nvcc-compiled code (CUDA kernels). Typically, it is used internally by OpenCV and by users who write device code. You can call its members from both host and device code. :: - template struct DevMem2D_ + template struct PtrStepSz { int cols; int rows; T* data; size_t step; - DevMem2D_() : cols(0), rows(0), data(0), step(0){}; - DevMem2D_(int rows, int cols, T *data, size_t step); + PtrStepSz() : cols(0), rows(0), data(0), step(0){}; + PtrStepSz(int rows, int cols, T *data, size_t step); template - explicit DevMem2D_(const DevMem2D_& d); + explicit PtrStepSz(const PtrStepSz& d); typedef T elem_type; enum { elem_size = sizeof(elem_type) }; @@ -34,25 +34,25 @@ Lightweight class encapsulating pitched memory on a GPU and passed to nvcc-compi __CV_GPU_HOST_DEVICE__ const T* ptr(int y = 0) const; }; - typedef DevMem2D_ DevMem2D; - typedef DevMem2D_ DevMem2Df; - typedef DevMem2D_ DevMem2Di; + typedef PtrStepSz PtrStepSzb; + typedef PtrStepSz PtrStepSzf; + typedef PtrStepSz PtrStepSzi; -gpu::PtrStep\_ +gpu::PtrStep -------------- -.. ocv:class:: gpu::PtrStep\_ +.. ocv:class:: gpu::PtrStep -Structure similar to :ocv:class:`gpu::DevMem2D_` but containing only a pointer and row step. Width and height fields are excluded due to performance reasons. The structure is intended for internal use or for users who write device code. :: +Structure similar to :ocv:class:`gpu::PtrStepSz` but containing only a pointer and row step. Width and height fields are excluded due to performance reasons. The structure is intended for internal use or for users who write device code. :: - template struct PtrStep_ + template struct PtrStep { T* data; size_t step; - PtrStep_(); - PtrStep_(const DevMem2D_& mem); + PtrStep(); + PtrStep(const PtrStepSz& mem); typedef T elem_type; enum { elem_size = sizeof(elem_type) }; @@ -62,25 +62,9 @@ Structure similar to :ocv:class:`gpu::DevMem2D_` but containing only a pointer a __CV_GPU_HOST_DEVICE__ const T* ptr(int y = 0) const; }; - typedef PtrStep_ PtrStep; - typedef PtrStep_ PtrStepf; - typedef PtrStep_ PtrStepi; - - - -gpu::PtrElemStep\_ ------------------- -.. ocv:class:: gpu::PtrElemStep\_ - -Structure similar to :ocv:class:`gpu::DevMem2D_` but containing only a pointer and a row step in elements. Width and height fields are excluded due to performance reasons. This class can only be constructed if ``sizeof(T)`` is a multiple of 256. The structure is intended for internal use or for users who write device code. :: - - template struct PtrElemStep_ : public PtrStep_ - { - PtrElemStep_(const DevMem2D_& mem); - __CV_GPU_HOST_DEVICE__ T* ptr(int y = 0); - __CV_GPU_HOST_DEVICE__ const T* ptr(int y = 0) const; - }; - + typedef PtrStep PtrStep; + typedef PtrStep PtrStepf; + typedef PtrStep PtrStepi; gpu::GpuMat @@ -93,7 +77,7 @@ Base storage class for GPU memory with reference counting. Its interface matches * no functions that return references to their data (because references on GPU are not valid for CPU) * no expression templates technique support -Beware that the latter limitation may lead to overloaded matrix operators that cause memory allocations. The ``GpuMat`` class is convertible to :ocv:class:`gpu::DevMem2D_` and :ocv:class:`gpu::PtrStep_` so it can be passed directly to the kernel. +Beware that the latter limitation may lead to overloaded matrix operators that cause memory allocations. The ``GpuMat`` class is convertible to :ocv:class:`gpu::PtrStepSz` and :ocv:class:`gpu::PtrStep` so it can be passed directly to the kernel. .. note:: In contrast with :ocv:class:`Mat`, in most cases ``GpuMat::isContinuous() == false`` . This means that rows are aligned to a size depending on the hardware. Single-row ``GpuMat`` is always a continuous matrix. @@ -113,10 +97,10 @@ Beware that the latter limitation may lead to overloaded matrix operators that c //! builds GpuMat from Mat. Blocks uploading to device. explicit GpuMat (const Mat& m); - //! returns lightweight DevMem2D_ structure for passing + //! returns lightweight PtrStepSz structure for passing //to nvcc-compiled code. Contains size, data ptr and step. - template operator DevMem2D_() const; - template operator PtrStep_() const; + template operator PtrStepSz() const; + template operator PtrStep() const; //! blocks uploading data to GpuMat. void upload(const cv::Mat& m); diff --git a/modules/gpu/include/opencv2/gpu/devmem2d.hpp b/modules/gpu/include/opencv2/gpu/devmem2d.hpp index 33af66afa1..6d4bc50557 100644 --- a/modules/gpu/include/opencv2/gpu/devmem2d.hpp +++ b/modules/gpu/include/opencv2/gpu/devmem2d.hpp @@ -40,4 +40,4 @@ // //M*/ -#include "opencv2/core/devmem2d.hpp" +#include "opencv2/core/cuda_devptrs.hpp" diff --git a/modules/gpu/src/arithm.cpp b/modules/gpu/src/arithm.cpp index 45196a522b..67f3936f99 100644 --- a/modules/gpu/src/arithm.cpp +++ b/modules/gpu/src/arithm.cpp @@ -454,8 +454,8 @@ namespace cv { namespace gpu { namespace device { namespace mathfunc { - void cartToPolar_gpu(DevMem2Df x, DevMem2Df y, DevMem2Df mag, bool magSqr, DevMem2Df angle, bool angleInDegrees, cudaStream_t stream); - void polarToCart_gpu(DevMem2Df mag, DevMem2Df angle, DevMem2Df x, DevMem2Df y, bool angleInDegrees, cudaStream_t stream); + void cartToPolar_gpu(PtrStepSzf x, PtrStepSzf y, PtrStepSzf mag, bool magSqr, PtrStepSzf angle, bool angleInDegrees, cudaStream_t stream); + void polarToCart_gpu(PtrStepSzf mag, PtrStepSzf angle, PtrStepSzf x, PtrStepSzf y, bool angleInDegrees, cudaStream_t stream); } }}} diff --git a/modules/gpu/src/bgfg_gmg.cpp b/modules/gpu/src/bgfg_gmg.cpp index 6e0ed9e631..f4133f4ff5 100644 --- a/modules/gpu/src/bgfg_gmg.cpp +++ b/modules/gpu/src/bgfg_gmg.cpp @@ -58,7 +58,7 @@ namespace cv { namespace gpu { namespace device { float decisionThreshold, int maxFeatures, int numInitializationFrames); template - void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, + void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); } }}} @@ -109,7 +109,7 @@ void cv::gpu::GMG_GPU::operator ()(const cv::gpu::GpuMat& frame, cv::gpu::GpuMat { using namespace cv::gpu::device::bgfg_gmg; - typedef void (*func_t)(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, + typedef void (*func_t)(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); static const func_t funcs[6][4] = { diff --git a/modules/gpu/src/bgfg_mog.cpp b/modules/gpu/src/bgfg_mog.cpp index 7c0e924d0d..94668e817f 100644 --- a/modules/gpu/src/bgfg_mog.cpp +++ b/modules/gpu/src/bgfg_mog.cpp @@ -62,14 +62,14 @@ namespace cv { namespace gpu { namespace device { namespace mog { - void mog_gpu(DevMem2Db frame, int cn, DevMem2Db fgmask, DevMem2Df weight, DevMem2Df sortKey, DevMem2Db mean, DevMem2Db var, + void mog_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzf weight, PtrStepSzf sortKey, PtrStepSzb mean, PtrStepSzb var, int nmixtures, float varThreshold, float learningRate, float backgroundRatio, float noiseSigma, cudaStream_t stream); - void getBackgroundImage_gpu(int cn, DevMem2Df weight, DevMem2Db mean, DevMem2Db dst, int nmixtures, float backgroundRatio, cudaStream_t stream); + void getBackgroundImage_gpu(int cn, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, int nmixtures, float backgroundRatio, cudaStream_t stream); void loadConstants(int nmixtures, float Tb, float TB, float Tg, float varInit, float varMin, float varMax, float tau, unsigned char shadowVal); - void mog2_gpu(DevMem2Db frame, int cn, DevMem2Db fgmask, DevMem2Db modesUsed, DevMem2Df weight, DevMem2Df variance, DevMem2Db mean, float alphaT, float prune, bool detectShadows, cudaStream_t stream); - void getBackgroundImage2_gpu(int cn, DevMem2Db modesUsed, DevMem2Df weight, DevMem2Db mean, DevMem2Db dst, cudaStream_t stream); + void mog2_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, float alphaT, float prune, bool detectShadows, cudaStream_t stream); + void getBackgroundImage2_gpu(int cn, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream); } }}} diff --git a/modules/gpu/src/bgfg_vibe.cpp b/modules/gpu/src/bgfg_vibe.cpp index af90c428ed..cf6d3c5340 100644 --- a/modules/gpu/src/bgfg_vibe.cpp +++ b/modules/gpu/src/bgfg_vibe.cpp @@ -57,9 +57,9 @@ namespace cv { namespace gpu { namespace device { void loadConstants(int nbSamples, int reqMatches, int radius, int subsamplingFactor); - void init_gpu(DevMem2Db frame, int cn, DevMem2Db samples, DevMem2D_ randStates, cudaStream_t stream); + void init_gpu(PtrStepSzb frame, int cn, PtrStepSzb samples, PtrStepSz randStates, cudaStream_t stream); - void update_gpu(DevMem2Db frame, int cn, DevMem2Db fgmask, DevMem2Db samples, DevMem2D_ randStates, cudaStream_t stream); + void update_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzb samples, PtrStepSz randStates, cudaStream_t stream); } }}} diff --git a/modules/gpu/src/bilateral_filter.cpp b/modules/gpu/src/bilateral_filter.cpp index d24adee90e..04c312688a 100644 --- a/modules/gpu/src/bilateral_filter.cpp +++ b/modules/gpu/src/bilateral_filter.cpp @@ -59,10 +59,10 @@ namespace cv { namespace gpu { namespace device { namespace bilateral_filter { - void load_constants(float* table_color, DevMem2Df table_space, int ndisp, int radius, short edge_disc, short max_disc); + void load_constants(float* table_color, PtrStepSzf table_space, int ndisp, int radius, short edge_disc, short max_disc); - void bilateral_filter_gpu(DevMem2Db disp, DevMem2Db img, int channels, int iters, cudaStream_t stream); - void bilateral_filter_gpu(DevMem2D_ disp, DevMem2Db img, int channels, int iters, cudaStream_t stream); + void bilateral_filter_gpu(PtrStepSzb disp, PtrStepSzb img, int channels, int iters, cudaStream_t stream); + void bilateral_filter_gpu(PtrStepSz disp, PtrStepSzb img, int channels, int iters, cudaStream_t stream); } }}} @@ -120,7 +120,7 @@ namespace disp.copyTo(dst); } - bilateral_filter_gpu((DevMem2D_)dst, img, img.channels(), iters, StreamAccessor::getStream(stream)); + bilateral_filter_gpu((PtrStepSz)dst, img, img.channels(), iters, StreamAccessor::getStream(stream)); } typedef void (*bilateral_filter_operator_t)(int ndisp, int radius, int iters, float edge_threshold, float max_disc_threshold, diff --git a/modules/gpu/src/brute_force_matcher.cpp b/modules/gpu/src/brute_force_matcher.cpp index a1fe066136..5e0ef21afe 100644 --- a/modules/gpu/src/brute_force_matcher.cpp +++ b/modules/gpu/src/brute_force_matcher.cpp @@ -86,72 +86,72 @@ namespace cv { namespace gpu { namespace device { namespace bf_match { - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& train, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& train, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& train, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& train, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& train, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& train, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); } namespace bf_knnmatch { - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& train, int k, const DevMem2Db& mask, - const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& train, int k, const PtrStepSzb& mask, + const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& train, int k, const DevMem2Db& mask, - const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& train, int k, const PtrStepSzb& mask, + const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& train, int k, const DevMem2Db& mask, - const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& train, int k, const PtrStepSzb& mask, + const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); - template void match2L1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, + template void match2L1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); - template void match2L2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, + template void match2L2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); - template void match2Hamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, + template void match2Hamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); } namespace bf_radius_match { - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& train, float maxDistance, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& train, float maxDistance, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& train, float maxDistance, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& train, float maxDistance, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& train, float maxDistance, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& train, float maxDistance, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); } }}} @@ -200,8 +200,8 @@ void cv::gpu::BFMatcher_GPU::matchSingle(const GpuMat& query, const GpuMat& trai using namespace cv::gpu::device::bf_match; - typedef void (*caller_t)(const DevMem2Db& query, const DevMem2Db& train, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + typedef void (*caller_t)(const PtrStepSzb& query, const PtrStepSzb& train, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); static const caller_t callersL1[] = @@ -301,9 +301,9 @@ void cv::gpu::BFMatcher_GPU::makeGpuCollection(GpuMat& trainCollection, GpuMat& if (masks.empty()) { - Mat trainCollectionCPU(1, static_cast(trainDescCollection.size()), CV_8UC(sizeof(DevMem2Db))); + Mat trainCollectionCPU(1, static_cast(trainDescCollection.size()), CV_8UC(sizeof(PtrStepSzb))); - DevMem2Db* trainCollectionCPU_ptr = trainCollectionCPU.ptr(); + PtrStepSzb* trainCollectionCPU_ptr = trainCollectionCPU.ptr(); for (size_t i = 0, size = trainDescCollection.size(); i < size; ++i, ++trainCollectionCPU_ptr) *trainCollectionCPU_ptr = trainDescCollection[i]; @@ -315,10 +315,10 @@ void cv::gpu::BFMatcher_GPU::makeGpuCollection(GpuMat& trainCollection, GpuMat& { CV_Assert(masks.size() == trainDescCollection.size()); - Mat trainCollectionCPU(1, static_cast(trainDescCollection.size()), CV_8UC(sizeof(DevMem2Db))); + Mat trainCollectionCPU(1, static_cast(trainDescCollection.size()), CV_8UC(sizeof(PtrStepSzb))); Mat maskCollectionCPU(1, static_cast(trainDescCollection.size()), CV_8UC(sizeof(PtrStepb))); - DevMem2Db* trainCollectionCPU_ptr = trainCollectionCPU.ptr(); + PtrStepSzb* trainCollectionCPU_ptr = trainCollectionCPU.ptr(); PtrStepb* maskCollectionCPU_ptr = maskCollectionCPU.ptr(); for (size_t i = 0, size = trainDescCollection.size(); i < size; ++i, ++trainCollectionCPU_ptr, ++maskCollectionCPU_ptr) @@ -346,8 +346,8 @@ void cv::gpu::BFMatcher_GPU::matchCollection(const GpuMat& query, const GpuMat& using namespace cv::gpu::device::bf_match; - typedef void (*caller_t)(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + typedef void (*caller_t)(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); static const caller_t callersL1[] = @@ -460,8 +460,8 @@ void cv::gpu::BFMatcher_GPU::knnMatchSingle(const GpuMat& query, const GpuMat& t using namespace cv::gpu::device::bf_knnmatch; - typedef void (*caller_t)(const DevMem2Db& query, const DevMem2Db& train, int k, const DevMem2Db& mask, - const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, + typedef void (*caller_t)(const PtrStepSzb& query, const PtrStepSzb& train, int k, const PtrStepSzb& mask, + const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); static const caller_t callersL1[] = @@ -592,8 +592,8 @@ void cv::gpu::BFMatcher_GPU::knnMatch2Collection(const GpuMat& query, const GpuM using namespace cv::gpu::device::bf_knnmatch; - typedef void (*caller_t)(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, + typedef void (*caller_t)(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); static const caller_t callersL1[] = @@ -776,8 +776,8 @@ void cv::gpu::BFMatcher_GPU::radiusMatchSingle(const GpuMat& query, const GpuMat using namespace cv::gpu::device::bf_radius_match; - typedef void (*caller_t)(const DevMem2Db& query, const DevMem2Db& train, float maxDistance, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + typedef void (*caller_t)(const PtrStepSzb& query, const PtrStepSzb& train, float maxDistance, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); static const caller_t callersL1[] = @@ -911,8 +911,8 @@ void cv::gpu::BFMatcher_GPU::radiusMatchCollection(const GpuMat& query, GpuMat& using namespace cv::gpu::device::bf_radius_match; - typedef void (*caller_t)(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + typedef void (*caller_t)(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); static const caller_t callersL1[] = @@ -964,8 +964,8 @@ void cv::gpu::BFMatcher_GPU::radiusMatchCollection(const GpuMat& query, GpuMat& caller_t func = callers[query.depth()]; CV_Assert(func != 0); - vector trains_(trainDescCollection.begin(), trainDescCollection.end()); - vector masks_(masks.begin(), masks.end()); + vector trains_(trainDescCollection.begin(), trainDescCollection.end()); + vector masks_(masks.begin(), masks.end()); func(query, &trains_[0], static_cast(trains_.size()), maxDistance, masks_.size() == 0 ? 0 : &masks_[0], trainIdx, imgIdx, distance, nMatches, cc, StreamAccessor::getStream(stream)); diff --git a/modules/gpu/src/calib3d.cpp b/modules/gpu/src/calib3d.cpp index 8897996269..efbd76eb17 100644 --- a/modules/gpu/src/calib3d.cpp +++ b/modules/gpu/src/calib3d.cpp @@ -60,12 +60,12 @@ namespace cv { namespace gpu { namespace device { namespace transform_points { - void call(const DevMem2D_ src, const float* rot, const float* transl, DevMem2D_ dst, cudaStream_t stream); + void call(const PtrStepSz src, const float* rot, const float* transl, PtrStepSz dst, cudaStream_t stream); } namespace project_points { - void call(const DevMem2D_ src, const float* rot, const float* transl, const float* proj, DevMem2D_ dst, cudaStream_t stream); + void call(const PtrStepSz src, const float* rot, const float* transl, const float* proj, PtrStepSz dst, cudaStream_t stream); } namespace solve_pnp_ransac diff --git a/modules/gpu/src/cascadeclassifier.cpp b/modules/gpu/src/cascadeclassifier.cpp index b5958697c9..d6fb10c98b 100644 --- a/modules/gpu/src/cascadeclassifier.cpp +++ b/modules/gpu/src/cascadeclassifier.cpp @@ -352,18 +352,18 @@ namespace cv { namespace gpu { namespace device float initalScale, float factor, int total, - const DevMem2Db& mstages, + const PtrStepSzb& mstages, const int nstages, - const DevMem2Di& mnodes, - const DevMem2Df& mleaves, - const DevMem2Di& msubsets, - const DevMem2Db& mfeatures, + const PtrStepSzi& mnodes, + const PtrStepSzf& mleaves, + const PtrStepSzi& msubsets, + const PtrStepSzb& mfeatures, const int subsetSize, - DevMem2D_ objects, + PtrStepSz objects, unsigned int* classified, - DevMem2Di integral); + PtrStepSzi integral); - void connectedConmonents(DevMem2D_ candidates, int ncandidates, DevMem2D_ objects,int groupThreshold, float grouping_eps, unsigned int* nclasses); + void connectedConmonents(PtrStepSz candidates, int ncandidates, PtrStepSz objects,int groupThreshold, float grouping_eps, unsigned int* nclasses); } }}} diff --git a/modules/gpu/src/color.cpp b/modules/gpu/src/color.cpp index cb2ae33d71..b8c5942d82 100644 --- a/modules/gpu/src/color.cpp +++ b/modules/gpu/src/color.cpp @@ -59,9 +59,9 @@ namespace cv { namespace gpu { namespace device { template - void Bayer2BGR_8u_gpu(DevMem2Db src, DevMem2Db dst, bool blue_last, bool start_with_green, cudaStream_t stream); + void Bayer2BGR_8u_gpu(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream); template - void Bayer2BGR_16u_gpu(DevMem2Db src, DevMem2Db dst, bool blue_last, bool start_with_green, cudaStream_t stream); + void Bayer2BGR_16u_gpu(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream); } }} @@ -69,7 +69,7 @@ using namespace ::cv::gpu::device; namespace { - typedef void (*gpu_func_t)(const DevMem2Db& src, const DevMem2Db& dst, cudaStream_t stream); + typedef void (*gpu_func_t)(const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream); void bgr_to_rgb(const GpuMat& src, GpuMat& dst, int, Stream& stream) { @@ -1336,7 +1336,7 @@ namespace void bayer_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, bool blue_last, bool start_with_green, Stream& stream) { - typedef void (*func_t)(DevMem2Db src, DevMem2Db dst, bool blue_last, bool start_with_green, cudaStream_t stream); + typedef void (*func_t)(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream); static const func_t funcs[3][4] = { {0,0,Bayer2BGR_8u_gpu<3>, Bayer2BGR_8u_gpu<4>}, diff --git a/modules/gpu/src/cuda/NV12ToARGB.cu b/modules/gpu/src/cuda/NV12ToARGB.cu index 6430e2dc62..32d5749099 100644 --- a/modules/gpu/src/cuda/NV12ToARGB.cu +++ b/modules/gpu/src/cuda/NV12ToARGB.cu @@ -191,7 +191,7 @@ namespace cv { namespace gpu { namespace device { dstImage[y * dstImagePitch + x + 1 ] = RGBAPACK_10bit(red[1], green[1], blue[1], constAlpha); } - void NV12ToARGB_gpu(const PtrStepb decodedFrame, DevMem2D_ interopFrame, cudaStream_t stream) + void NV12ToARGB_gpu(const PtrStepb decodedFrame, PtrStepSz interopFrame, cudaStream_t stream) { dim3 block(32, 8); dim3 grid(divUp(interopFrame.cols, 2 * block.x), divUp(interopFrame.rows, block.y)); diff --git a/modules/gpu/src/cuda/bf_knnmatch.cu b/modules/gpu/src/cuda/bf_knnmatch.cu index 8ee3c26c71..b545cb5ab2 100644 --- a/modules/gpu/src/cuda/bf_knnmatch.cu +++ b/modules/gpu/src/cuda/bf_knnmatch.cu @@ -209,7 +209,7 @@ namespace cv { namespace gpu { namespace device // Match Unrolled Cached template - __device__ void loadQueryToSmem(int queryIdx, const DevMem2D_& query, U* s_query) + __device__ void loadQueryToSmem(int queryIdx, const PtrStepSz& query, U* s_query) { #pragma unroll for (int i = 0; i < MAX_DESC_LEN / BLOCK_SIZE; ++i) @@ -220,7 +220,7 @@ namespace cv { namespace gpu { namespace device } template - __device__ void loopUnrolledCached(int queryIdx, const DevMem2D_& query, int imgIdx, const DevMem2D_& train, const Mask& mask, + __device__ void loopUnrolledCached(int queryIdx, const PtrStepSz& query, int imgIdx, const PtrStepSz& train, const Mask& mask, typename Dist::value_type* s_query, typename Dist::value_type* s_train, float& bestDistance1, float& bestDistance2, int& bestTrainIdx1, int& bestTrainIdx2, @@ -281,7 +281,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void matchUnrolledCached(const DevMem2D_ query, const DevMem2D_ train, const Mask mask, int2* bestTrainIdx, float2* bestDistance) + __global__ void matchUnrolledCached(const PtrStepSz query, const PtrStepSz train, const Mask mask, int2* bestTrainIdx, float2* bestDistance) { extern __shared__ int smem[]; @@ -314,8 +314,8 @@ namespace cv { namespace gpu { namespace device } template - void matchUnrolledCached(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, - const DevMem2D_& trainIdx, const DevMem2D_& distance, + void matchUnrolledCached(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, + const PtrStepSz& trainIdx, const PtrStepSz& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -331,7 +331,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void matchUnrolledCached(const DevMem2D_ query, const DevMem2D_* trains, int n, const Mask mask, int2* bestTrainIdx, int2* bestImgIdx, float2* bestDistance) + __global__ void matchUnrolledCached(const PtrStepSz query, const PtrStepSz* trains, int n, const Mask mask, int2* bestTrainIdx, int2* bestImgIdx, float2* bestDistance) { extern __shared__ int smem[]; @@ -353,7 +353,7 @@ namespace cv { namespace gpu { namespace device for (int imgIdx = 0; imgIdx < n; ++imgIdx) { - const DevMem2D_ train = trains[imgIdx]; + const PtrStepSz train = trains[imgIdx]; m.next(); loopUnrolledCached(queryIdx, query, imgIdx, train, m, s_query, s_train, myBestDistance1, myBestDistance2, myBestTrainIdx1, myBestTrainIdx2, myBestImgIdx1, myBestImgIdx2); } @@ -375,8 +375,8 @@ namespace cv { namespace gpu { namespace device } template - void matchUnrolledCached(const DevMem2D_& query, const DevMem2D_* trains, int n, const Mask& mask, - const DevMem2D_& trainIdx, const DevMem2D_& imgIdx, const DevMem2D_& distance, + void matchUnrolledCached(const PtrStepSz& query, const PtrStepSz* trains, int n, const Mask& mask, + const PtrStepSz& trainIdx, const PtrStepSz& imgIdx, const PtrStepSz& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -395,7 +395,7 @@ namespace cv { namespace gpu { namespace device // Match Unrolled template - __device__ void loopUnrolled(int queryIdx, const DevMem2D_& query, int imgIdx, const DevMem2D_& train, const Mask& mask, + __device__ void loopUnrolled(int queryIdx, const PtrStepSz& query, int imgIdx, const PtrStepSz& train, const Mask& mask, typename Dist::value_type* s_query, typename Dist::value_type* s_train, float& bestDistance1, float& bestDistance2, int& bestTrainIdx1, int& bestTrainIdx2, @@ -460,7 +460,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void matchUnrolled(const DevMem2D_ query, const DevMem2D_ train, const Mask mask, int2* bestTrainIdx, float2* bestDistance) + __global__ void matchUnrolled(const PtrStepSz query, const PtrStepSz train, const Mask mask, int2* bestTrainIdx, float2* bestDistance) { extern __shared__ int smem[]; @@ -491,8 +491,8 @@ namespace cv { namespace gpu { namespace device } template - void matchUnrolled(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, - const DevMem2D_& trainIdx, const DevMem2D_& distance, + void matchUnrolled(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, + const PtrStepSz& trainIdx, const PtrStepSz& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -508,7 +508,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void matchUnrolled(const DevMem2D_ query, const DevMem2D_* trains, int n, const Mask mask, int2* bestTrainIdx, int2* bestImgIdx, float2* bestDistance) + __global__ void matchUnrolled(const PtrStepSz query, const PtrStepSz* trains, int n, const Mask mask, int2* bestTrainIdx, int2* bestImgIdx, float2* bestDistance) { extern __shared__ int smem[]; @@ -528,7 +528,7 @@ namespace cv { namespace gpu { namespace device for (int imgIdx = 0; imgIdx < n; ++imgIdx) { - const DevMem2D_ train = trains[imgIdx]; + const PtrStepSz train = trains[imgIdx]; m.next(); loopUnrolled(queryIdx, query, imgIdx, train, m, s_query, s_train, myBestDistance1, myBestDistance2, myBestTrainIdx1, myBestTrainIdx2, myBestImgIdx1, myBestImgIdx2); } @@ -550,8 +550,8 @@ namespace cv { namespace gpu { namespace device } template - void matchUnrolled(const DevMem2D_& query, const DevMem2D_* trains, int n, const Mask& mask, - const DevMem2D_& trainIdx, const DevMem2D_& imgIdx, const DevMem2D_& distance, + void matchUnrolled(const PtrStepSz& query, const PtrStepSz* trains, int n, const Mask& mask, + const PtrStepSz& trainIdx, const PtrStepSz& imgIdx, const PtrStepSz& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -570,7 +570,7 @@ namespace cv { namespace gpu { namespace device // Match template - __device__ void loop(int queryIdx, const DevMem2D_& query, int imgIdx, const DevMem2D_& train, const Mask& mask, + __device__ void loop(int queryIdx, const PtrStepSz& query, int imgIdx, const PtrStepSz& train, const Mask& mask, typename Dist::value_type* s_query, typename Dist::value_type* s_train, float& bestDistance1, float& bestDistance2, int& bestTrainIdx1, int& bestTrainIdx2, @@ -634,7 +634,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void match(const DevMem2D_ query, const DevMem2D_ train, const Mask mask, int2* bestTrainIdx, float2* bestDistance) + __global__ void match(const PtrStepSz query, const PtrStepSz train, const Mask mask, int2* bestTrainIdx, float2* bestDistance) { extern __shared__ int smem[]; @@ -665,8 +665,8 @@ namespace cv { namespace gpu { namespace device } template - void match(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, - const DevMem2D_& trainIdx, const DevMem2D_& distance, + void match(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, + const PtrStepSz& trainIdx, const PtrStepSz& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -682,7 +682,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void match(const DevMem2D_ query, const DevMem2D_* trains, int n, const Mask mask, int2* bestTrainIdx, int2* bestImgIdx, float2* bestDistance) + __global__ void match(const PtrStepSz query, const PtrStepSz* trains, int n, const Mask mask, int2* bestTrainIdx, int2* bestImgIdx, float2* bestDistance) { extern __shared__ int smem[]; @@ -702,7 +702,7 @@ namespace cv { namespace gpu { namespace device for (int imgIdx = 0; imgIdx < n; ++imgIdx) { - const DevMem2D_ train = trains[imgIdx]; + const PtrStepSz train = trains[imgIdx]; m.next(); loop(queryIdx, query, imgIdx, train, m, s_query, s_train, myBestDistance1, myBestDistance2, myBestTrainIdx1, myBestTrainIdx2, myBestImgIdx1, myBestImgIdx2); } @@ -724,8 +724,8 @@ namespace cv { namespace gpu { namespace device } template - void match(const DevMem2D_& query, const DevMem2D_* trains, int n, const Mask& mask, - const DevMem2D_& trainIdx, const DevMem2D_& imgIdx, const DevMem2D_& distance, + void match(const PtrStepSz& query, const PtrStepSz* trains, int n, const Mask& mask, + const PtrStepSz& trainIdx, const PtrStepSz& imgIdx, const PtrStepSz& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -744,66 +744,66 @@ namespace cv { namespace gpu { namespace device // knnMatch 2 dispatcher template - void match2Dispatcher(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, - const DevMem2Db& trainIdx, const DevMem2Db& distance, + void match2Dispatcher(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, + const PtrStepSzb& trainIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream) { (void)cc; if (query.cols <= 64) { - matchUnrolledCached<16, 64, Dist>(query, train, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ > (distance), stream); + matchUnrolledCached<16, 64, Dist>(query, train, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz > (distance), stream); } else if (query.cols <= 128) { - matchUnrolledCached<16, 128, Dist>(query, train, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ > (distance), stream); + matchUnrolledCached<16, 128, Dist>(query, train, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz > (distance), stream); } /*else if (query.cols <= 256) { - matchUnrolled<16, 256, Dist>(query, train, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ > (distance), stream); + matchUnrolled<16, 256, Dist>(query, train, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz > (distance), stream); } else if (query.cols <= 512) { - matchUnrolled<16, 512, Dist>(query, train, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ > (distance), stream); + matchUnrolled<16, 512, Dist>(query, train, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz > (distance), stream); } else if (query.cols <= 1024) { - matchUnrolled<16, 1024, Dist>(query, train, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ > (distance), stream); + matchUnrolled<16, 1024, Dist>(query, train, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz > (distance), stream); }*/ else { - match<16, Dist>(query, train, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ > (distance), stream); + match<16, Dist>(query, train, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz > (distance), stream); } } template - void match2Dispatcher(const DevMem2D_& query, const DevMem2D_* trains, int n, const Mask& mask, - const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, + void match2Dispatcher(const PtrStepSz& query, const PtrStepSz* trains, int n, const Mask& mask, + const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream) { (void)cc; if (query.cols <= 64) { - matchUnrolledCached<16, 64, Dist>(query, trains, n, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ >(imgIdx), static_cast< DevMem2D_ > (distance), stream); + matchUnrolledCached<16, 64, Dist>(query, trains, n, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz >(imgIdx), static_cast< PtrStepSz > (distance), stream); } else if (query.cols <= 128) { - matchUnrolledCached<16, 128, Dist>(query, trains, n, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ >(imgIdx), static_cast< DevMem2D_ > (distance), stream); + matchUnrolledCached<16, 128, Dist>(query, trains, n, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz >(imgIdx), static_cast< PtrStepSz > (distance), stream); } /*else if (query.cols <= 256) { - matchUnrolled<16, 256, Dist>(query, trains, n, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ >(imgIdx), static_cast< DevMem2D_ > (distance), stream); + matchUnrolled<16, 256, Dist>(query, trains, n, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz >(imgIdx), static_cast< PtrStepSz > (distance), stream); } else if (query.cols <= 512) { - matchUnrolled<16, 512, Dist>(query, trains, n, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ >(imgIdx), static_cast< DevMem2D_ > (distance), stream); + matchUnrolled<16, 512, Dist>(query, trains, n, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz >(imgIdx), static_cast< PtrStepSz > (distance), stream); } else if (query.cols <= 1024) { - matchUnrolled<16, 1024, Dist>(query, trains, n, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ >(imgIdx), static_cast< DevMem2D_ > (distance), stream); + matchUnrolled<16, 1024, Dist>(query, trains, n, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz >(imgIdx), static_cast< PtrStepSz > (distance), stream); }*/ else { - match<16, Dist>(query, trains, n, mask, static_cast< DevMem2D_ >(trainIdx), static_cast< DevMem2D_ >(imgIdx), static_cast< DevMem2D_ > (distance), stream); + match<16, Dist>(query, trains, n, mask, static_cast< PtrStepSz >(trainIdx), static_cast< PtrStepSz >(imgIdx), static_cast< PtrStepSz > (distance), stream); } } @@ -811,7 +811,7 @@ namespace cv { namespace gpu { namespace device // Calc distance kernel template - __global__ void calcDistanceUnrolled(const DevMem2D_ query, const DevMem2D_ train, const Mask mask, PtrStepf allDist) + __global__ void calcDistanceUnrolled(const PtrStepSz query, const PtrStepSz train, const Mask mask, PtrStepf allDist) { extern __shared__ int smem[]; @@ -860,7 +860,7 @@ namespace cv { namespace gpu { namespace device } template - void calcDistanceUnrolled(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, const DevMem2Df& allDist, cudaStream_t stream) + void calcDistanceUnrolled(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, const PtrStepSzf& allDist, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); const dim3 grid(divUp(train.rows, BLOCK_SIZE), divUp(query.rows, BLOCK_SIZE)); @@ -875,7 +875,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void calcDistance(const DevMem2D_ query, const DevMem2D_ train, const Mask mask, PtrStepf allDist) + __global__ void calcDistance(const PtrStepSz query, const PtrStepSz train, const Mask mask, PtrStepf allDist) { extern __shared__ int smem[]; @@ -923,7 +923,7 @@ namespace cv { namespace gpu { namespace device } template - void calcDistance(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, const DevMem2Df& allDist, cudaStream_t stream) + void calcDistance(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, const PtrStepSzf& allDist, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); const dim3 grid(divUp(train.rows, BLOCK_SIZE), divUp(query.rows, BLOCK_SIZE)); @@ -941,8 +941,8 @@ namespace cv { namespace gpu { namespace device // Calc Distance dispatcher template - void calcDistanceDispatcher(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, - const DevMem2Df& allDist, + void calcDistanceDispatcher(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, + const PtrStepSzf& allDist, int cc, cudaStream_t stream) { (void)cc; @@ -976,7 +976,7 @@ namespace cv { namespace gpu { namespace device // find knn match kernel template - __global__ void findBestMatch(DevMem2Df allDist, int i, PtrStepi trainIdx, PtrStepf distance) + __global__ void findBestMatch(PtrStepSzf allDist, int i, PtrStepi trainIdx, PtrStepf distance) { const int SMEM_SIZE = BLOCK_SIZE > 64 ? BLOCK_SIZE : 64; __shared__ float s_dist[SMEM_SIZE]; @@ -1017,7 +1017,7 @@ namespace cv { namespace gpu { namespace device } template - void findKnnMatch(int k, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2Df& allDist, cudaStream_t stream) + void findKnnMatch(int k, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSzf& allDist, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, 1, 1); const dim3 grid(trainIdx.rows, 1, 1); @@ -1032,17 +1032,17 @@ namespace cv { namespace gpu { namespace device cudaSafeCall( cudaDeviceSynchronize() ); } - void findKnnMatchDispatcher(int k, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream) + void findKnnMatchDispatcher(int k, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream) { - findKnnMatch<256>(k, static_cast(trainIdx), static_cast(distance), allDist, stream); + findKnnMatch<256>(k, static_cast(trainIdx), static_cast(distance), allDist, stream); } /////////////////////////////////////////////////////////////////////////////// // knn match Dispatcher template - void matchDispatcher(const DevMem2D_& query, const DevMem2D_& train, int k, const Mask& mask, - const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, + void matchDispatcher(const PtrStepSz& query, const PtrStepSz& train, int k, const Mask& mask, + const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream) { if (k == 2) @@ -1059,104 +1059,104 @@ namespace cv { namespace gpu { namespace device /////////////////////////////////////////////////////////////////////////////// // knn match caller - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& train, int k, const DevMem2Db& mask, - const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& train, int k, const PtrStepSzb& mask, + const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream) { if (mask.data) - matchDispatcher< L1Dist >(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), k, SingleMask(mask), trainIdx, distance, allDist, cc, stream); + matchDispatcher< L1Dist >(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), k, SingleMask(mask), trainIdx, distance, allDist, cc, stream); else - matchDispatcher< L1Dist >(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), k, WithOutMask(), trainIdx, distance, allDist, cc, stream); + matchDispatcher< L1Dist >(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), k, WithOutMask(), trainIdx, distance, allDist, cc, stream); } - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - //template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + //template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& train, int k, const DevMem2Db& mask, - const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& train, int k, const PtrStepSzb& mask, + const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream) { if (mask.data) - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), k, SingleMask(mask), trainIdx, distance, allDist, cc, stream); + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), k, SingleMask(mask), trainIdx, distance, allDist, cc, stream); else - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), k, WithOutMask(), trainIdx, distance, allDist, cc, stream); + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), k, WithOutMask(), trainIdx, distance, allDist, cc, stream); } - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& train, int k, const DevMem2Db& mask, - const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& train, int k, const PtrStepSzb& mask, + const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream) { if (mask.data) - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), k, SingleMask(mask), trainIdx, distance, allDist, cc, stream); + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), k, SingleMask(mask), trainIdx, distance, allDist, cc, stream); else - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), k, WithOutMask(), trainIdx, distance, allDist, cc, stream); + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), k, WithOutMask(), trainIdx, distance, allDist, cc, stream); } - template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - //template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - //template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, int k, const DevMem2Db& mask, const DevMem2Db& trainIdx, const DevMem2Db& distance, const DevMem2Df& allDist, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + //template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + //template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, int k, const PtrStepSzb& mask, const PtrStepSzb& trainIdx, const PtrStepSzb& distance, const PtrStepSzf& allDist, int cc, cudaStream_t stream); - template void match2L1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, + template void match2L1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream) { if (masks.data) - match2Dispatcher< L1Dist >(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, MaskCollection(masks.data), trainIdx, imgIdx, distance, cc, stream); + match2Dispatcher< L1Dist >(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, MaskCollection(masks.data), trainIdx, imgIdx, distance, cc, stream); else - match2Dispatcher< L1Dist >(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, WithOutMask(), trainIdx, imgIdx, distance, cc, stream); + match2Dispatcher< L1Dist >(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, WithOutMask(), trainIdx, imgIdx, distance, cc, stream); } - template void match2L1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - //template void match2L1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - template void match2L1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - template void match2L1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - template void match2L1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - template void match2L1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); + template void match2L1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + //template void match2L1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + template void match2L1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + template void match2L1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + template void match2L1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + template void match2L1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); - template void match2L2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, + template void match2L2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream) { if (masks.data) - match2Dispatcher(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, MaskCollection(masks.data), trainIdx, imgIdx, distance, cc, stream); + match2Dispatcher(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, MaskCollection(masks.data), trainIdx, imgIdx, distance, cc, stream); else - match2Dispatcher(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, WithOutMask(), trainIdx, imgIdx, distance, cc, stream); + match2Dispatcher(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, WithOutMask(), trainIdx, imgIdx, distance, cc, stream); } - //template void match2L2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - //template void match2L2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - //template void match2L2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - //template void match2L2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - //template void match2L2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Di& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - template void match2L2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); + //template void match2L2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + //template void match2L2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + //template void match2L2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + //template void match2L2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + //template void match2L2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + template void match2L2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); - template void match2Hamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, + template void match2Hamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream) { if (masks.data) - match2Dispatcher(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, MaskCollection(masks.data), trainIdx, imgIdx, distance, cc, stream); + match2Dispatcher(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, MaskCollection(masks.data), trainIdx, imgIdx, distance, cc, stream); else - match2Dispatcher(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, WithOutMask(), trainIdx, imgIdx, distance, cc, stream); + match2Dispatcher(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, WithOutMask(), trainIdx, imgIdx, distance, cc, stream); } - template void match2Hamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - //template void match2Hamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - template void match2Hamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - //template void match2Hamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); - template void match2Hamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Db& trainIdx, const DevMem2Db& imgIdx, const DevMem2Db& distance, int cc, cudaStream_t stream); + template void match2Hamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + //template void match2Hamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + template void match2Hamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + //template void match2Hamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); + template void match2Hamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzb& trainIdx, const PtrStepSzb& imgIdx, const PtrStepSzb& distance, int cc, cudaStream_t stream); } // namespace bf_knnmatch }}} // namespace cv { namespace gpu { namespace device { diff --git a/modules/gpu/src/cuda/bf_match.cu b/modules/gpu/src/cuda/bf_match.cu index 3068c81dc4..d8489d933b 100644 --- a/modules/gpu/src/cuda/bf_match.cu +++ b/modules/gpu/src/cuda/bf_match.cu @@ -86,7 +86,7 @@ namespace cv { namespace gpu { namespace device // Match Unrolled Cached template - __device__ void loadQueryToSmem(int queryIdx, const DevMem2D_& query, U* s_query) + __device__ void loadQueryToSmem(int queryIdx, const PtrStepSz& query, U* s_query) { #pragma unroll for (int i = 0; i < MAX_DESC_LEN / BLOCK_SIZE; ++i) @@ -97,7 +97,7 @@ namespace cv { namespace gpu { namespace device } template - __device__ void loopUnrolledCached(int queryIdx, const DevMem2D_& query,volatile int imgIdx, const DevMem2D_& train, const Mask& mask, + __device__ void loopUnrolledCached(int queryIdx, const PtrStepSz& query,volatile int imgIdx, const PtrStepSz& train, const Mask& mask, typename Dist::value_type* s_query, typename Dist::value_type* s_train, float& bestDistance, int& bestTrainIdx, int& bestImgIdx) { @@ -143,7 +143,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void matchUnrolledCached(const DevMem2D_ query, const DevMem2D_ train, const Mask mask, int* bestTrainIdx, float* bestDistance) + __global__ void matchUnrolledCached(const PtrStepSz query, const PtrStepSz train, const Mask mask, int* bestTrainIdx, float* bestDistance) { extern __shared__ int smem[]; @@ -174,8 +174,8 @@ namespace cv { namespace gpu { namespace device } template - void matchUnrolledCached(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + void matchUnrolledCached(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -191,7 +191,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void matchUnrolledCached(const DevMem2D_ query, const DevMem2D_* trains, int n, const Mask mask, + __global__ void matchUnrolledCached(const PtrStepSz query, const PtrStepSz* trains, int n, const Mask mask, int* bestTrainIdx, int* bestImgIdx, float* bestDistance) { extern __shared__ int smem[]; @@ -211,7 +211,7 @@ namespace cv { namespace gpu { namespace device for (int imgIdx = 0; imgIdx < n; ++imgIdx) { - const DevMem2D_ train = trains[imgIdx]; + const PtrStepSz train = trains[imgIdx]; m.next(); loopUnrolledCached(queryIdx, query, imgIdx, train, m, s_query, s_train, myBestDistance, myBestTrainIdx, myBestImgIdx); } @@ -233,8 +233,8 @@ namespace cv { namespace gpu { namespace device } template - void matchUnrolledCached(const DevMem2D_& query, const DevMem2D_* trains, int n, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + void matchUnrolledCached(const PtrStepSz& query, const PtrStepSz* trains, int n, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -253,7 +253,7 @@ namespace cv { namespace gpu { namespace device // Match Unrolled template - __device__ void loopUnrolled(int queryIdx, const DevMem2D_& query,volatile int imgIdx, const DevMem2D_& train, const Mask& mask, + __device__ void loopUnrolled(int queryIdx, const PtrStepSz& query,volatile int imgIdx, const PtrStepSz& train, const Mask& mask, typename Dist::value_type* s_query, typename Dist::value_type* s_train, float& bestDistance, int& bestTrainIdx, int& bestImgIdx) { @@ -303,7 +303,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void matchUnrolled(const DevMem2D_ query, const DevMem2D_ train, const Mask mask, int* bestTrainIdx, float* bestDistance) + __global__ void matchUnrolled(const PtrStepSz query, const PtrStepSz train, const Mask mask, int* bestTrainIdx, float* bestDistance) { extern __shared__ int smem[]; @@ -332,8 +332,8 @@ namespace cv { namespace gpu { namespace device } template - void matchUnrolled(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + void matchUnrolled(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -349,7 +349,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void matchUnrolled(const DevMem2D_ query, const DevMem2D_* trains, int n, const Mask mask, + __global__ void matchUnrolled(const PtrStepSz query, const PtrStepSz* trains, int n, const Mask mask, int* bestTrainIdx, int* bestImgIdx, float* bestDistance) { extern __shared__ int smem[]; @@ -367,7 +367,7 @@ namespace cv { namespace gpu { namespace device for (int imgIdx = 0; imgIdx < n; ++imgIdx) { - const DevMem2D_ train = trains[imgIdx]; + const PtrStepSz train = trains[imgIdx]; m.next(); loopUnrolled(queryIdx, query, imgIdx, train, m, s_query, s_train, myBestDistance, myBestTrainIdx, myBestImgIdx); } @@ -389,8 +389,8 @@ namespace cv { namespace gpu { namespace device } template - void matchUnrolled(const DevMem2D_& query, const DevMem2D_* trains, int n, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + void matchUnrolled(const PtrStepSz& query, const PtrStepSz* trains, int n, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -409,7 +409,7 @@ namespace cv { namespace gpu { namespace device // Match template - __device__ void loop(int queryIdx, const DevMem2D_& query, volatile int imgIdx, const DevMem2D_& train, const Mask& mask, + __device__ void loop(int queryIdx, const PtrStepSz& query, volatile int imgIdx, const PtrStepSz& train, const Mask& mask, typename Dist::value_type* s_query, typename Dist::value_type* s_train, float& bestDistance, int& bestTrainIdx, int& bestImgIdx) { @@ -458,7 +458,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void match(const DevMem2D_ query, const DevMem2D_ train, const Mask mask, int* bestTrainIdx, float* bestDistance) + __global__ void match(const PtrStepSz query, const PtrStepSz train, const Mask mask, int* bestTrainIdx, float* bestDistance) { extern __shared__ int smem[]; @@ -487,8 +487,8 @@ namespace cv { namespace gpu { namespace device } template - void match(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + void match(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -504,7 +504,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void match(const DevMem2D_ query, const DevMem2D_* trains, int n, const Mask mask, + __global__ void match(const PtrStepSz query, const PtrStepSz* trains, int n, const Mask mask, int* bestTrainIdx, int* bestImgIdx, float* bestDistance) { extern __shared__ int smem[]; @@ -521,7 +521,7 @@ namespace cv { namespace gpu { namespace device Mask m = mask; for (int imgIdx = 0; imgIdx < n; ++imgIdx) { - const DevMem2D_ train = trains[imgIdx]; + const PtrStepSz train = trains[imgIdx]; m.next(); loop(queryIdx, query, imgIdx, train, m, s_query, s_train, myBestDistance, myBestTrainIdx, myBestImgIdx); } @@ -543,8 +543,8 @@ namespace cv { namespace gpu { namespace device } template - void match(const DevMem2D_& query, const DevMem2D_* trains, int n, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + void match(const PtrStepSz& query, const PtrStepSz* trains, int n, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -563,8 +563,8 @@ namespace cv { namespace gpu { namespace device // Match dispatcher template - void matchDispatcher(const DevMem2D_& query, const DevMem2D_& train, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + void matchDispatcher(const PtrStepSz& query, const PtrStepSz& train, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream) { (void)cc; @@ -595,8 +595,8 @@ namespace cv { namespace gpu { namespace device } template - void matchDispatcher(const DevMem2D_& query, const DevMem2D_* trains, int n, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + void matchDispatcher(const PtrStepSz& query, const PtrStepSz* trains, int n, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream) { (void)cc; @@ -629,152 +629,152 @@ namespace cv { namespace gpu { namespace device /////////////////////////////////////////////////////////////////////////////// // Match caller - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& train, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& train, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream) { if (mask.data) { - matchDispatcher< L1Dist >(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), SingleMask(mask), + matchDispatcher< L1Dist >(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), SingleMask(mask), trainIdx, distance, cc, stream); } else { - matchDispatcher< L1Dist >(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), WithOutMask(), + matchDispatcher< L1Dist >(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), WithOutMask(), trainIdx, distance, cc, stream); } } - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& train, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& train, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream) { if (mask.data) { - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), SingleMask(mask), + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), SingleMask(mask), trainIdx, distance, cc, stream); } else { - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), WithOutMask(), + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), WithOutMask(), trainIdx, distance, cc, stream); } } - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& train, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& train, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream) { if (mask.data) { - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), SingleMask(mask), + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), SingleMask(mask), trainIdx, distance, cc, stream); } else { - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), WithOutMask(), + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), WithOutMask(), trainIdx, distance, cc, stream); } } - template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream) { if (masks.data) { - matchDispatcher< L1Dist >(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, MaskCollection(masks.data), + matchDispatcher< L1Dist >(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, MaskCollection(masks.data), trainIdx, imgIdx, distance, cc, stream); } else { - matchDispatcher< L1Dist >(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, WithOutMask(), + matchDispatcher< L1Dist >(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, WithOutMask(), trainIdx, imgIdx, distance, cc, stream); } } - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream) { if (masks.data) { - matchDispatcher(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, MaskCollection(masks.data), + matchDispatcher(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, MaskCollection(masks.data), trainIdx, imgIdx, distance, cc, stream); } else { - matchDispatcher(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, WithOutMask(), + matchDispatcher(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, WithOutMask(), trainIdx, imgIdx, distance, cc, stream); } } - //template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& maskCollection, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& maskCollection, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream) { if (masks.data) { - matchDispatcher(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, MaskCollection(masks.data), + matchDispatcher(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, MaskCollection(masks.data), trainIdx, imgIdx, distance, cc, stream); } else { - matchDispatcher(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains.ptr(), trains.cols, WithOutMask(), + matchDispatcher(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains.ptr(), trains.cols, WithOutMask(), trainIdx, imgIdx, distance, cc, stream); } } - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - //template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& trains, const DevMem2D_& masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + //template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& trains, const PtrStepSz& masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, int cc, cudaStream_t stream); } // namespace bf_match }}} // namespace cv { namespace gpu { namespace device { diff --git a/modules/gpu/src/cuda/bf_radius_match.cu b/modules/gpu/src/cuda/bf_radius_match.cu index c6cba928c1..63dcd01537 100644 --- a/modules/gpu/src/cuda/bf_radius_match.cu +++ b/modules/gpu/src/cuda/bf_radius_match.cu @@ -53,7 +53,7 @@ namespace cv { namespace gpu { namespace device // Match Unrolled template - __global__ void matchUnrolled(const DevMem2D_ query, int imgIdx, const DevMem2D_ train, float maxDistance, const Mask mask, + __global__ void matchUnrolled(const PtrStepSz query, int imgIdx, const PtrStepSz train, float maxDistance, const Mask mask, PtrStepi bestTrainIdx, PtrStepi bestImgIdx, PtrStepf bestDistance, unsigned int* nMatches, int maxCount) { #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) @@ -113,8 +113,8 @@ namespace cv { namespace gpu { namespace device } template - void matchUnrolled(const DevMem2D_& query, const DevMem2D_& train, float maxDistance, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, cudaStream_t stream) + void matchUnrolled(const PtrStepSz& query, const PtrStepSz& train, float maxDistance, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); const dim3 grid(divUp(train.rows, BLOCK_SIZE), divUp(query.rows, BLOCK_SIZE)); @@ -130,8 +130,8 @@ namespace cv { namespace gpu { namespace device } template - void matchUnrolled(const DevMem2D_& query, const DevMem2D_* trains, int n, float maxDistance, const DevMem2Db* masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + void matchUnrolled(const PtrStepSz& query, const PtrStepSz* trains, int n, float maxDistance, const PtrStepSzb* masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -140,7 +140,7 @@ namespace cv { namespace gpu { namespace device for (int i = 0; i < n; ++i) { - const DevMem2D_ train = trains[i]; + const PtrStepSz train = trains[i]; const dim3 grid(divUp(train.rows, BLOCK_SIZE), divUp(query.rows, BLOCK_SIZE)); @@ -165,7 +165,7 @@ namespace cv { namespace gpu { namespace device // Match template - __global__ void match(const DevMem2D_ query, int imgIdx, const DevMem2D_ train, float maxDistance, const Mask mask, + __global__ void match(const PtrStepSz query, int imgIdx, const PtrStepSz train, float maxDistance, const Mask mask, PtrStepi bestTrainIdx, PtrStepi bestImgIdx, PtrStepf bestDistance, unsigned int* nMatches, int maxCount) { #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 110) @@ -224,8 +224,8 @@ namespace cv { namespace gpu { namespace device } template - void match(const DevMem2D_& query, const DevMem2D_& train, float maxDistance, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + void match(const PtrStepSz& query, const PtrStepSz& train, float maxDistance, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -242,8 +242,8 @@ namespace cv { namespace gpu { namespace device } template - void match(const DevMem2D_& query, const DevMem2D_* trains, int n, float maxDistance, const DevMem2Db* masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + void match(const PtrStepSz& query, const PtrStepSz* trains, int n, float maxDistance, const PtrStepSzb* masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, cudaStream_t stream) { const dim3 block(BLOCK_SIZE, BLOCK_SIZE); @@ -252,7 +252,7 @@ namespace cv { namespace gpu { namespace device for (int i = 0; i < n; ++i) { - const DevMem2D_ train = trains[i]; + const PtrStepSz train = trains[i]; const dim3 grid(divUp(train.rows, BLOCK_SIZE), divUp(query.rows, BLOCK_SIZE)); @@ -277,8 +277,8 @@ namespace cv { namespace gpu { namespace device // Match dispatcher template - void matchDispatcher(const DevMem2D_& query, const DevMem2D_& train, float maxDistance, const Mask& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + void matchDispatcher(const PtrStepSz& query, const PtrStepSz& train, float maxDistance, const Mask& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream) { (void)cc; @@ -309,8 +309,8 @@ namespace cv { namespace gpu { namespace device } template - void matchDispatcher(const DevMem2D_& query, const DevMem2D_* trains, int n, float maxDistance, const DevMem2Db* masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + void matchDispatcher(const PtrStepSz& query, const PtrStepSz* trains, int n, float maxDistance, const PtrStepSzb* masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream) { (void)cc; @@ -343,125 +343,125 @@ namespace cv { namespace gpu { namespace device /////////////////////////////////////////////////////////////////////////////// // Radius Match caller - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db& train, float maxDistance, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb& train, float maxDistance, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream) { if (mask.data) { - matchDispatcher< L1Dist >(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), maxDistance, SingleMask(mask), + matchDispatcher< L1Dist >(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), maxDistance, SingleMask(mask), trainIdx, distance, nMatches, cc, stream); } else { - matchDispatcher< L1Dist >(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), maxDistance, WithOutMask(), + matchDispatcher< L1Dist >(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), maxDistance, WithOutMask(), trainIdx, distance, nMatches, cc, stream); } } - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db& train, float maxDistance, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb& train, float maxDistance, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream) { if (mask.data) { - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), maxDistance, SingleMask(mask), + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), maxDistance, SingleMask(mask), trainIdx, distance, nMatches, cc, stream); } else { - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), maxDistance, WithOutMask(), + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), maxDistance, WithOutMask(), trainIdx, distance, nMatches, cc, stream); } } - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchL2_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db& train, float maxDistance, const DevMem2Db& mask, - const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb& train, float maxDistance, const PtrStepSzb& mask, + const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream) { if (mask.data) { - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), maxDistance, SingleMask(mask), + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), maxDistance, SingleMask(mask), trainIdx, distance, nMatches, cc, stream); } else { - matchDispatcher(static_cast< DevMem2D_ >(query), static_cast< DevMem2D_ >(train), maxDistance, WithOutMask(), + matchDispatcher(static_cast< PtrStepSz >(query), static_cast< PtrStepSz >(train), maxDistance, WithOutMask(), trainIdx, distance, nMatches, cc, stream); } } - template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& queryDescs, const DevMem2Db& trainDescs, float maxDistance, const DevMem2Db& mask, const DevMem2Di& trainIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& queryDescs, const PtrStepSzb& trainDescs, float maxDistance, const PtrStepSzb& mask, const PtrStepSzi& trainIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream) { - matchDispatcher< L1Dist >(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains, n, maxDistance, masks, + matchDispatcher< L1Dist >(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains, n, maxDistance, masks, trainIdx, imgIdx, distance, nMatches, cc, stream); } - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchL1_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchL1_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream) { - matchDispatcher(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains, n, maxDistance, masks, + matchDispatcher(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains, n, maxDistance, masks, trainIdx, imgIdx, distance, nMatches, cc, stream); } - //template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchL2_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchL2_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, - const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, + const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream) { - matchDispatcher(static_cast< DevMem2D_ >(query), (const DevMem2D_*)trains, n, maxDistance, masks, + matchDispatcher(static_cast< PtrStepSz >(query), (const PtrStepSz*)trains, n, maxDistance, masks, trainIdx, imgIdx, distance, nMatches, cc, stream); } - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - //template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); - template void matchHamming_gpu(const DevMem2Db& query, const DevMem2Db* trains, int n, float maxDistance, const DevMem2Db* masks, const DevMem2Di& trainIdx, const DevMem2Di& imgIdx, const DevMem2Df& distance, const DevMem2D_& nMatches, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + //template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); + template void matchHamming_gpu(const PtrStepSzb& query, const PtrStepSzb* trains, int n, float maxDistance, const PtrStepSzb* masks, const PtrStepSzi& trainIdx, const PtrStepSzi& imgIdx, const PtrStepSzf& distance, const PtrStepSz& nMatches, int cc, cudaStream_t stream); } // namespace bf_radius_match }}} // namespace cv { namespace gpu { namespace device diff --git a/modules/gpu/src/cuda/bgfg_gmg.cu b/modules/gpu/src/cuda/bgfg_gmg.cu index 76ebb2da09..7fee2d87b3 100644 --- a/modules/gpu/src/cuda/bgfg_gmg.cu +++ b/modules/gpu/src/cuda/bgfg_gmg.cu @@ -168,7 +168,7 @@ namespace cv { namespace gpu { namespace device { template struct Quantization : detail::Quantization::cn> {}; template - __global__ void update(const PtrStep_ frame, PtrStepb fgmask, PtrStepi colors_, PtrStepf weights_, PtrStepi nfeatures_, + __global__ void update(const PtrStep frame, PtrStepb fgmask, PtrStepi colors_, PtrStepf weights_, PtrStepi nfeatures_, const int frameNum, const float learningRate, const bool updateBackgroundModel) { const int x = blockIdx.x * blockDim.x + threadIdx.x; @@ -222,7 +222,7 @@ namespace cv { namespace gpu { namespace device { } template - void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, + void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream) { const dim3 block(32, 8); @@ -230,7 +230,7 @@ namespace cv { namespace gpu { namespace device { cudaSafeCall( cudaFuncSetCacheConfig(update, cudaFuncCachePreferL1) ); - update<<>>((DevMem2D_) frame, fgmask, colors, weights, nfeatures, frameNum, learningRate, updateBackgroundModel); + update<<>>((PtrStepSz) frame, fgmask, colors, weights, nfeatures, frameNum, learningRate, updateBackgroundModel); cudaSafeCall( cudaGetLastError() ); @@ -238,16 +238,16 @@ namespace cv { namespace gpu { namespace device { cudaSafeCall( cudaDeviceSynchronize() ); } - template void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); - template void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); - template void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); + template void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); + template void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); + template void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); - template void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); - template void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); - template void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); + template void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); + template void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); + template void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); - template void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); - template void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); - template void update_gpu(DevMem2Db frame, PtrStepb fgmask, DevMem2Di colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); + template void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); + template void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); + template void update_gpu(PtrStepSzb frame, PtrStepb fgmask, PtrStepSzi colors, PtrStepf weights, PtrStepi nfeatures, int frameNum, float learningRate, bool updateBackgroundModel, cudaStream_t stream); } }}} diff --git a/modules/gpu/src/cuda/bgfg_mog.cu b/modules/gpu/src/cuda/bgfg_mog.cu index 5b4dfc9ada..dcfd502848 100644 --- a/modules/gpu/src/cuda/bgfg_mog.cu +++ b/modules/gpu/src/cuda/bgfg_mog.cu @@ -121,8 +121,8 @@ namespace cv { namespace gpu { namespace device // MOG without learning template - __global__ void mog_withoutLearning(const DevMem2D_ frame, PtrStepb fgmask, - const PtrStepf gmm_weight, const PtrStep_ gmm_mean, const PtrStep_ gmm_var, + __global__ void mog_withoutLearning(const PtrStepSz frame, PtrStepb fgmask, + const PtrStepf gmm_weight, const PtrStep gmm_mean, const PtrStep gmm_var, const int nmixtures, const float varThreshold, const float backgroundRatio) { const int x = blockIdx.x * blockDim.x + threadIdx.x; @@ -172,7 +172,7 @@ namespace cv { namespace gpu { namespace device } template - void mog_withoutLearning_caller(DevMem2Db frame, DevMem2Db fgmask, DevMem2Df weight, DevMem2Db mean, DevMem2Db var, + void mog_withoutLearning_caller(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb var, int nmixtures, float varThreshold, float backgroundRatio, cudaStream_t stream) { dim3 block(32, 8); @@ -180,8 +180,8 @@ namespace cv { namespace gpu { namespace device cudaSafeCall( cudaFuncSetCacheConfig(mog_withoutLearning, cudaFuncCachePreferL1) ); - mog_withoutLearning<<>>((DevMem2D_) frame, fgmask, - weight, (DevMem2D_) mean, (DevMem2D_) var, + mog_withoutLearning<<>>((PtrStepSz) frame, fgmask, + weight, (PtrStepSz) mean, (PtrStepSz) var, nmixtures, varThreshold, backgroundRatio); cudaSafeCall( cudaGetLastError() ); @@ -194,8 +194,8 @@ namespace cv { namespace gpu { namespace device // MOG with learning template - __global__ void mog_withLearning(const DevMem2D_ frame, PtrStepb fgmask, - PtrStepf gmm_weight, PtrStepf gmm_sortKey, PtrStep_ gmm_mean, PtrStep_ gmm_var, + __global__ void mog_withLearning(const PtrStepSz frame, PtrStepb fgmask, + PtrStepf gmm_weight, PtrStepf gmm_sortKey, PtrStep gmm_mean, PtrStep gmm_var, const int nmixtures, const float varThreshold, const float backgroundRatio, const float learningRate, const float minVar) { const float w0 = 0.05f; @@ -324,7 +324,7 @@ namespace cv { namespace gpu { namespace device } template - void mog_withLearning_caller(DevMem2Db frame, DevMem2Db fgmask, DevMem2Df weight, DevMem2Df sortKey, DevMem2Db mean, DevMem2Db var, + void mog_withLearning_caller(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzf weight, PtrStepSzf sortKey, PtrStepSzb mean, PtrStepSzb var, int nmixtures, float varThreshold, float backgroundRatio, float learningRate, float minVar, cudaStream_t stream) { @@ -333,8 +333,8 @@ namespace cv { namespace gpu { namespace device cudaSafeCall( cudaFuncSetCacheConfig(mog_withLearning, cudaFuncCachePreferL1) ); - mog_withLearning<<>>((DevMem2D_) frame, fgmask, - weight, sortKey, (DevMem2D_) mean, (DevMem2D_) var, + mog_withLearning<<>>((PtrStepSz) frame, fgmask, + weight, sortKey, (PtrStepSz) mean, (PtrStepSz) var, nmixtures, varThreshold, backgroundRatio, learningRate, minVar); cudaSafeCall( cudaGetLastError() ); @@ -346,10 +346,10 @@ namespace cv { namespace gpu { namespace device /////////////////////////////////////////////////////////////// // MOG - void mog_gpu(DevMem2Db frame, int cn, DevMem2Db fgmask, DevMem2Df weight, DevMem2Df sortKey, DevMem2Db mean, DevMem2Db var, int nmixtures, float varThreshold, float learningRate, float backgroundRatio, float noiseSigma, cudaStream_t stream) + void mog_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzf weight, PtrStepSzf sortKey, PtrStepSzb mean, PtrStepSzb var, int nmixtures, float varThreshold, float learningRate, float backgroundRatio, float noiseSigma, cudaStream_t stream) { - typedef void (*withoutLearning_t)(DevMem2Db frame, DevMem2Db fgmask, DevMem2Df weight, DevMem2Db mean, DevMem2Db var, int nmixtures, float varThreshold, float backgroundRatio, cudaStream_t stream); - typedef void (*withLearning_t)(DevMem2Db frame, DevMem2Db fgmask, DevMem2Df weight, DevMem2Df sortKey, DevMem2Db mean, DevMem2Db var, int nmixtures, float varThreshold, float backgroundRatio, float learningRate, float minVar, cudaStream_t stream); + typedef void (*withoutLearning_t)(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb var, int nmixtures, float varThreshold, float backgroundRatio, cudaStream_t stream); + typedef void (*withLearning_t)(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzf weight, PtrStepSzf sortKey, PtrStepSzb mean, PtrStepSzb var, int nmixtures, float varThreshold, float backgroundRatio, float learningRate, float minVar, cudaStream_t stream); static const withoutLearning_t withoutLearning[] = { @@ -369,7 +369,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void getBackgroundImage(const PtrStepf gmm_weight, const PtrStep_ gmm_mean, DevMem2D_ dst, const int nmixtures, const float backgroundRatio) + __global__ void getBackgroundImage(const PtrStepf gmm_weight, const PtrStep gmm_mean, PtrStepSz dst, const int nmixtures, const float backgroundRatio) { const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -399,23 +399,23 @@ namespace cv { namespace gpu { namespace device } template - void getBackgroundImage_caller(DevMem2Df weight, DevMem2Db mean, DevMem2Db dst, int nmixtures, float backgroundRatio, cudaStream_t stream) + void getBackgroundImage_caller(PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, int nmixtures, float backgroundRatio, cudaStream_t stream) { dim3 block(32, 8); dim3 grid(divUp(dst.cols, block.x), divUp(dst.rows, block.y)); cudaSafeCall( cudaFuncSetCacheConfig(getBackgroundImage, cudaFuncCachePreferL1) ); - getBackgroundImage<<>>(weight, (DevMem2D_) mean, (DevMem2D_) dst, nmixtures, backgroundRatio); + getBackgroundImage<<>>(weight, (PtrStepSz) mean, (PtrStepSz) dst, nmixtures, backgroundRatio); cudaSafeCall( cudaGetLastError() ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); } - void getBackgroundImage_gpu(int cn, DevMem2Df weight, DevMem2Db mean, DevMem2Db dst, int nmixtures, float backgroundRatio, cudaStream_t stream) + void getBackgroundImage_gpu(int cn, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, int nmixtures, float backgroundRatio, cudaStream_t stream) { - typedef void (*func_t)(DevMem2Df weight, DevMem2Db mean, DevMem2Db dst, int nmixtures, float backgroundRatio, cudaStream_t stream); + typedef void (*func_t)(PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, int nmixtures, float backgroundRatio, cudaStream_t stream); static const func_t funcs[] = { @@ -455,8 +455,8 @@ namespace cv { namespace gpu { namespace device } template - __global__ void mog2(const DevMem2D_ frame, PtrStepb fgmask, PtrStepb modesUsed, - PtrStepf gmm_weight, PtrStepf gmm_variance, PtrStep_ gmm_mean, + __global__ void mog2(const PtrStepSz frame, PtrStepb fgmask, PtrStepb modesUsed, + PtrStepf gmm_weight, PtrStepf gmm_variance, PtrStep gmm_mean, const float alphaT, const float alpha1, const float prune) { const int x = blockIdx.x * blockDim.x + threadIdx.x; @@ -653,7 +653,7 @@ namespace cv { namespace gpu { namespace device } template - void mog2_caller(DevMem2Db frame, DevMem2Db fgmask, DevMem2Db modesUsed, DevMem2Df weight, DevMem2Df variance, DevMem2Db mean, + void mog2_caller(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, float alphaT, float prune, bool detectShadows, cudaStream_t stream) { dim3 block(32, 8); @@ -665,16 +665,16 @@ namespace cv { namespace gpu { namespace device { cudaSafeCall( cudaFuncSetCacheConfig(mog2, cudaFuncCachePreferL1) ); - mog2<<>>((DevMem2D_) frame, fgmask, modesUsed, - weight, variance, (DevMem2D_) mean, + mog2<<>>((PtrStepSz) frame, fgmask, modesUsed, + weight, variance, (PtrStepSz) mean, alphaT, alpha1, prune); } else { cudaSafeCall( cudaFuncSetCacheConfig(mog2, cudaFuncCachePreferL1) ); - mog2<<>>((DevMem2D_) frame, fgmask, modesUsed, - weight, variance, (DevMem2D_) mean, + mog2<<>>((PtrStepSz) frame, fgmask, modesUsed, + weight, variance, (PtrStepSz) mean, alphaT, alpha1, prune); } @@ -684,10 +684,10 @@ namespace cv { namespace gpu { namespace device cudaSafeCall( cudaDeviceSynchronize() ); } - void mog2_gpu(DevMem2Db frame, int cn, DevMem2Db fgmask, DevMem2Db modesUsed, DevMem2Df weight, DevMem2Df variance, DevMem2Db mean, + void mog2_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, float alphaT, float prune, bool detectShadows, cudaStream_t stream) { - typedef void (*func_t)(DevMem2Db frame, DevMem2Db fgmask, DevMem2Db modesUsed, DevMem2Df weight, DevMem2Df variance, DevMem2Db mean, float alphaT, float prune, bool detectShadows, cudaStream_t stream); + typedef void (*func_t)(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzf variance, PtrStepSzb mean, float alphaT, float prune, bool detectShadows, cudaStream_t stream); static const func_t funcs[] = { @@ -698,7 +698,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void getBackgroundImage2(const DevMem2Db modesUsed, const PtrStepf gmm_weight, const PtrStep_ gmm_mean, PtrStep_ dst) + __global__ void getBackgroundImage2(const PtrStepSzb modesUsed, const PtrStepf gmm_weight, const PtrStep gmm_mean, PtrStep dst) { const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -730,23 +730,23 @@ namespace cv { namespace gpu { namespace device } template - void getBackgroundImage2_caller(DevMem2Db modesUsed, DevMem2Df weight, DevMem2Db mean, DevMem2Db dst, cudaStream_t stream) + void getBackgroundImage2_caller(PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream) { dim3 block(32, 8); dim3 grid(divUp(modesUsed.cols, block.x), divUp(modesUsed.rows, block.y)); cudaSafeCall( cudaFuncSetCacheConfig(getBackgroundImage2, cudaFuncCachePreferL1) ); - getBackgroundImage2<<>>(modesUsed, weight, (DevMem2D_) mean, (DevMem2D_) dst); + getBackgroundImage2<<>>(modesUsed, weight, (PtrStepSz) mean, (PtrStepSz) dst); cudaSafeCall( cudaGetLastError() ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); } - void getBackgroundImage2_gpu(int cn, DevMem2Db modesUsed, DevMem2Df weight, DevMem2Db mean, DevMem2Db dst, cudaStream_t stream) + void getBackgroundImage2_gpu(int cn, PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream) { - typedef void (*func_t)(DevMem2Db modesUsed, DevMem2Df weight, DevMem2Db mean, DevMem2Db dst, cudaStream_t stream); + typedef void (*func_t)(PtrStepSzb modesUsed, PtrStepSzf weight, PtrStepSzb mean, PtrStepSzb dst, cudaStream_t stream); static const func_t funcs[] = { diff --git a/modules/gpu/src/cuda/bgfg_vibe.cu b/modules/gpu/src/cuda/bgfg_vibe.cu index ed95dfef21..2b3b7074ea 100644 --- a/modules/gpu/src/cuda/bgfg_vibe.cu +++ b/modules/gpu/src/cuda/bgfg_vibe.cu @@ -90,7 +90,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void init(const DevMem2D_ frame, PtrStep_ samples, PtrStep_ randStates) + __global__ void init(const PtrStepSz frame, PtrStep samples, PtrStep randStates) { const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -116,23 +116,23 @@ namespace cv { namespace gpu { namespace device } template - void init_caller(DevMem2Db frame, DevMem2Db samples, DevMem2D_ randStates, cudaStream_t stream) + void init_caller(PtrStepSzb frame, PtrStepSzb samples, PtrStepSz randStates, cudaStream_t stream) { dim3 block(32, 8); dim3 grid(divUp(frame.cols, block.x), divUp(frame.rows, block.y)); cudaSafeCall( cudaFuncSetCacheConfig(init, cudaFuncCachePreferL1) ); - init<<>>((DevMem2D_) frame, (DevMem2D_) samples, randStates); + init<<>>((PtrStepSz) frame, (PtrStepSz) samples, randStates); cudaSafeCall( cudaGetLastError() ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); } - void init_gpu(DevMem2Db frame, int cn, DevMem2Db samples, DevMem2D_ randStates, cudaStream_t stream) + void init_gpu(PtrStepSzb frame, int cn, PtrStepSzb samples, PtrStepSz randStates, cudaStream_t stream) { - typedef void (*func_t)(DevMem2Db frame, DevMem2Db samples, DevMem2D_ randStates, cudaStream_t stream); + typedef void (*func_t)(PtrStepSzb frame, PtrStepSzb samples, PtrStepSz randStates, cudaStream_t stream); static const func_t funcs[] = { 0, init_caller, 0, init_caller, init_caller @@ -155,7 +155,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void update(const DevMem2D_ frame, PtrStepb fgmask, PtrStep_ samples, PtrStep_ randStates) + __global__ void update(const PtrStepSz frame, PtrStepb fgmask, PtrStep samples, PtrStep randStates) { const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -225,23 +225,23 @@ namespace cv { namespace gpu { namespace device } template - void update_caller(DevMem2Db frame, DevMem2Db fgmask, DevMem2Db samples, DevMem2D_ randStates, cudaStream_t stream) + void update_caller(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb samples, PtrStepSz randStates, cudaStream_t stream) { dim3 block(32, 8); dim3 grid(divUp(frame.cols, block.x), divUp(frame.rows, block.y)); cudaSafeCall( cudaFuncSetCacheConfig(update, cudaFuncCachePreferL1) ); - update<<>>((DevMem2D_) frame, fgmask, (DevMem2D_) samples, randStates); + update<<>>((PtrStepSz) frame, fgmask, (PtrStepSz) samples, randStates); cudaSafeCall( cudaGetLastError() ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); } - void update_gpu(DevMem2Db frame, int cn, DevMem2Db fgmask, DevMem2Db samples, DevMem2D_ randStates, cudaStream_t stream) + void update_gpu(PtrStepSzb frame, int cn, PtrStepSzb fgmask, PtrStepSzb samples, PtrStepSz randStates, cudaStream_t stream) { - typedef void (*func_t)(DevMem2Db frame, DevMem2Db fgmask, DevMem2Db samples, DevMem2D_ randStates, cudaStream_t stream); + typedef void (*func_t)(PtrStepSzb frame, PtrStepSzb fgmask, PtrStepSzb samples, PtrStepSz randStates, cudaStream_t stream); static const func_t funcs[] = { 0, update_caller, 0, update_caller, update_caller diff --git a/modules/gpu/src/cuda/bilateral_filter.cu b/modules/gpu/src/cuda/bilateral_filter.cu index d09268ad8d..abae91d2c5 100644 --- a/modules/gpu/src/cuda/bilateral_filter.cu +++ b/modules/gpu/src/cuda/bilateral_filter.cu @@ -57,7 +57,7 @@ namespace cv { namespace gpu { namespace device __constant__ short cedge_disc; __constant__ short cmax_disc; - void load_constants(float* table_color, DevMem2Df table_space, int ndisp, int radius, short edge_disc, short max_disc) + void load_constants(float* table_color, PtrStepSzf table_space, int ndisp, int radius, short edge_disc, short max_disc) { cudaSafeCall( cudaMemcpyToSymbol(ctable_color, &table_color, sizeof(table_color)) ); cudaSafeCall( cudaMemcpyToSymbol(ctable_space, &table_space.data, sizeof(table_space.data)) ); @@ -176,7 +176,7 @@ namespace cv { namespace gpu { namespace device } template - void bilateral_filter_caller(DevMem2D_ disp, DevMem2Db img, int channels, int iters, cudaStream_t stream) + void bilateral_filter_caller(PtrStepSz disp, PtrStepSzb img, int channels, int iters, cudaStream_t stream) { dim3 threads(32, 8, 1); dim3 grid(1, 1, 1); @@ -213,12 +213,12 @@ namespace cv { namespace gpu { namespace device cudaSafeCall( cudaDeviceSynchronize() ); } - void bilateral_filter_gpu(DevMem2Db disp, DevMem2Db img, int channels, int iters, cudaStream_t stream) + void bilateral_filter_gpu(PtrStepSzb disp, PtrStepSzb img, int channels, int iters, cudaStream_t stream) { bilateral_filter_caller(disp, img, channels, iters, stream); } - void bilateral_filter_gpu(DevMem2D_ disp, DevMem2Db img, int channels, int iters, cudaStream_t stream) + void bilateral_filter_gpu(PtrStepSz disp, PtrStepSzb img, int channels, int iters, cudaStream_t stream) { bilateral_filter_caller(disp, img, channels, iters, stream); } diff --git a/modules/gpu/src/cuda/calib3d.cu b/modules/gpu/src/cuda/calib3d.cu index 4776c55724..5def4ad245 100644 --- a/modules/gpu/src/cuda/calib3d.cu +++ b/modules/gpu/src/cuda/calib3d.cu @@ -66,8 +66,8 @@ namespace cv { namespace gpu { namespace device } }; - void call(const DevMem2D_ src, const float* rot, - const float* transl, DevMem2D_ dst, + void call(const PtrStepSz src, const float* rot, + const float* transl, PtrStepSz dst, cudaStream_t stream) { cudaSafeCall(cudaMemcpyToSymbol(crot0, rot, sizeof(float) * 3)); @@ -103,8 +103,8 @@ namespace cv { namespace gpu { namespace device } }; - void call(const DevMem2D_ src, const float* rot, - const float* transl, const float* proj, DevMem2D_ dst, + void call(const PtrStepSz src, const float* rot, + const float* transl, const float* proj, PtrStepSz dst, cudaStream_t stream) { cudaSafeCall(cudaMemcpyToSymbol(crot0, rot, sizeof(float) * 3)); diff --git a/modules/gpu/src/cuda/ccomponetns.cu b/modules/gpu/src/cuda/ccomponetns.cu index 076fdcc125..e92615e5f7 100644 --- a/modules/gpu/src/cuda/ccomponetns.cu +++ b/modules/gpu/src/cuda/ccomponetns.cu @@ -176,7 +176,7 @@ namespace cv { namespace gpu { namespace device template - __global__ void computeConnectivity(const DevMem2D_ image, DevMem2D components, F connected) + __global__ void computeConnectivity(const PtrStepSz image, PtrStepSzb components, F connected) { int x = threadIdx.x + blockIdx.x * blockDim.x; int y = threadIdx.y + blockIdx.y * blockDim.y; @@ -202,7 +202,7 @@ namespace cv { namespace gpu { namespace device } template< typename T> - void computeEdges(const DevMem2D& image, DevMem2D edges, const float4& lo, const float4& hi, cudaStream_t stream) + void computeEdges(const PtrStepSzb& image, PtrStepSzb edges, const float4& lo, const float4& hi, cudaStream_t stream) { dim3 block(CTA_SIZE_X, CTA_SIZE_Y); dim3 grid(divUp(image.cols, block.x), divUp(image.rows, block.y)); @@ -210,23 +210,23 @@ namespace cv { namespace gpu { namespace device typedef InInterval::dist_type, IntervalsTraits::ch> Int_t; Int_t inInt(lo, hi); - computeConnectivity<<>>(static_cast >(image), edges, inInt); + computeConnectivity<<>>(static_cast >(image), edges, inInt); cudaSafeCall( cudaGetLastError() ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); } - template void computeEdges (const DevMem2D& image, DevMem2D edges, const float4& lo, const float4& hi, cudaStream_t stream); - template void computeEdges (const DevMem2D& image, DevMem2D edges, const float4& lo, const float4& hi, cudaStream_t stream); - template void computeEdges (const DevMem2D& image, DevMem2D edges, const float4& lo, const float4& hi, cudaStream_t stream); - template void computeEdges (const DevMem2D& image, DevMem2D edges, const float4& lo, const float4& hi, cudaStream_t stream); - template void computeEdges(const DevMem2D& image, DevMem2D edges, const float4& lo, const float4& hi, cudaStream_t stream); - template void computeEdges(const DevMem2D& image, DevMem2D edges, const float4& lo, const float4& hi, cudaStream_t stream); - template void computeEdges (const DevMem2D& image, DevMem2D edges, const float4& lo, const float4& hi, cudaStream_t stream); - template void computeEdges (const DevMem2D& image, DevMem2D edges, const float4& lo, const float4& hi, cudaStream_t stream); + template void computeEdges (const PtrStepSzb& image, PtrStepSzb edges, const float4& lo, const float4& hi, cudaStream_t stream); + template void computeEdges (const PtrStepSzb& image, PtrStepSzb edges, const float4& lo, const float4& hi, cudaStream_t stream); + template void computeEdges (const PtrStepSzb& image, PtrStepSzb edges, const float4& lo, const float4& hi, cudaStream_t stream); + template void computeEdges (const PtrStepSzb& image, PtrStepSzb edges, const float4& lo, const float4& hi, cudaStream_t stream); + template void computeEdges(const PtrStepSzb& image, PtrStepSzb edges, const float4& lo, const float4& hi, cudaStream_t stream); + template void computeEdges(const PtrStepSzb& image, PtrStepSzb edges, const float4& lo, const float4& hi, cudaStream_t stream); + template void computeEdges (const PtrStepSzb& image, PtrStepSzb edges, const float4& lo, const float4& hi, cudaStream_t stream); + template void computeEdges (const PtrStepSzb& image, PtrStepSzb edges, const float4& lo, const float4& hi, cudaStream_t stream); - __global__ void lableTiles(const DevMem2D edges, DevMem2Di comps) + __global__ void lableTiles(const PtrStepSzb edges, PtrStepSzi comps) { int x = threadIdx.x + blockIdx.x * TILE_COLS; int y = threadIdx.y + blockIdx.y * TILE_ROWS; @@ -360,7 +360,7 @@ namespace cv { namespace gpu { namespace device } } - __device__ __forceinline__ int root(const DevMem2Di& comps, int label) + __device__ __forceinline__ int root(const PtrStepSzi& comps, int label) { while(1) { @@ -376,7 +376,7 @@ namespace cv { namespace gpu { namespace device return label; } - __device__ __forceinline__ void isConnected(DevMem2Di& comps, int l1, int l2, bool& changed) + __device__ __forceinline__ void isConnected(PtrStepSzi& comps, int l1, int l2, bool& changed) { int r1 = root(comps, l1); int r2 = root(comps, l2); @@ -394,7 +394,7 @@ namespace cv { namespace gpu { namespace device } __global__ void crossMerge(const int tilesNumY, const int tilesNumX, int tileSizeY, int tileSizeX, - const DevMem2D edges, DevMem2Di comps, const int yIncomplete, int xIncomplete) + const PtrStepSzb edges, PtrStepSzi comps, const int yIncomplete, int xIncomplete) { int tid = threadIdx.y * blockDim.x + threadIdx.x; int stride = blockDim.y * blockDim.x; @@ -482,7 +482,7 @@ namespace cv { namespace gpu { namespace device } while (Emulation::syncthreadsOr(changed)); } - __global__ void flatten(const DevMem2D edges, DevMem2Di comps) + __global__ void flatten(const PtrStepSzb edges, PtrStepSzi comps) { int x = threadIdx.x + blockIdx.x * blockDim.x; int y = threadIdx.y + blockIdx.y * blockDim.y; @@ -493,7 +493,7 @@ namespace cv { namespace gpu { namespace device enum {CC_NO_COMPACT = 0, CC_COMPACT_LABELS = 1}; - void labelComponents(const DevMem2D& edges, DevMem2Di comps, int flags, cudaStream_t stream) + void labelComponents(const PtrStepSzb& edges, PtrStepSzi comps, int flags, cudaStream_t stream) { dim3 block(CTA_SIZE_X, CTA_SIZE_Y); dim3 grid(divUp(edges.cols, TILE_COLS), divUp(edges.rows, TILE_ROWS)); diff --git a/modules/gpu/src/cuda/color.cu b/modules/gpu/src/cuda/color.cu index 562f3ff2c5..54925abe62 100644 --- a/modules/gpu/src/cuda/color.cu +++ b/modules/gpu/src/cuda/color.cu @@ -222,12 +222,12 @@ namespace cv { namespace gpu { namespace device }; #define OPENCV_GPU_IMPLEMENT_CVTCOLOR(name, traits) \ - void name(const DevMem2Db& src, const DevMem2Db& dst, cudaStream_t stream) \ + void name(const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream) \ { \ traits::functor_type functor = traits::create_functor(); \ typedef typename traits::functor_type::argument_type src_t; \ typedef typename traits::functor_type::result_type dst_t; \ - cv::gpu::device::transform((DevMem2D_)src, (DevMem2D_)dst, functor, WithOutMask(), stream); \ + cv::gpu::device::transform((PtrStepSz)src, (PtrStepSz)dst, functor, WithOutMask(), stream); \ } #define OPENCV_GPU_IMPLEMENT_CVTCOLOR_ONE(name) \ diff --git a/modules/gpu/src/cuda/column_filter.cu b/modules/gpu/src/cuda/column_filter.cu index fb52d6e989..307e87ad34 100644 --- a/modules/gpu/src/cuda/column_filter.cu +++ b/modules/gpu/src/cuda/column_filter.cu @@ -62,7 +62,7 @@ namespace cv { namespace gpu { namespace device } template - __global__ void linearColumnFilter(const DevMem2D_ src, PtrStep dst, const int anchor, const B brd) + __global__ void linearColumnFilter(const PtrStepSz src, PtrStep dst, const int anchor, const B brd) { #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 200) const int BLOCK_DIM_X = 16; @@ -125,7 +125,7 @@ namespace cv { namespace gpu { namespace device } template class B> - void linearColumnFilter_caller(DevMem2D_ src, DevMem2D_ dst, int anchor, int cc, cudaStream_t stream) + void linearColumnFilter_caller(PtrStepSz src, PtrStepSz dst, int anchor, int cc, cudaStream_t stream) { int BLOCK_DIM_X; int BLOCK_DIM_Y; @@ -158,9 +158,9 @@ namespace cv { namespace gpu { namespace device } template - void linearColumnFilter_gpu(DevMem2Db src, DevMem2Db dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream) + void linearColumnFilter_gpu(PtrStepSzb src, PtrStepSzb dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream) { - typedef void (*caller_t)(DevMem2D_ src, DevMem2D_ dst, int anchor, int cc, cudaStream_t stream); + typedef void (*caller_t)(PtrStepSz src, PtrStepSz dst, int anchor, int cc, cudaStream_t stream); static const caller_t callers[5][33] = { @@ -343,13 +343,13 @@ namespace cv { namespace gpu { namespace device loadKernel(kernel, ksize); - callers[brd_type][ksize]((DevMem2D_)src, (DevMem2D_)dst, anchor, cc, stream); + callers[brd_type][ksize]((PtrStepSz)src, (PtrStepSz)dst, anchor, cc, stream); } - template void linearColumnFilter_gpu(DevMem2Db src, DevMem2Db dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream); - template void linearColumnFilter_gpu(DevMem2Db src, DevMem2Db dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream); - template void linearColumnFilter_gpu(DevMem2Db src, DevMem2Db dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream); - template void linearColumnFilter_gpu(DevMem2Db src, DevMem2Db dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream); - template void linearColumnFilter_gpu(DevMem2Db src, DevMem2Db dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream); + template void linearColumnFilter_gpu(PtrStepSzb src, PtrStepSzb dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream); + template void linearColumnFilter_gpu(PtrStepSzb src, PtrStepSzb dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream); + template void linearColumnFilter_gpu(PtrStepSzb src, PtrStepSzb dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream); + template void linearColumnFilter_gpu(PtrStepSzb src, PtrStepSzb dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream); + template void linearColumnFilter_gpu(PtrStepSzb src, PtrStepSzb dst, const float kernel[], int ksize, int anchor, int brd_type, int cc, cudaStream_t stream); } // namespace column_filter }}} // namespace cv { namespace gpu { namespace device diff --git a/modules/gpu/src/cuda/copy_make_border.cu b/modules/gpu/src/cuda/copy_make_border.cu index a54a9b7db2..71859f2b77 100644 --- a/modules/gpu/src/cuda/copy_make_border.cu +++ b/modules/gpu/src/cuda/copy_make_border.cu @@ -47,7 +47,7 @@ namespace cv { namespace gpu { namespace device { namespace imgproc { - template __global__ void copyMakeBorder(const Ptr2D src, DevMem2D_ dst, int top, int left) + template __global__ void copyMakeBorder(const Ptr2D src, PtrStepSz dst, int top, int left) { const int x = blockDim.x * blockIdx.x + threadIdx.x; const int y = blockDim.y * blockIdx.y + threadIdx.y; @@ -58,7 +58,7 @@ namespace cv { namespace gpu { namespace device template