added DIST_LABEL_PIXEL labelType to distanceTransform, ticket #1641 (thanks to Mikhail Matrosov for the patch)
This commit is contained in:
parent
f70d171cef
commit
e8fab91d51
@ -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
|
||||
|
||||
@ -429,6 +429,8 @@ Calculates the distance to the closest zero pixel for each pixel of the source i
|
||||
: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 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.
|
||||
@ -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;
|
||||
}*/
|
||||
CvSize size = cvGetMatSize(src);
|
||||
|
||||
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;
|
||||
|
||||
st = cvCreateMemStorage();
|
||||
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++ )
|
||||
|
||||
if( labelType == CV_DIST_LABEL_CCOMP )
|
||||
{
|
||||
CvScalar area_color = cvScalarAll(label);
|
||||
cvDrawContours( labels, contours, area_color, area_color, -255, -1, 8 );
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
for( int j = 0; j < src->cols; j++ )
|
||||
if( srcptr[j] == 0 )
|
||||
labelptr[j] = k++;
|
||||
}
|
||||
}
|
||||
|
||||
//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 );
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user