-----------------
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 )
: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.
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);
+}
const float* sqr_tab;
};
-
struct DTRowInvoker : ParallelLoopBody
{
DTRowInvoker( Mat* _dst, const float* _sqr_tab, const float* _inv_tab )
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;
{
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);
}
}
}
}
+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 )
{
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 )
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;
}
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
{
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
}
}
- 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,