Added ippiDistanceTransform for cv::distanceTransform, maskSize=3,5
authorElena Gvozdeva <elena.gvozdeva@itseez.com>
Wed, 9 Apr 2014 13:03:06 +0000 (17:03 +0400)
committerElena Gvozdeva <elena.gvozdeva@itseez.com>
Mon, 21 Apr 2014 11:17:55 +0000 (15:17 +0400)
modules/imgproc/doc/miscellaneous_transformations.rst
modules/imgproc/include/opencv2/imgproc.hpp
modules/imgproc/perf/perf_distanceTransform.cpp
modules/imgproc/src/distransform.cpp

index 32690cf..c8f7d15 100644 (file)
@@ -411,7 +411,7 @@ 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 )
+.. ocv:function:: void distanceTransform( InputArray src, OutputArray dst, int distanceType, int maskSize, int dstType=CV_32F )
 
 .. ocv:function:: void distanceTransform( InputArray src, OutputArray dst, OutputArray labels, int distanceType, int maskSize, int labelType=DIST_LABEL_CCOMP )
 
@@ -421,12 +421,14 @@ Calculates the distance to the closest zero pixel for each pixel of the source i
 
     :param src: 8-bit, single-channel (binary) source image.
 
-    :param dst: Output image with calculated distances. It is a 32-bit floating-point, single-channel image of the same size as  ``src`` .
+    :param dst: Output image with calculated distances. It is a 8-bit or 32-bit floating-point, single-channel image of the same size as  ``src`` .
 
     :param distanceType: Type of distance. It can be  ``CV_DIST_L1, CV_DIST_L2`` , or  ``CV_DIST_C`` .
 
     :param maskSize: Size of the distance transform mask. It can be 3, 5, or  ``CV_DIST_MASK_PRECISE``  (the latter option is only supported by the first function). In case of the ``CV_DIST_L1``  or  ``CV_DIST_C``  distance type, the parameter is forced to 3 because a  :math:`3\times 3`  mask gives the same result as  :math:`5\times 5`  or any larger aperture.
 
+    :param dstType: Type of output image. It can be ``CV_8U`` or ``CV_32F``. Type ``CV_8U`` can be used only for the first variant of the function and ``distanceType == CV_DIST_L1``.
+
     :param labels: Optional output 2D array of labels (the discrete Voronoi diagram). It has the type  ``CV_32SC1``  and the same size as  ``src`` . See the details below.
 
     :param labelType: Type of the label array to build. If ``labelType==DIST_LABEL_CCOMP`` then each connected component of zeros in ``src`` (as well as all the non-zero pixels closest to the connected component) will be assigned the same label. If ``labelType==DIST_LABEL_PIXEL`` then each zero pixel (and all the non-zero pixels closest to it) gets its own label.
index ffa4165..7928ae0 100644 (file)
@@ -1389,7 +1389,7 @@ CV_EXPORTS_AS(distanceTransformWithLabels) void distanceTransform( InputArray sr
 
 //! computes the distance transform map
 CV_EXPORTS_W void distanceTransform( InputArray src, OutputArray dst,
-                                     int distanceType, int maskSize );
+                                     int distanceType, int maskSize, int dstType=CV_32F);
 
 
 //! fills the semi-uniform image region starting from the specified seed point
index c1deb93..6136a65 100644 (file)
@@ -21,3 +21,82 @@ PERF_TEST_P(Size_DistanceTransform, icvTrueDistTrans, testing::Values(TYPICAL_MA
 
     SANITY_CHECK(dst, 1);
 }*/
+
+#include "perf_precomp.hpp"
+
+using namespace std;
+using namespace cv;
+using namespace perf;
+using std::tr1::make_tuple;
+using std::tr1::get;
+
+CV_ENUM(DistanceType, DIST_L1, DIST_L2 , DIST_C)
+CV_ENUM(MaskSize, DIST_MASK_3, DIST_MASK_5, DIST_MASK_PRECISE)
+CV_ENUM(DstType, CV_8U, CV_32F)
+CV_ENUM(LabelType, DIST_LABEL_CCOMP, DIST_LABEL_PIXEL)
+
+typedef std::tr1::tuple<Size, DistanceType, MaskSize, DstType> SrcSize_DistType_MaskSize_DstType;
+typedef std::tr1::tuple<Size, DistanceType, MaskSize, LabelType> SrcSize_DistType_MaskSize_LabelType;
+typedef perf::TestBaseWithParam<SrcSize_DistType_MaskSize_DstType> DistanceTransform_Test;
+typedef perf::TestBaseWithParam<SrcSize_DistType_MaskSize_LabelType> DistanceTransform_NeedLabels_Test;
+
+PERF_TEST_P(DistanceTransform_Test, distanceTransform,
+            testing::Combine(
+                testing::Values(cv::Size(640, 480), cv::Size(800, 600), cv::Size(1024, 768), cv::Size(1280, 1024)),
+                DistanceType::all(),
+                MaskSize::all(),
+                DstType::all()
+                )
+            )
+{
+    Size srcSize = get<0>(GetParam());
+    int distanceType = get<1>(GetParam());
+    int maskSize = get<2>(GetParam());
+    int dstType = get<3>(GetParam());
+
+    Mat src(srcSize, CV_8U);
+    Mat dst(srcSize, dstType);
+
+    declare
+        .in(src, WARMUP_RNG)
+        .out(dst, WARMUP_RNG)
+        .time(30);
+
+    TEST_CYCLE() distanceTransform( src, dst, distanceType, maskSize, dstType);
+
+    double eps = 2e-4;
+
+    SANITY_CHECK(dst, eps);
+}
+
+PERF_TEST_P(DistanceTransform_NeedLabels_Test, distanceTransform_NeedLabels,
+            testing::Combine(
+                testing::Values(cv::Size(640, 480), cv::Size(800, 600), cv::Size(1024, 768), cv::Size(1280, 1024)),
+                DistanceType::all(),
+                MaskSize::all(),
+                LabelType::all()
+                )
+    )
+{
+    Size srcSize = get<0>(GetParam());
+    int distanceType = get<1>(GetParam());
+    int maskSize = get<2>(GetParam());
+    int labelType = get<3>(GetParam());
+
+    Mat src(srcSize, CV_8U);
+    Mat label(srcSize, CV_32S);
+    Mat dst(srcSize, CV_32F);
+
+    declare
+        .in(src, WARMUP_RNG)
+        .out(label, WARMUP_RNG)
+        .out(dst, WARMUP_RNG)
+        .time(30);
+
+    TEST_CYCLE() distanceTransform( src, dst, label, distanceType, maskSize, labelType);
+
+    double eps = 2e-4;
+
+    SANITY_CHECK(label, eps);
+    SANITY_CHECK(dst, eps);
+}
index 7173fe3..220696c 100644 (file)
@@ -488,7 +488,6 @@ struct DTColumnInvoker : ParallelLoopBody
     const float* sqr_tab;
 };
 
-
 struct DTRowInvoker : ParallelLoopBody
 {
     DTRowInvoker( Mat* _dst, const float* _sqr_tab, const float* _inv_tab )
@@ -578,7 +577,7 @@ trueDistTrans( const Mat& src, Mat& dst )
     for( ; i <= m*3; i++ )
         sat_tab[i] = i - shift;
 
-    cv::parallel_for_(cv::Range(0, n), cv::DTColumnInvoker(&src, &dst, sat_tab, sqr_tab));
+    cv::parallel_for_(cv::Range(0, n), cv::DTColumnInvoker(&src, &dst, sat_tab, sqr_tab)); //dst.total()/(double)(1<<16)
 
     // stage 2: compute modified distance transform for each row
     float* inv_tab = sqr_tab + n;
@@ -669,7 +668,8 @@ distanceATS_L1_8u( const Mat& src, Mat& dst )
         {
             int b = dbase[x+dststep];
             a = lut[MIN(a, b)];
-            dbase[x] = (uchar)(MIN(a, dbase[x]));
+            a = MIN(a, dbase[x]);
+            dbase[x] = (uchar)(a);
         }
     }
 }
@@ -677,23 +677,39 @@ distanceATS_L1_8u( const Mat& src, Mat& dst )
 
 }
 
+namespace cv
+{
+static void distanceTransform_L1_8U(InputArray _src, OutputArray _dst)
+{
+    Mat src = _src.getMat();
+
+    CV_Assert( src.type() == CV_8UC1);
+
+    _dst.create( src.size(), CV_8UC1);
+    Mat dst = _dst.getMat();
+
+    #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) && !defined HAVE_IPP_ICV_ONLY
+                IppiSize roi = { src.cols, src.rows };
+                Ipp32s pMetrics[2] = { 1, 2 }; //L1, 3x3 mask
+                if (ippiDistanceTransform_3x3_8u_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<uchar>(), (int)dst.step, roi, pMetrics)>=0)
+                    return;
+    #endif
+
+    distanceATS_L1_8u(src, dst);
+}
+}
 
 // Wrapper function for distance transform group
 void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels,
                             int distType, int maskSize, int labelType )
 {
-    Mat src = _src.getMat(), dst = _dst.getMat(), labels;
+    Mat src = _src.getMat(), labels;
     bool need_labels = _labels.needed();
 
-    CV_Assert( src.type() == CV_8U );
-    if( dst.size == src.size && dst.type() == CV_8U && !need_labels && distType == CV_DIST_L1 )
-    {
-        distanceATS_L1_8u(src, dst);
-        return;
-    }
+    CV_Assert( src.type() == CV_8UC1);
 
-    _dst.create( src.size(), CV_32F );
-    dst = _dst.getMat();
+    _dst.create( src.size(), CV_32F);
+    Mat dst = _dst.getMat();
 
     if( need_labels )
     {
@@ -704,7 +720,6 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
         maskSize = CV_DIST_MASK_5;
     }
 
-    CV_Assert( src.type() == CV_8UC1 );
     float _mask[5] = {0};
 
     if( maskSize != CV_DIST_MASK_3 && maskSize != CV_DIST_MASK_5 && maskSize != CV_DIST_MASK_PRECISE )
@@ -717,6 +732,22 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
 
     if( maskSize == CV_DIST_MASK_PRECISE )
     {
+        //ipp version is slower than the parallel in OpenCV
+        /*#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
+        IppStatus status;
+        IppiSize roi = { src.cols, src.rows };
+        Ipp8u *pBuffer;
+        int bufSize=0;
+
+        status = ippiTrueDistanceTransformGetBufferSize_8u32f_C1R(roi, &bufSize);
+
+        pBuffer = ippsMalloc_8u( bufSize );
+        status = ippiTrueDistanceTransform_8u32f_C1R(src.ptr<uchar>(),(int)src.step, dst.ptr<float>(), (int)dst.step, roi, pBuffer);
+        ippsFree( pBuffer );
+        return;
+
+        #endif*/
+
         trueDistTrans( src, dst );
         return;
     }
@@ -734,9 +765,25 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
     if( !need_labels )
     {
         if( maskSize == CV_DIST_MASK_3 )
+        {
+            #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) && !defined HAVE_IPP_ICV_ONLY
+                IppiSize roi = { src.cols, src.rows };
+                if (ippiDistanceTransform_3x3_8u32f_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask)>=0)
+                    return;
+            #endif
+
             distanceTransform_3x3(src, temp, dst, _mask);
+        }
         else
+        {
+            #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
+            IppiSize roi = { src.cols, src.rows };
+                if (ippiDistanceTransform_5x5_8u32f_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask)>=0)
+                    return;
+            #endif
+
             distanceTransform_5x5(src, temp, dst, _mask);
+        }
     }
     else
     {
@@ -744,18 +791,7 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
 
         if( labelType == CV_DIST_LABEL_CCOMP )
         {
-        #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
-            if( maskSize == CV_DIST_MASK_5 )
-            {
-                IppiSize roi = { src.cols, src.rows };
-                if( ippiDistanceTransform_5x5_8u32f_C1R(
-                        src.ptr<uchar>(), (int)src.step,
-                        dst.ptr<float>(), (int)dst.step, roi, _mask) >= 0 )
-                    return;
-                setIppErrorStatus();
-            }
-        #endif
-            Mat zpix = src == 0;
+        #endif            Mat zpix = src == 0;
             connectedComponents(zpix, labels, 8, CV_32S);
         }
         else
@@ -772,17 +808,19 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
             }
         }
 
-        distanceTransformEx_5x5( src, temp, dst, labels, _mask );
+       distanceTransformEx_5x5( src, temp, dst, labels, _mask );
     }
 }
 
-
 void cv::distanceTransform( InputArray _src, OutputArray _dst,
-                            int distanceType, int maskSize )
+                            int distanceType, int maskSize, int dstType)
 {
-    distanceTransform(_src, _dst, noArray(), distanceType, maskSize, DIST_LABEL_PIXEL);
-}
+    if (distanceType == CV_DIST_L1 && dstType==CV_8U)
+        distanceTransform_L1_8U(_src, _dst);
+    else
+        distanceTransform(_src, _dst, noArray(), distanceType, maskSize, DIST_LABEL_PIXEL);
 
+}
 
 CV_IMPL void
 cvDistTransform( const void* srcarr, void* dstarr,