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
.. 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
......@@ -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 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
distance from every binary image pixel to the nearest zero pixel.
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
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
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)` .
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.
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
-------------
......
......@@ -751,9 +751,16 @@ CV_EXPORTS_W void grabCut( InputArray img, InputOutputArray mask, Rect rect,
InputOutputArray bgdModel, InputOutputArray fgdModel,
int iterCount, int mode = GC_EVAL );
enum
{
DIST_LABEL_CCOMP = 0,
DIST_LABEL_PIXEL = 1
};
//! builds the discrete Voronoi diagram
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
CV_EXPORTS_W void distanceTransform( InputArray src, OutputArray dst,
......
......@@ -620,7 +620,8 @@ CVAPI(void) cvDistTransform( const CvArr* src, CvArr* dst,
int distance_type CV_DEFAULT(CV_DIST_L2),
int mask_size CV_DEFAULT(3),
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.
......
......@@ -470,6 +470,13 @@ enum
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 */
enum
{
......
......@@ -706,19 +706,12 @@ CV_IMPL void
cvDistTransform( const void* srcarr, void* dstarr,
int distType, int maskSize,
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};
CvMat srcstub, *src = (CvMat*)srcarr;
CvMat dststub, *dst = (CvMat*)dstarr;
CvMat lstub, *labels = (CvMat*)labelsarr;
CvSize size;
//CvIPPDistTransFunc ipp_func = 0;
//CvIPPDistTransFunc2 ipp_inp_func = 0;
src = cvGetMat( src, &srcstub );
dst = cvGetMat( dst, &dststub );
......@@ -773,46 +766,16 @@ cvDistTransform( const void* srcarr, void* dstarr,
memcpy( _mask, mask, (maskSize/2 + 1)*sizeof(float));
}
/*if( !labels )
{
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);
CvSize size = cvGetMatSize(src);
/*if( (ipp_func || ipp_inp_func) && src->cols >= 4 && src->rows >= 2 )
{
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 )
if( CV_MAT_TYPE(dst->type) == CV_8UC1 )
{
icvDistanceATS_L1_8u( src, dst );
}
else
{
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 )
{
......@@ -825,25 +788,37 @@ cvDistTransform( const void* srcarr, void* dstarr,
}
else
{
CvSeq *contours = 0;
int label;
cvZero( labels );
st = cvCreateMemStorage();
src_copy = cvCreateMat( size.height+border*2, size.width+border*2, src->type );
if( labelType == CV_DIST_LABEL_CCOMP )
{
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));
cvCmpS( src_copy, 0, src_copy, CV_CMP_EQ );
cvFindContours( src_copy, st, &contours, sizeof(CvContour),
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);
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 );
//CvPoint top_left = {0,0}, bottom_right = {size.width-1,size.height-1};
//cvRectangle( src_copy, top_left, bottom_right, cvScalarAll(255), 1, 8 );
for( int j = 0; j < src->cols; j++ )
if( srcptr[j] == 0 )
labelptr[j] = k++;
}
}
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 );
......@@ -852,13 +827,13 @@ cvDistTransform( const void* srcarr, void* dstarr,
}
void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels,
int distanceType, int maskSize )
int distanceType, int maskSize, int labelType )
{
Mat src = _src.getMat();
_dst.create(src.size(), CV_32F);
_labels.create(src.size(), CV_32S);
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,
......@@ -868,7 +843,7 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst,
_dst.create(src.size(), CV_32F);
Mat 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. */
......@@ -6,7 +6,7 @@
using namespace cv;
int maskSize0 = CV_DIST_MASK_5;
bool buildVoronoi = false;
int voronoiType = -1;
int edgeThresh = 100;
int distType0 = CV_DIST_L1;
......@@ -29,17 +29,17 @@ void onTrackbar( int, void* )
Scalar(255,0,255)
};
int maskSize = buildVoronoi ? CV_DIST_MASK_5 : maskSize0;
int distType = buildVoronoi ? CV_DIST_L2 : distType0;
int maskSize = voronoiType >= 0 ? CV_DIST_MASK_5 : maskSize0;
int distType = voronoiType >= 0 ? CV_DIST_L2 : distType0;
Mat edge = gray >= edgeThresh, dist, labels, dist8u;
if( !buildVoronoi )
if( voronoiType < 0 )
distanceTransform( edge, dist, distType, maskSize );
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
dist *= 5000;
......@@ -70,9 +70,10 @@ void onTrackbar( int, void* )
for( int j = 0; j < labels.cols; j++ )
{
int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1;
int b = cvRound(colors[idx][0]);
int g = cvRound(colors[idx][1]);
int r = cvRound(colors[idx][2]);
float scale = 1.f/(1 + dd[j]*dd[j]*0.0004f);
int b = cvRound(colors[idx][0]*scale);
int g = cvRound(colors[idx][1]*scale);
int r = cvRound(colors[idx][2]*scale);
d[j*3] = (uchar)b;
d[j*3+1] = (uchar)g;
d[j*3+2] = (uchar)r;
......@@ -96,7 +97,8 @@ void help()
"\t3 - use 3x3 mask\n"
"\t5 - use 5x5 mask\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");
}
......@@ -126,30 +128,38 @@ int main( int argc, const char** argv )
// Call to update the view
onTrackbar(0, 0);
int c = cvWaitKey(0);
int c = cvWaitKey(0) & 255;
if( (char)c == 27 )
if( c == 27 )
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;
else if( (char)c == '1' )
else if( c == '1' )
distType0 = CV_DIST_L1;
else if( (char)c == '2' )
else if( c == '2' )
distType0 = CV_DIST_L2;
else if( (char)c == '3' )
else if( c == '3' )
maskSize0 = CV_DIST_MASK_3;
else if( (char)c == '5' )
else if( c == '5' )
maskSize0 = CV_DIST_MASK_5;
else if( (char)c == '0' )
else if( c == '0' )
maskSize0 = CV_DIST_MASK_PRECISE;
else if( (char)c == 'v' )
buildVoronoi = !buildVoronoi;
else if( (char)c == ' ' )
else if( c == 'v' )
voronoiType = 0;
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;
distType0 = CV_DIST_C;
}
......@@ -162,7 +172,7 @@ int main( int argc, const char** argv )
else if( maskSize0 == CV_DIST_MASK_5 )
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