Merge pull request #9017 from sovrasov:parallel_for_cxx11

This commit is contained in:
Vadim Pisarevsky 2017-06-29 11:12:57 +00:00
commit 5f1b6ee889
4 changed files with 71 additions and 1 deletions

View File

@ -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`. `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. 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 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. 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 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. 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 Results
----------- -----------

View File

@ -354,6 +354,20 @@ Cv64suf;
#endif #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 * * C++ Move semantics *
\****************************************************************************************/ \****************************************************************************************/

View File

@ -56,6 +56,10 @@
#include "opencv2/core.hpp" #include "opencv2/core.hpp"
#include <ostream> #include <ostream>
#ifdef CV_CXX_11
#include <functional>
#endif
namespace cv namespace cv
{ {
@ -478,6 +482,28 @@ public:
*/ */
CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body, double nstripes=-1.); CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body, double nstripes=-1.);
#ifdef CV_CXX_11
class ParallelLoopBodyLambdaWrapper : public ParallelLoopBody
{
private:
std::function<void(const Range&)> m_functor;
public:
ParallelLoopBodyLambdaWrapper(std::function<void(const Range&)> functor) :
m_functor(functor)
{ }
virtual void operator() (const cv::Range& range) const
{
m_functor(range);
}
};
inline void parallel_for_(const Range& range, std::function<void(const Range&)> functor, double nstripes=-1.)
{
parallel_for_(range, ParallelLoopBodyLambdaWrapper(functor), nstripes);
}
#endif
/////////////////////////////// forEach method of cv::Mat //////////////////////////// /////////////////////////////// forEach method of cv::Mat ////////////////////////////
template<typename _Tp, typename Functor> inline template<typename _Tp, typename Functor> inline
void Mat::forEach_impl(const Functor& operation) { void Mat::forEach_impl(const Functor& operation) {

View File

@ -101,10 +101,35 @@ int main()
//! [mandelbrot-transformation] //! [mandelbrot-transformation]
double t1 = (double) getTickCount(); double t1 = (double) getTickCount();
#ifdef CV_CXX_11
//! [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<float> z0(x0, y0);
uchar value = (uchar) mandelbrotFormula(z0);
mandelbrotImg.ptr<uchar>(i)[j] = value;
}
});
//! [mandelbrot-parallel-call-cxx11]
#else
//! [mandelbrot-parallel-call] //! [mandelbrot-parallel-call]
ParallelMandelbrot parallelMandelbrot(mandelbrotImg, x1, y1, scaleX, scaleY); ParallelMandelbrot parallelMandelbrot(mandelbrotImg, x1, y1, scaleX, scaleY);
parallel_for_(Range(0, mandelbrotImg.rows*mandelbrotImg.cols), parallelMandelbrot); parallel_for_(Range(0, mandelbrotImg.rows*mandelbrotImg.cols), parallelMandelbrot);
//! [mandelbrot-parallel-call] //! [mandelbrot-parallel-call]
#endif
t1 = ((double) getTickCount() - t1) / getTickFrequency(); t1 = ((double) getTickCount() - t1) / getTickFrequency();
cout << "Parallel Mandelbrot: " << t1 << " s" << endl; cout << "Parallel Mandelbrot: " << t1 << " s" << endl;