Commit 6823b369 authored by Andrey Pavlenko's avatar Andrey Pavlenko Committed by OpenCV Buildbot

Merge pull request #2624 from ElenaGvozdeva:ipp_DistanceTransform

parents 7c3d5b05 3d7872b9
...@@ -411,7 +411,7 @@ distanceTransform ...@@ -411,7 +411,7 @@ distanceTransform
----------------- -----------------
Calculates the distance to the closest zero pixel for each pixel of the source image. 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 ) .. 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 ...@@ -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 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 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 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 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. :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.
......
...@@ -1389,7 +1389,7 @@ CV_EXPORTS_AS(distanceTransformWithLabels) void distanceTransform( InputArray sr ...@@ -1389,7 +1389,7 @@ CV_EXPORTS_AS(distanceTransformWithLabels) void distanceTransform( InputArray sr
//! computes the distance transform map //! computes the distance transform map
CV_EXPORTS_W void distanceTransform( InputArray src, OutputArray dst, 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 //! fills the semi-uniform image region starting from the specified seed point
......
...@@ -21,3 +21,82 @@ PERF_TEST_P(Size_DistanceTransform, icvTrueDistTrans, testing::Values(TYPICAL_MA ...@@ -21,3 +21,82 @@ PERF_TEST_P(Size_DistanceTransform, icvTrueDistTrans, testing::Values(TYPICAL_MA
SANITY_CHECK(dst, 1); 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);
}
...@@ -488,7 +488,6 @@ struct DTColumnInvoker : ParallelLoopBody ...@@ -488,7 +488,6 @@ struct DTColumnInvoker : ParallelLoopBody
const float* sqr_tab; const float* sqr_tab;
}; };
struct DTRowInvoker : ParallelLoopBody struct DTRowInvoker : ParallelLoopBody
{ {
DTRowInvoker( Mat* _dst, const float* _sqr_tab, const float* _inv_tab ) DTRowInvoker( Mat* _dst, const float* _sqr_tab, const float* _inv_tab )
...@@ -669,7 +668,8 @@ distanceATS_L1_8u( const Mat& src, Mat& dst ) ...@@ -669,7 +668,8 @@ distanceATS_L1_8u( const Mat& src, Mat& dst )
{ {
int b = dbase[x+dststep]; int b = dbase[x+dststep];
a = lut[MIN(a, b)]; a = lut[MIN(a, b)];
dbase[x] = (uchar)(MIN(a, dbase[x])); a = MIN(a, dbase[x]);
dbase[x] = (uchar)(a);
} }
} }
} }
...@@ -677,23 +677,40 @@ distanceATS_L1_8u( const Mat& src, Mat& dst ) ...@@ -677,23 +677,40 @@ 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;
setIppErrorStatus();
#endif
distanceATS_L1_8u(src, dst);
}
}
// Wrapper function for distance transform group // Wrapper function for distance transform group
void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels, void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels,
int distType, int maskSize, int labelType ) int distType, int maskSize, int labelType )
{ {
Mat src = _src.getMat(), dst = _dst.getMat(), labels; Mat src = _src.getMat(), labels;
bool need_labels = _labels.needed(); bool need_labels = _labels.needed();
CV_Assert( src.type() == CV_8U ); CV_Assert( src.type() == CV_8UC1);
if( dst.size == src.size && dst.type() == CV_8U && !need_labels && distType == CV_DIST_L1 )
{
distanceATS_L1_8u(src, dst);
return;
}
_dst.create( src.size(), CV_32F ); _dst.create( src.size(), CV_32F);
dst = _dst.getMat(); Mat dst = _dst.getMat();
if( need_labels ) if( need_labels )
{ {
...@@ -704,7 +721,6 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe ...@@ -704,7 +721,6 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
maskSize = CV_DIST_MASK_5; maskSize = CV_DIST_MASK_5;
} }
CV_Assert( src.type() == CV_8UC1 );
float _mask[5] = {0}; 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_3 && maskSize != CV_DIST_MASK_5 && maskSize != CV_DIST_MASK_PRECISE )
...@@ -717,6 +733,28 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe ...@@ -717,6 +733,28 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
if( maskSize == CV_DIST_MASK_PRECISE ) if( maskSize == CV_DIST_MASK_PRECISE )
{ {
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
if ((currentParallelFramework()==NULL) || (src.total()<(int)(1<<14)))
{
IppStatus status;
IppiSize roi = { src.cols, src.rows };
Ipp8u *pBuffer;
int bufSize=0;
status = ippiTrueDistanceTransformGetBufferSize_8u32f_C1R(roi, &bufSize);
if (status>=0)
{
pBuffer = ippsMalloc_8u( bufSize );
status = ippiTrueDistanceTransform_8u32f_C1R(src.ptr<uchar>(),(int)src.step, dst.ptr<float>(), (int)dst.step, roi, pBuffer);
ippsFree( pBuffer );
if (status>=0)
return;
setIppErrorStatus();
}
}
#endif
trueDistTrans( src, dst ); trueDistTrans( src, dst );
return; return;
} }
...@@ -734,9 +772,27 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe ...@@ -734,9 +772,27 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
if( !need_labels ) if( !need_labels )
{ {
if( maskSize == CV_DIST_MASK_3 ) 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;
setIppErrorStatus();
#endif
distanceTransform_3x3(src, temp, dst, _mask); distanceTransform_3x3(src, temp, dst, _mask);
}
else 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;
setIppErrorStatus();
#endif
distanceTransform_5x5(src, temp, dst, _mask); distanceTransform_5x5(src, temp, dst, _mask);
}
} }
else else
{ {
...@@ -744,17 +800,6 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe ...@@ -744,17 +800,6 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
if( labelType == CV_DIST_LABEL_CCOMP ) 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; Mat zpix = src == 0;
connectedComponents(zpix, labels, 8, CV_32S); connectedComponents(zpix, labels, 8, CV_32S);
} }
...@@ -772,17 +817,19 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe ...@@ -772,17 +817,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, 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 CV_IMPL void
cvDistTransform( const void* srcarr, void* dstarr, cvDistTransform( const void* srcarr, void* dstarr,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment