1#include <opencv2/core/utility.hpp>
2#include "opencv2/imgproc.hpp"
3#include "opencv2/imgcodecs.hpp"
4#include "opencv2/highgui.hpp"
5
6#include <stdio.h>
7
8using namespace std;
9using namespace cv;
10
11int maskSize0 = DIST_MASK_5;
12int voronoiType = -1;
13int edgeThresh = 100;
14int distType0 = DIST_L1;
15
16// The output and temporary images
17Mat gray;
18
19// threshold trackbar callback
20static void onTrackbar( int, void* )
21{
22    static const Scalar colors[] =
23    {
24        Scalar(0,0,0),
25        Scalar(255,0,0),
26        Scalar(255,128,0),
27        Scalar(255,255,0),
28        Scalar(0,255,0),
29        Scalar(0,128,255),
30        Scalar(0,255,255),
31        Scalar(0,0,255),
32        Scalar(255,0,255)
33    };
34
35    int maskSize = voronoiType >= 0 ? DIST_MASK_5 : maskSize0;
36    int distType = voronoiType >= 0 ? DIST_L2 : distType0;
37
38    Mat edge = gray >= edgeThresh, dist, labels, dist8u;
39
40    if( voronoiType < 0 )
41        distanceTransform( edge, dist, distType, maskSize );
42    else
43        distanceTransform( edge, dist, labels, distType, maskSize, voronoiType );
44
45    if( voronoiType < 0 )
46    {
47        // begin "painting" the distance transform result
48        dist *= 5000;
49        pow(dist, 0.5, dist);
50
51        Mat dist32s, dist8u1, dist8u2;
52
53        dist.convertTo(dist32s, CV_32S, 1, 0.5);
54        dist32s &= Scalar::all(255);
55
56        dist32s.convertTo(dist8u1, CV_8U, 1, 0);
57        dist32s *= -1;
58
59        dist32s += Scalar::all(255);
60        dist32s.convertTo(dist8u2, CV_8U);
61
62        Mat planes[] = {dist8u1, dist8u2, dist8u2};
63        merge(planes, 3, dist8u);
64    }
65    else
66    {
67        dist8u.create(labels.size(), CV_8UC3);
68        for( int i = 0; i < labels.rows; i++ )
69        {
70            const int* ll = (const int*)labels.ptr(i);
71            const float* dd = (const float*)dist.ptr(i);
72            uchar* d = (uchar*)dist8u.ptr(i);
73            for( int j = 0; j < labels.cols; j++ )
74            {
75                int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1;
76                float scale = 1.f/(1 + dd[j]*dd[j]*0.0004f);
77                int b = cvRound(colors[idx][0]*scale);
78                int g = cvRound(colors[idx][1]*scale);
79                int r = cvRound(colors[idx][2]*scale);
80                d[j*3] = (uchar)b;
81                d[j*3+1] = (uchar)g;
82                d[j*3+2] = (uchar)r;
83            }
84        }
85    }
86
87    imshow("Distance Map", dist8u );
88}
89
90static void help()
91{
92    printf("\nProgram to demonstrate the use of the distance transform function between edge images.\n"
93            "Usage:\n"
94            "./distrans [image_name -- default image is ../data/stuff.jpg]\n"
95            "\nHot keys: \n"
96            "\tESC - quit the program\n"
97            "\tC - use C/Inf metric\n"
98            "\tL1 - use L1 metric\n"
99            "\tL2 - use L2 metric\n"
100            "\t3 - use 3x3 mask\n"
101            "\t5 - use 5x5 mask\n"
102            "\t0 - use precise distance transform\n"
103            "\tv - switch to Voronoi diagram mode\n"
104            "\tp - switch to pixel-based Voronoi diagram mode\n"
105            "\tSPACE - loop through all the modes\n\n");
106}
107
108const char* keys =
109{
110    "{@image |../data/stuff.jpg|input image file}"
111};
112
113int main( int argc, const char** argv )
114{
115    help();
116    CommandLineParser parser(argc, argv, keys);
117    string filename = parser.get<string>(0);
118    gray = imread(filename.c_str(), 0);
119    if(gray.empty())
120    {
121        printf("Cannot read image file: %s\n", filename.c_str());
122        help();
123        return -1;
124    }
125
126    namedWindow("Distance Map", 1);
127    createTrackbar("Brightness Threshold", "Distance Map", &edgeThresh, 255, onTrackbar, 0);
128
129    for(;;)
130    {
131        // Call to update the view
132        onTrackbar(0, 0);
133
134        int c = waitKey(0) & 255;
135
136        if( c == 27 )
137            break;
138
139        if( c == 'c' || c == 'C' || c == '1' || c == '2' ||
140            c == '3' || c == '5' || c == '0' )
141            voronoiType = -1;
142
143        if( c == 'c' || c == 'C' )
144            distType0 = DIST_C;
145        else if( c == '1' )
146            distType0 = DIST_L1;
147        else if( c == '2' )
148            distType0 = DIST_L2;
149        else if( c == '3' )
150            maskSize0 = DIST_MASK_3;
151        else if( c == '5' )
152            maskSize0 = DIST_MASK_5;
153        else if( c == '0' )
154            maskSize0 = DIST_MASK_PRECISE;
155        else if( c == 'v' )
156            voronoiType = 0;
157        else if( c == 'p' )
158            voronoiType = 1;
159        else if( c == ' ' )
160        {
161            if( voronoiType == 0 )
162                voronoiType = 1;
163            else if( voronoiType == 1 )
164            {
165                voronoiType = -1;
166                maskSize0 = DIST_MASK_3;
167                distType0 = DIST_C;
168            }
169            else if( distType0 == DIST_C )
170                distType0 = DIST_L1;
171            else if( distType0 == DIST_L1 )
172                distType0 = DIST_L2;
173            else if( maskSize0 == DIST_MASK_3 )
174                maskSize0 = DIST_MASK_5;
175            else if( maskSize0 == DIST_MASK_5 )
176                maskSize0 = DIST_MASK_PRECISE;
177            else if( maskSize0 == DIST_MASK_PRECISE )
178                voronoiType = 0;
179        }
180    }
181
182    return 0;
183}
184