parallel version
authorIlya Lavrenov <ilya.lavrenov@itseez.com>
Wed, 9 Apr 2014 20:01:10 +0000 (00:01 +0400)
committerIlya Lavrenov <ilya.lavrenov@itseez.com>
Thu, 10 Apr 2014 15:39:00 +0000 (19:39 +0400)
modules/imgproc/src/histogram.cpp

index cdccde0..8e8484d 100644 (file)
@@ -1175,6 +1175,48 @@ calcHist_8u( std::vector<uchar*>& _ptrs, const std::vector<int>& _deltas,
     }
 }
 
+#if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY
+
+class IPPCalcHistInvoker :
+    public ParallelLoopBody
+{
+public:
+    IPPCalcHistInvoker(const Mat & _src, Mat & _hist, AutoBuffer<Ipp32s> & _levels, Ipp32s _histSize, Ipp32s _low, Ipp32s _high, bool * _ok) :
+        ParallelLoopBody(), src(&_src), hist(&_hist), levels(&_levels), histSize(_histSize), low(_low), high(_high), ok(_ok)
+    {
+        *ok = true;
+    }
+
+    virtual void operator() (const Range & range) const
+    {
+        Mat phist(hist->size(), hist->type(), Scalar::all(0));
+
+        IppStatus status = ippiHistogramEven_8u_C1R(
+            src->data + src->step * range.start, (int)src->step, ippiSize(src->cols, range.end - range.start),
+            (Ipp32s *)phist.data, (Ipp32s *)*levels, histSize, low, high);
+
+        if (status < 0)
+        {
+            *ok = false;
+            return;
+        }
+
+        for (int i = 0; i < histSize; ++i)
+            CV_XADD((int *)(hist->data + i * hist->step), *(int *)(phist.data + i * phist.step));
+    }
+
+private:
+    const Mat * src;
+    Mat * hist;
+    AutoBuffer<Ipp32s> * levels;
+    Ipp32s histSize, low, high;
+    bool * ok;
+
+    const IPPCalcHistInvoker & operator = (const IPPCalcHistInvoker & );
+};
+
+#endif
+
 }
 
 void cv::calcHist( const Mat* images, int nimages, const int* channels,
@@ -1190,19 +1232,25 @@ void cv::calcHist( const Mat* images, int nimages, const int* channels,
     Mat hist = _hist.getMat(), ihist = hist;
     ihist.flags = (ihist.flags & ~CV_MAT_TYPE_MASK)|CV_32S;
 
-#ifdef HAVE_IPP
+#if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY
     if (nimages == 1 && images[0].type() == CV_8UC1 && dims == 1 && channels &&
             channels[0] == 0 && mask.empty() && images[0].dims <= 2 &&
             !accumulate && uniform)
     {
-        hist.setTo(Scalar::all(0));
+        ihist.setTo(Scalar::all(0));
         AutoBuffer<Ipp32s> levels(histSize[0] + 1);
-        IppStatus status =
-                ippiHistogramEven_8u_C1R(
-                    (const Ipp8u *)images[0].data, (int)images[0].step, ippiSize(images[0].size()),
-                    (Ipp32s *)ihist.data, (Ipp32s *)levels, histSize[0] + 1, (Ipp32s)ranges[0][0], (Ipp32s)ranges[0][1]);
 
-        if (status >= 0)
+        bool ok = true;
+        const Mat & src = images[0];
+        int nstripes = std::min<int>(8, src.total() / (1 << 16));
+#ifdef HAVE_CONCURRENCY
+        nstripes = 1;
+#endif
+        IPPCalcHistInvoker invoker(src, ihist, levels, histSize[0] + 1, (Ipp32s)ranges[0][0], (Ipp32s)ranges[0][1], &ok);
+        Range range(0, src.rows);
+        parallel_for_(range, invoker, nstripes);
+
+        if (ok)
         {
             ihist.convertTo(hist, CV_32F);
             return;