If you wish, you can check the code below. It's a new version of DT with OpenCV C++ API
//#define CV_NO_BACKWARD_COMPATIBILITY
// if you compile the program under Windows and MSVC2008/2005
#if defined WIN32 || defined _MSC_VER
#pragma warning(disable:4786)
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#define _SCL_SECURE_NO_WARNINGS
#endif
#include <iostream>
#include "cv.h"
#include "cvaux.h"
#include "highgui.h"
#define DEMO_MIXED_API_USE 1
using namespace cv;
using namespace std;
char wndname[] = "Distance transform";
char tbarname[] = "Threshold";
int mask_size = CV_DIST_MASK_5;
int build_voronoi = 0;
int edge_thresh = 100;
int dist_type = CV_DIST_L1;
// The output and temporary images
Mat dist;
Mat dist8u1;
Mat dist8u2;
Mat dist8u;
Mat dist32s;
Mat gray;
Mat edge;
Mat labels;
// threshold trackbar callback
void on_trackbar( int dummy, void *)
{
static const uchar colors[][3] =
{
{0,0,0},
{255,0,0},
{255,128,0},
{255,255,0},
{0,255,0},
{0,128,255},
{0,255,255},
{0,0,255},
{255,0,255}
};
int msize = mask_size;
int _dist_type = build_voronoi ? CV_DIST_L2 : dist_type;
threshold( gray, edge, (double)edge_thresh, (double)edge_thresh, CV_THRESH_BINARY );
if( build_voronoi )
msize = CV_DIST_MASK_5;
if( _dist_type == CV_DIST_L1 )
{
distanceTransform( edge, dist, _dist_type, msize );
}
else
{
build_voronoi ? distanceTransform( edge, dist, labels, _dist_type, msize ) : distanceTransform( edge, dist, _dist_type, msize ) ;
}
if( !build_voronoi )
{
// begin "painting" the distance transform result
dist.convertTo( dist, dist.type(), 5000.0, 0 ); //before--> cvConvertScale( dist, dist, 5000.0, 0 );
pow( dist, 0.5, dist ); //before--> cvPow(dist, dist, 0.5);
dist.convertTo( dist32s, dist32s.type(), 1.0, 0.5 ); //before--> cvConvertScale( dist, dist32s, 1.0, 0.5 );
bitwise_and( dist32s, Scalar::all(255), dist32s, Mat() ); //before--> cvAndS( dist32s, ScalarAll(255), dist32s, 0 );
dist32s.convertTo(dist8u1, dist8u1.type(), 1, 0 ); //before--> cvConvertScale( dist32s, dist8u1, 1, 0 );
dist32s.convertTo( dist32s, dist32s.type(), -1, 0 ); //before--> cvConvertScale( dist32s, dist32s, -1, 0 );
add( dist32s, Scalar::all(255), dist32s, Mat() ); //before--> cvAddS( dist32s, cvScalarAll(255), dist32s, 0 );
dist32s.convertTo( dist8u2, dist8u2.type(), 1, 0 ); //before--> cvConvertScale( dist32s, dist8u2, 1, 0 );
vector<Mat> Out(3);
Out[0] = dist8u1;
Out[1] = dist8u2;
Out[2] = dist8u2;
merge( Out, dist8u ); //before--> cvMerge( dist8u1, dist8u2, dist8u2, 0, dist8u );
// end "painting" the distance transform result
}
else
{
int i, j;
for( i = 0; i < labels.rows; i++ )
{
int* ll = labels.ptr<int>(i); //before--> (int*)(labels->imageData + i*labels->widthStep)
float* dd = dist.ptr<float>(i); //before--> (float*)(dist->imageData + i*dist->widthStep)
uchar* d = dist8u.ptr<uchar>(i); //before--> (uchar*)(dist8u->imageData + i*dist8u->widthStep)
for( 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]); // if there is an option to cvRound in the new OpenCV C++ API, tell me please
int g = cvRound(colors[idx][1]);
int r = cvRound(colors[idx][2]);
d[j*3] = saturate_cast<uchar>(b); //before--> (uchar)b;
d[j*3+1] = saturate_cast<uchar>(g); //before--> (uchar)g;
d[j*3+2] = saturate_cast<uchar>(r); //before--> (uchar)r;
}
}
}
imshow( wndname, dist8u ); //before--> cvShowImage( wndname, dist8u );
}
int main( int argc, char* argv[] )
{
const char* filename = (argc == 2 ? argv[1] : "Debug/stuff.jpg");//lena.jpg
gray = imread( filename, 0 ); // -1 loads image full(3 channels + alpha) , 0 only in grayscale
if( gray.empty() )
return -1;
cout << "Hot keys: \n"
<< "\tESC - quit the program\n"
<< "\tC - use C/Inf metric\n"
<< "\tL1 - use L1 metric\n"
<< "\tL2 - use L2 metric\n"
<< "\t3 - use 3x3 mask\n"
<< "\t5 - use 5x5 mask\n"
<< "\t0 - use precise distance transform\n"
<< "\tv - switch Voronoi diagram mode on/off\n"
<< "\tSPACE - loop through all the modes\n" << endl;
dist = Mat( gray.size(), CV_32FC1 ); //dist = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32F, 1 );
dist8u1 = gray.clone(); //dist8u1 = cvCloneImage( gray );
dist8u2 = gray.clone(); //dist8u2 = cvCloneImage( gray );
dist8u = Mat( gray.size(), CV_8UC3 ); //dist8u = cvCreateImage( cvGetSize(gray), IPL_DEPTH_8U, 3 );
dist32s = Mat( gray.size(), CV_32SC1 ); //dist32s = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 );
edge = gray.clone(); //edge = cvCloneImage( gray );
labels = Mat( gray.size(), CV_32SC1 ); //labels = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 );
namedWindow( wndname, 1 );
createTrackbar( tbarname, wndname, &edge_thresh, 255, on_trackbar );
for(;;)
{
int c;
// Call to update the view
on_trackbar(0, 0);
c = waitKey(0);
if( (char)c == 27 )
break;
if( (char)c == 'c' || (char)c == 'C' )
dist_type = CV_DIST_C;
else if( (char)c == '1' )
dist_type = CV_DIST_L1;
else if( (char)c == '2' )
dist_type = CV_DIST_L2;
else if( (char)c == '3' )
mask_size = CV_DIST_MASK_3;
else if( (char)c == '5' )
mask_size = CV_DIST_MASK_5;
else if( (char)c == '0' )
mask_size = CV_DIST_MASK_PRECISE;
else if( (char)c == 'v' )
build_voronoi ^= 1;
else if( (char)c == ' ' )
{
if( build_voronoi )
{
build_voronoi = 0;
mask_size = CV_DIST_MASK_3;
dist_type = CV_DIST_C;
}
else if( dist_type == CV_DIST_C )
dist_type = CV_DIST_L1;
else if( dist_type == CV_DIST_L1 )
dist_type = CV_DIST_L2;
else if( mask_size == CV_DIST_MASK_3 )
mask_size = CV_DIST_MASK_5;
else if( mask_size == CV_DIST_MASK_5 )
mask_size = CV_DIST_MASK_PRECISE;
else if( mask_size == CV_DIST_MASK_PRECISE )
build_voronoi = 1;
}
}
return 0;
}