distrans.cpp 4.48 KB
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <stdio.h>

using namespace cv;

void help()
{
	printf("\nProgram to demonstrate the use of the distance transform function between edge images.\n"
			"Usage:\n"
			"./distrans [image_name -- default image is stuff.jpg]\n"
			);
    printf( "\nHot 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" );
}

int maskSize0 = CV_DIST_MASK_5;
bool buildVoronoi = false;
int edgeThresh = 100;
int distType0 = CV_DIST_L1;

// The output and temporary images
Mat gray;

// threshold trackbar callback
void onTrackbar( int, void* )
{
    static const Scalar colors[] =
    {
        Scalar(0,0,0),
        Scalar(255,0,0),
        Scalar(255,128,0),
        Scalar(255,255,0),
        Scalar(0,255,0),
        Scalar(0,128,255),
        Scalar(0,255,255),
        Scalar(0,0,255),
        Scalar(255,0,255)
    };

    int maskSize = buildVoronoi ? CV_DIST_MASK_5 : maskSize0;
    int distType = buildVoronoi ? CV_DIST_L2 : distType0;

    Mat edge = gray >= edgeThresh, dist, labels, dist8u;

    if( !buildVoronoi )
        distanceTransform( edge, dist, distType, maskSize );
    else
        distanceTransform( edge, dist, labels, distType, maskSize );

    if( !buildVoronoi )
    {
        // begin "painting" the distance transform result
        dist *= 5000;
        pow(dist, 0.5, dist);
        
        Mat dist32s, dist8u1, dist8u2;
        
        dist.convertTo(dist32s, CV_32S, 1, 0.5);
        dist32s &= Scalar::all(255);
        
        dist32s.convertTo(dist8u1, CV_8U, 1, 0);
        dist32s *= -1;
        
        dist32s += Scalar::all(255);
        dist32s.convertTo(dist8u2, CV_8U);
        
        Mat planes[] = {dist8u1, dist8u2, dist8u2};
        merge(planes, 3, dist8u); 
    }
    else
    {
        dist8u.create(labels.size(), CV_8UC3);
        for( int i = 0; i < labels.rows; i++ )
        {
            const int* ll = (const int*)labels.ptr(i);
            const float* dd = (const float*)dist.ptr(i);
            uchar* d = (uchar*)dist8u.ptr(i);
            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]);
                d[j*3] = (uchar)b;
                d[j*3+1] = (uchar)g;
                d[j*3+2] = (uchar)r;
            }
        }
    }

    imshow("Distance Map", dist8u );
}

int main( int argc, char** argv )
{
    char* filename = argc == 2 ? argv[1] : (char*)"stuff.jpg";
    gray = imread(filename, 0);
    if(gray.empty())
    {
    	help();
    	return -1;
    }

    help();
    namedWindow("Distance Map", 1);
    createTrackbar("Brightness Threshold", "Distance Map", &edgeThresh, 255, onTrackbar, 0);

    for(;;)
    {
        // Call to update the view
        onTrackbar(0, 0);

        int c = cvWaitKey(0);

        if( (char)c == 27 )
            break;

        if( (char)c == 'c' || (char)c == 'C' )
            distType0 = CV_DIST_C;
        else if( (char)c == '1' )
            distType0 = CV_DIST_L1;
        else if( (char)c == '2' )
            distType0 = CV_DIST_L2;
        else if( (char)c == '3' )
            maskSize0 = CV_DIST_MASK_3;
        else if( (char)c == '5' )
            maskSize0 = CV_DIST_MASK_5;
        else if( (char)c == '0' )
            maskSize0 = CV_DIST_MASK_PRECISE;
        else if( (char)c == 'v' )
            buildVoronoi = !buildVoronoi;
        else if( (char)c == ' ' )
        {
            if( buildVoronoi )
            {
                buildVoronoi = false;
                maskSize0 = CV_DIST_MASK_3;
                distType0 = CV_DIST_C;
            }
            else if( distType0 == CV_DIST_C )
                distType0 = CV_DIST_L1;
            else if( distType0 == CV_DIST_L1 )
                distType0 = CV_DIST_L2;
            else if( maskSize0 == CV_DIST_MASK_3 )
                maskSize0 = CV_DIST_MASK_5;
            else if( maskSize0 == CV_DIST_MASK_5 )
                maskSize0 = CV_DIST_MASK_PRECISE;
            else if( maskSize0 == CV_DIST_MASK_PRECISE )
                buildVoronoi = true;
        }
    }

    return 0;
}