From 3c748ccf10e790138e31b9b5715aca032c1757f0 Mon Sep 17 00:00:00 2001 From: Vladislav Sovrasov Date: Wed, 28 Jun 2017 13:57:24 +0300 Subject: [PATCH 1/2] core: add an ability to use cxx11 lambda as a parallel_for_ body --- .../how_to_use_OpenCV_parallel_for_.markdown | 7 ++++- modules/core/include/opencv2/core/utility.hpp | 26 +++++++++++++++++++ .../how_to_use_OpenCV_parallel_for_.cpp | 25 ++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/doc/tutorials/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.markdown b/doc/tutorials/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.markdown index f2a511fc21..f37b81e060 100644 --- a/doc/tutorials/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.markdown +++ b/doc/tutorials/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.markdown @@ -153,7 +153,7 @@ The first thing is to declare a custom class that inherits from @ref cv::Paralle `virtual void operator ()(const cv::Range& range) const`. The range in the `operator ()` represents the subset of pixels that will be treated by an individual thread. -This splitting is done automatically to distribuate equally the computation load. We have to convert the pixel index coordinate +This splitting is done automatically to distribute equally the computation load. We have to convert the pixel index coordinate to a 2D `[row, col]` coordinate. Also note that we have to keep a reference on the mat image to be able to modify in-place the image. @@ -167,6 +167,11 @@ nstripes parameter in @ref cv::parallel_for_. For instance, if your processor ha or setting `nstripes=2` should be the same as by default it will use all the processor threads available but will split the workload only on two threads. +@note +C++ 11 standard allows to simplify the parallel implementation by get rid of the `ParallelMandelbrot` class and replacing it with lambda expression: + +@snippet how_to_use_OpenCV_parallel_for_.cpp mandelbrot-parallel-call-cxx11 + Results ----------- diff --git a/modules/core/include/opencv2/core/utility.hpp b/modules/core/include/opencv2/core/utility.hpp index 8a923c9f42..411fc013dc 100644 --- a/modules/core/include/opencv2/core/utility.hpp +++ b/modules/core/include/opencv2/core/utility.hpp @@ -56,6 +56,10 @@ #include "opencv2/core.hpp" #include +#if __cplusplus >= 201103L +#include +#endif + namespace cv { @@ -478,6 +482,28 @@ public: */ CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body, double nstripes=-1.); +#if __cplusplus >= 201103L +class ParallelLoopBodyLambdaWrapper : public ParallelLoopBody +{ +private: + std::function m_functor; +public: + ParallelLoopBodyLambdaWrapper(std::function functor) : + m_functor(functor) + { } + + virtual void operator() (const cv::Range& range) const + { + m_functor(range); + } +}; + +inline void parallel_for_(const Range& range, std::function functor, double nstripes=-1.) +{ + parallel_for_(range, ParallelLoopBodyLambdaWrapper(functor), nstripes); +} +#endif + /////////////////////////////// forEach method of cv::Mat //////////////////////////// template inline void Mat::forEach_impl(const Functor& operation) { diff --git a/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp b/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp index c661b919b3..59dcb69954 100644 --- a/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp +++ b/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp @@ -101,10 +101,35 @@ int main() //! [mandelbrot-transformation] double t1 = (double) getTickCount(); + + #if __cplusplus >= 201103L + + //! [mandelbrot-parallel-call-cxx11] + parallel_for_(Range(0, mandelbrotImg.rows*mandelbrotImg.cols), [&](const Range& range){ + for (int r = range.start; r < range.end; r++) + { + int i = r / mandelbrotImg.cols; + int j = r % mandelbrotImg.cols; + + float x0 = j / scaleX + x1; + float y0 = i / scaleY + y1; + + complex z0(x0, y0); + uchar value = (uchar) mandelbrotFormula(z0); + mandelbrotImg.ptr(i)[j] = value; + } + }); + //! [mandelbrot-parallel-call-cxx11] + + #else + //! [mandelbrot-parallel-call] ParallelMandelbrot parallelMandelbrot(mandelbrotImg, x1, y1, scaleX, scaleY); parallel_for_(Range(0, mandelbrotImg.rows*mandelbrotImg.cols), parallelMandelbrot); //! [mandelbrot-parallel-call] + + #endif + t1 = ((double) getTickCount() - t1) / getTickFrequency(); cout << "Parallel Mandelbrot: " << t1 << " s" << endl; From 08db55fb6235d5d343dc801272a86b9ce4c70ca0 Mon Sep 17 00:00:00 2001 From: Vladislav Sovrasov Date: Wed, 28 Jun 2017 16:07:07 +0300 Subject: [PATCH 2/2] core: add CV_CXX_11 flag to cvdef.h --- modules/core/include/opencv2/core/cvdef.h | 14 ++++++++++++++ modules/core/include/opencv2/core/utility.hpp | 4 ++-- .../how_to_use_OpenCV_parallel_for_.cpp | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/modules/core/include/opencv2/core/cvdef.h b/modules/core/include/opencv2/core/cvdef.h index 47b2c12637..46001d48e3 100644 --- a/modules/core/include/opencv2/core/cvdef.h +++ b/modules/core/include/opencv2/core/cvdef.h @@ -358,6 +358,20 @@ Cv64suf; #endif +/****************************************************************************************\ +* C++ 11 * +\****************************************************************************************/ +#ifndef CV_CXX_11 +# if __cplusplus >= 201103L || defined(_MSC_VER) && _MSC_VER >= 1600 +# define CV_CXX_11 1 +# endif +#else +# if CV_CXX_11 == 0 +# undef CV_CXX_11 +# endif +#endif + + /****************************************************************************************\ * C++ Move semantics * \****************************************************************************************/ diff --git a/modules/core/include/opencv2/core/utility.hpp b/modules/core/include/opencv2/core/utility.hpp index 411fc013dc..3590f9be34 100644 --- a/modules/core/include/opencv2/core/utility.hpp +++ b/modules/core/include/opencv2/core/utility.hpp @@ -56,7 +56,7 @@ #include "opencv2/core.hpp" #include -#if __cplusplus >= 201103L +#ifdef CV_CXX_11 #include #endif @@ -482,7 +482,7 @@ public: */ CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body, double nstripes=-1.); -#if __cplusplus >= 201103L +#ifdef CV_CXX_11 class ParallelLoopBodyLambdaWrapper : public ParallelLoopBody { private: diff --git a/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp b/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp index 59dcb69954..5f7013a470 100644 --- a/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp +++ b/samples/cpp/tutorial_code/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.cpp @@ -102,7 +102,7 @@ int main() double t1 = (double) getTickCount(); - #if __cplusplus >= 201103L + #ifdef CV_CXX_11 //! [mandelbrot-parallel-call-cxx11] parallel_for_(Range(0, mandelbrotImg.rows*mandelbrotImg.cols), [&](const Range& range){