Commit e8fab91d authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

added DIST_LABEL_PIXEL labelType to distanceTransform, ticket #1641 (thanks to…

added DIST_LABEL_PIXEL labelType to distanceTransform, ticket #1641 (thanks to Mikhail Matrosov for the patch)
parent f70d171c
...@@ -412,11 +412,11 @@ Calculates the distance to the closest zero pixel for each pixel of the source i ...@@ -412,11 +412,11 @@ Calculates the distance to the closest zero pixel for each pixel of the source i
.. ocv:function:: void distanceTransform( InputArray src, OutputArray dst, int distanceType, int maskSize ) .. ocv:function:: void distanceTransform( InputArray src, OutputArray dst, int distanceType, int maskSize )
.. ocv:function:: void distanceTransform( InputArray src, OutputArray dst, OutputArray labels, int distanceType, int maskSize ) .. ocv:function:: void distanceTransform( InputArray src, OutputArray dst, OutputArray labels, int distanceType, int maskSize, int labelType=DIST_LABEL_CCOMP )
.. ocv:pyfunction:: cv2.distanceTransform(src, distanceType, maskSize[, dst[, labels]]) -> dst, labels .. ocv:pyfunction:: cv2.distanceTransform(src, distanceType, maskSize[, dst[, labels[, labelType=cv2.DIST_LABEL_CCOMP]]]) -> dst, labels
.. ocv:cfunction:: void cvDistTransform( const CvArr* src, CvArr* dst, int distanceType=CV_DIST_L2, int maskSize=3, const float* mask=NULL, CvArr* labels=NULL ) .. ocv:cfunction:: void cvDistTransform( const CvArr* src, CvArr* dst, int distanceType=CV_DIST_L2, int maskSize=3, const float* mask=NULL, CvArr* labels=NULL, int labelType=CV_DIST_LABEL_CCOMP )
.. ocv:pyoldfunction:: cv.DistTransform(src, dst, distanceType=CV_DIST_L2, maskSize=3, mask=None, labels=None)-> None .. ocv:pyoldfunction:: cv.DistTransform(src, dst, distanceType=CV_DIST_L2, maskSize=3, mask=None, labels=None)-> None
...@@ -430,6 +430,8 @@ Calculates the distance to the closest zero pixel for each pixel of the source i ...@@ -430,6 +430,8 @@ Calculates the distance to the closest zero pixel for each pixel of the source i
: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.
The functions ``distanceTransform`` calculate the approximate or precise The functions ``distanceTransform`` calculate the approximate or precise
distance from every binary image pixel to the nearest zero pixel. distance from every binary image pixel to the nearest zero pixel.
For zero image pixels, the distance will obviously be zero. For zero image pixels, the distance will obviously be zero.
...@@ -469,17 +471,13 @@ Note that both the precise and the approximate algorithms are linear on the numb ...@@ -469,17 +471,13 @@ Note that both the precise and the approximate algorithms are linear on the numb
The second variant of the function does not only compute the minimum distance for each pixel The second variant of the function does not only compute the minimum distance for each pixel
:math:`(x, y)` but also identifies the nearest connected :math:`(x, y)` but also identifies the nearest connected
component consisting of zero pixels. Index of the component is stored in component consisting of zero pixels (``labelType==DIST_LABEL_CCOMP``) or the nearest zero pixel (``labelType==DIST_LABEL_PIXEL``). Index of the component/pixel is stored in
:math:`\texttt{labels}(x, y)` . :math:`\texttt{labels}(x, y)` .
The connected components of zero pixels are also found and marked by the function. When ``labelType==DIST_LABEL_CCOMP``, the function automatically finds connected components of zero pixels in the input image and marks them with distinct labels. When ``labelType==DIST_LABEL_CCOMP``, the function scans through the input image and marks all the zero pixels with distinct labels.
In this mode, the complexity is still linear. In this mode, the complexity is still linear.
That is, the function provides a very fast way to compute the Voronoi diagram for a binary image. That is, the function provides a very fast way to compute the Voronoi diagram for a binary image.
Currently, the second variant can use only the approximate distance transform algorithm. Currently, the second variant can use only the approximate distance transform algorithm, i.e. ``maskSize=CV_DIST_MASK_PRECISE`` is not supported yet.
floodFill floodFill
------------- -------------
......
...@@ -751,9 +751,16 @@ CV_EXPORTS_W void grabCut( InputArray img, InputOutputArray mask, Rect rect, ...@@ -751,9 +751,16 @@ CV_EXPORTS_W void grabCut( InputArray img, InputOutputArray mask, Rect rect,
InputOutputArray bgdModel, InputOutputArray fgdModel, InputOutputArray bgdModel, InputOutputArray fgdModel,
int iterCount, int mode = GC_EVAL ); int iterCount, int mode = GC_EVAL );
enum
{
DIST_LABEL_CCOMP = 0,
DIST_LABEL_PIXEL = 1
};
//! builds the discrete Voronoi diagram //! builds the discrete Voronoi diagram
CV_EXPORTS_AS(distanceTransformWithLabels) void distanceTransform( InputArray src, OutputArray dst, CV_EXPORTS_AS(distanceTransformWithLabels) void distanceTransform( InputArray src, OutputArray dst,
OutputArray labels, int distanceType, int maskSize ); OutputArray labels, int distanceType, int maskSize,
int labelType=DIST_LABEL_CCOMP );
//! 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,
......
...@@ -620,7 +620,8 @@ CVAPI(void) cvDistTransform( const CvArr* src, CvArr* dst, ...@@ -620,7 +620,8 @@ CVAPI(void) cvDistTransform( const CvArr* src, CvArr* dst,
int distance_type CV_DEFAULT(CV_DIST_L2), int distance_type CV_DEFAULT(CV_DIST_L2),
int mask_size CV_DEFAULT(3), int mask_size CV_DEFAULT(3),
const float* mask CV_DEFAULT(NULL), const float* mask CV_DEFAULT(NULL),
CvArr* labels CV_DEFAULT(NULL)); CvArr* labels CV_DEFAULT(NULL),
int labelType CV_DEFAULT(CV_DIST_LABEL_CCOMP));
/* Applies fixed-level threshold to grayscale image. /* Applies fixed-level threshold to grayscale image.
......
...@@ -470,6 +470,13 @@ enum ...@@ -470,6 +470,13 @@ enum
CV_DIST_MASK_PRECISE =0 CV_DIST_MASK_PRECISE =0
}; };
/* Content of output label array: connected components or pixels */
enum
{
CV_DIST_LABEL_CCOMP = 0,
CV_DIST_LABEL_PIXEL = 1
};
/* Distance types for Distance Transform and M-estimators */ /* Distance types for Distance Transform and M-estimators */
enum enum
{ {
......
...@@ -706,19 +706,12 @@ CV_IMPL void ...@@ -706,19 +706,12 @@ CV_IMPL void
cvDistTransform( const void* srcarr, void* dstarr, cvDistTransform( const void* srcarr, void* dstarr,
int distType, int maskSize, int distType, int maskSize,
const float *mask, const float *mask,
void* labelsarr ) void* labelsarr, int labelType )
{ {
cv::Ptr<CvMat> temp;
cv::Ptr<CvMat> src_copy;
cv::Ptr<CvMemStorage> st;
float _mask[5] = {0}; float _mask[5] = {0};
CvMat srcstub, *src = (CvMat*)srcarr; CvMat srcstub, *src = (CvMat*)srcarr;
CvMat dststub, *dst = (CvMat*)dstarr; CvMat dststub, *dst = (CvMat*)dstarr;
CvMat lstub, *labels = (CvMat*)labelsarr; CvMat lstub, *labels = (CvMat*)labelsarr;
CvSize size;
//CvIPPDistTransFunc ipp_func = 0;
//CvIPPDistTransFunc2 ipp_inp_func = 0;
src = cvGetMat( src, &srcstub ); src = cvGetMat( src, &srcstub );
dst = cvGetMat( dst, &dststub ); dst = cvGetMat( dst, &dststub );
...@@ -773,46 +766,16 @@ cvDistTransform( const void* srcarr, void* dstarr, ...@@ -773,46 +766,16 @@ cvDistTransform( const void* srcarr, void* dstarr,
memcpy( _mask, mask, (maskSize/2 + 1)*sizeof(float)); memcpy( _mask, mask, (maskSize/2 + 1)*sizeof(float));
} }
/*if( !labels ) CvSize size = cvGetMatSize(src);
{
if( CV_MAT_TYPE(dst->type) == CV_32FC1 )
ipp_func = (CvIPPDistTransFunc)(maskSize == CV_DIST_MASK_3 ?
icvDistanceTransform_3x3_8u32f_C1R_p : icvDistanceTransform_5x5_8u32f_C1R_p);
else if( src->data.ptr != dst->data.ptr )
ipp_func = (CvIPPDistTransFunc)icvDistanceTransform_3x3_8u_C1R_p;
else
ipp_inp_func = icvDistanceTransform_3x3_8u_C1IR_p;
}*/
size = cvGetMatSize(src);
/*if( (ipp_func || ipp_inp_func) && src->cols >= 4 && src->rows >= 2 ) if( CV_MAT_TYPE(dst->type) == CV_8UC1 )
{
int _imask[3];
_imask[0] = cvRound(_mask[0]);
_imask[1] = cvRound(_mask[1]);
_imask[2] = cvRound(_mask[2]);
if( ipp_func )
{
IPPI_CALL( ipp_func( src->data.ptr, src->step,
dst->data.fl, dst->step, size,
CV_MAT_TYPE(dst->type) == CV_8UC1 ?
(void*)_imask : (void*)_mask ));
}
else
{
IPPI_CALL( ipp_inp_func( src->data.ptr, src->step, size, _imask ));
}
}
else*/ if( CV_MAT_TYPE(dst->type) == CV_8UC1 )
{ {
icvDistanceATS_L1_8u( src, dst ); icvDistanceATS_L1_8u( src, dst );
} }
else else
{ {
int border = maskSize == CV_DIST_MASK_3 ? 1 : 2; int border = maskSize == CV_DIST_MASK_3 ? 1 : 2;
temp = cvCreateMat( size.height + border*2, size.width + border*2, CV_32SC1 ); cv::Ptr<CvMat> temp = cvCreateMat( size.height + border*2, size.width + border*2, CV_32SC1 );
if( !labels ) if( !labels )
{ {
...@@ -825,25 +788,37 @@ cvDistTransform( const void* srcarr, void* dstarr, ...@@ -825,25 +788,37 @@ cvDistTransform( const void* srcarr, void* dstarr,
} }
else else
{ {
CvSeq *contours = 0; cvZero( labels );
int label;
st = cvCreateMemStorage(); if( labelType == CV_DIST_LABEL_CCOMP )
src_copy = cvCreateMat( size.height+border*2, size.width+border*2, src->type ); {
CvSeq *contours = 0;
cv::Ptr<CvMemStorage> st = cvCreateMemStorage();
cv::Ptr<CvMat> src_copy = cvCreateMat( size.height+border*2, size.width+border*2, src->type );
cvCopyMakeBorder(src, src_copy, cvPoint(border, border), IPL_BORDER_CONSTANT, cvScalarAll(255)); cvCopyMakeBorder(src, src_copy, cvPoint(border, border), IPL_BORDER_CONSTANT, cvScalarAll(255));
cvCmpS( src_copy, 0, src_copy, CV_CMP_EQ ); cvCmpS( src_copy, 0, src_copy, CV_CMP_EQ );
cvFindContours( src_copy, st, &contours, sizeof(CvContour), cvFindContours( src_copy, st, &contours, sizeof(CvContour),
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(-border, -border)); CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(-border, -border));
cvZero( labels );
for( label = 1; contours != 0; contours = contours->h_next, label++ ) for( int label = 1; contours != 0; contours = contours->h_next, label++ )
{ {
CvScalar area_color = cvScalarAll(label); CvScalar area_color = cvScalarAll(label);
cvDrawContours( labels, contours, area_color, area_color, -255, -1, 8 ); cvDrawContours( labels, contours, area_color, area_color, -255, -1, 8 );
} }
}
else
{
int k = 1;
for( int i = 0; i < src->rows; i++ )
{
const uchar* srcptr = src->data.ptr + src->step*i;
int* labelptr = (int*)(labels->data.ptr + labels->step*i);
//cvCopy( src, src_copy ); for( int j = 0; j < src->cols; j++ )
//CvPoint top_left = {0,0}, bottom_right = {size.width-1,size.height-1}; if( srcptr[j] == 0 )
//cvRectangle( src_copy, top_left, bottom_right, cvScalarAll(255), 1, 8 ); labelptr[j] = k++;
}
}
icvDistanceTransformEx_5x5_C1R( src->data.ptr, src->step, temp->data.i, temp->step, icvDistanceTransformEx_5x5_C1R( src->data.ptr, src->step, temp->data.i, temp->step,
dst->data.fl, dst->step, labels->data.i, labels->step, size, _mask ); dst->data.fl, dst->step, labels->data.i, labels->step, size, _mask );
...@@ -852,13 +827,13 @@ cvDistTransform( const void* srcarr, void* dstarr, ...@@ -852,13 +827,13 @@ cvDistTransform( const void* srcarr, void* dstarr,
} }
void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels, void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels,
int distanceType, int maskSize ) int distanceType, int maskSize, int labelType )
{ {
Mat src = _src.getMat(); Mat src = _src.getMat();
_dst.create(src.size(), CV_32F); _dst.create(src.size(), CV_32F);
_labels.create(src.size(), CV_32S); _labels.create(src.size(), CV_32S);
CvMat c_src = src, c_dst = _dst.getMat(), c_labels = _labels.getMat(); CvMat c_src = src, c_dst = _dst.getMat(), c_labels = _labels.getMat();
cvDistTransform(&c_src, &c_dst, distanceType, maskSize, 0, &c_labels); cvDistTransform(&c_src, &c_dst, distanceType, maskSize, 0, &c_labels, labelType);
} }
void cv::distanceTransform( InputArray _src, OutputArray _dst, void cv::distanceTransform( InputArray _src, OutputArray _dst,
...@@ -868,7 +843,7 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, ...@@ -868,7 +843,7 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst,
_dst.create(src.size(), CV_32F); _dst.create(src.size(), CV_32F);
Mat dst = _dst.getMat(); Mat dst = _dst.getMat();
CvMat c_src = src, c_dst = _dst.getMat(); CvMat c_src = src, c_dst = _dst.getMat();
cvDistTransform(&c_src, &c_dst, distanceType, maskSize, 0, 0); cvDistTransform(&c_src, &c_dst, distanceType, maskSize, 0, 0, -1);
} }
/* End of file. */ /* End of file. */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
using namespace cv; using namespace cv;
int maskSize0 = CV_DIST_MASK_5; int maskSize0 = CV_DIST_MASK_5;
bool buildVoronoi = false; int voronoiType = -1;
int edgeThresh = 100; int edgeThresh = 100;
int distType0 = CV_DIST_L1; int distType0 = CV_DIST_L1;
...@@ -29,17 +29,17 @@ void onTrackbar( int, void* ) ...@@ -29,17 +29,17 @@ void onTrackbar( int, void* )
Scalar(255,0,255) Scalar(255,0,255)
}; };
int maskSize = buildVoronoi ? CV_DIST_MASK_5 : maskSize0; int maskSize = voronoiType >= 0 ? CV_DIST_MASK_5 : maskSize0;
int distType = buildVoronoi ? CV_DIST_L2 : distType0; int distType = voronoiType >= 0 ? CV_DIST_L2 : distType0;
Mat edge = gray >= edgeThresh, dist, labels, dist8u; Mat edge = gray >= edgeThresh, dist, labels, dist8u;
if( !buildVoronoi ) if( voronoiType < 0 )
distanceTransform( edge, dist, distType, maskSize ); distanceTransform( edge, dist, distType, maskSize );
else else
distanceTransform( edge, dist, labels, distType, maskSize ); distanceTransform( edge, dist, labels, distType, maskSize, voronoiType );
if( !buildVoronoi ) if( voronoiType < 0 )
{ {
// begin "painting" the distance transform result // begin "painting" the distance transform result
dist *= 5000; dist *= 5000;
...@@ -70,9 +70,10 @@ void onTrackbar( int, void* ) ...@@ -70,9 +70,10 @@ void onTrackbar( int, void* )
for( int j = 0; j < labels.cols; j++ ) for( int j = 0; j < labels.cols; j++ )
{ {
int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1; int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1;
int b = cvRound(colors[idx][0]); float scale = 1.f/(1 + dd[j]*dd[j]*0.0004f);
int g = cvRound(colors[idx][1]); int b = cvRound(colors[idx][0]*scale);
int r = cvRound(colors[idx][2]); int g = cvRound(colors[idx][1]*scale);
int r = cvRound(colors[idx][2]*scale);
d[j*3] = (uchar)b; d[j*3] = (uchar)b;
d[j*3+1] = (uchar)g; d[j*3+1] = (uchar)g;
d[j*3+2] = (uchar)r; d[j*3+2] = (uchar)r;
...@@ -96,7 +97,8 @@ void help() ...@@ -96,7 +97,8 @@ void help()
"\t3 - use 3x3 mask\n" "\t3 - use 3x3 mask\n"
"\t5 - use 5x5 mask\n" "\t5 - use 5x5 mask\n"
"\t0 - use precise distance transform\n" "\t0 - use precise distance transform\n"
"\tv - switch Voronoi diagram mode on/off\n" "\tv - switch to Voronoi diagram mode\n"
"\tp - switch to pixel-based Voronoi diagram mode\n"
"\tSPACE - loop through all the modes\n\n"); "\tSPACE - loop through all the modes\n\n");
} }
...@@ -126,30 +128,38 @@ int main( int argc, const char** argv ) ...@@ -126,30 +128,38 @@ int main( int argc, const char** argv )
// Call to update the view // Call to update the view
onTrackbar(0, 0); onTrackbar(0, 0);
int c = cvWaitKey(0); int c = cvWaitKey(0) & 255;
if( (char)c == 27 ) if( c == 27 )
break; break;
if( (char)c == 'c' || (char)c == 'C' ) if( c == 'c' || c == 'C' || c == '1' || c == '2' ||
c == '3' || c == '5' || c == '0' )
voronoiType = -1;
if( c == 'c' || c == 'C' )
distType0 = CV_DIST_C; distType0 = CV_DIST_C;
else if( (char)c == '1' ) else if( c == '1' )
distType0 = CV_DIST_L1; distType0 = CV_DIST_L1;
else if( (char)c == '2' ) else if( c == '2' )
distType0 = CV_DIST_L2; distType0 = CV_DIST_L2;
else if( (char)c == '3' ) else if( c == '3' )
maskSize0 = CV_DIST_MASK_3; maskSize0 = CV_DIST_MASK_3;
else if( (char)c == '5' ) else if( c == '5' )
maskSize0 = CV_DIST_MASK_5; maskSize0 = CV_DIST_MASK_5;
else if( (char)c == '0' ) else if( c == '0' )
maskSize0 = CV_DIST_MASK_PRECISE; maskSize0 = CV_DIST_MASK_PRECISE;
else if( (char)c == 'v' ) else if( c == 'v' )
buildVoronoi = !buildVoronoi; voronoiType = 0;
else if( (char)c == ' ' ) else if( c == 'p' )
voronoiType = 1;
else if( c == ' ' )
{ {
if( buildVoronoi ) if( voronoiType == 0 )
voronoiType = 1;
else if( voronoiType == 1 )
{ {
buildVoronoi = false; voronoiType = -1;
maskSize0 = CV_DIST_MASK_3; maskSize0 = CV_DIST_MASK_3;
distType0 = CV_DIST_C; distType0 = CV_DIST_C;
} }
...@@ -162,7 +172,7 @@ int main( int argc, const char** argv ) ...@@ -162,7 +172,7 @@ int main( int argc, const char** argv )
else if( maskSize0 == CV_DIST_MASK_5 ) else if( maskSize0 == CV_DIST_MASK_5 )
maskSize0 = CV_DIST_MASK_PRECISE; maskSize0 = CV_DIST_MASK_PRECISE;
else if( maskSize0 == CV_DIST_MASK_PRECISE ) else if( maskSize0 == CV_DIST_MASK_PRECISE )
buildVoronoi = true; voronoiType = 0;
} }
} }
......
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