4 * Sweep-and-update Euclidean distance transform of an
5 * image. Positive pixels are treated as object pixels,
6 * zero or negative pixels are treated as background.
7 * An attempt is made to treat antialiased edges correctly.
8 * The input image must have pixels in the range [0,1],
9 * and the antialiased image should be a box-filter
10 * sampling of the ideal, crisp edge.
11 * If the antialias region is more than 1 pixel wide,
12 * the result from this transform will be inaccurate.
14 * By Stefan Gustavson (stefan.gustavson@gmail.com).
16 * Originally written in 1994, based on a verbal
17 * description of the SSED8 algorithm published in the
18 * PhD dissertation of Ingemar Ragnemalm. This is his
19 * algorithm, I only implemented it in C.
21 * Updated in 2004 to treat border pixels correctly,
22 * and cleaned up the code to improve readability.
24 * Updated in 2009 to handle anti-aliased edges.
26 * Updated in 2011 to avoid a corner case infinite loop.
28 * Updated 2012 to change license from LGPL to MIT.
32 Copyright (C) 2009-2012 Stefan Gustavson (stefan.gustavson@gmail.com)
33 The code in this file is distributed under the MIT license:
35 Permission is hereby granted, free of charge, to any person obtaining a copy
36 of this software and associated documentation files (the "Software"), to deal
37 in the Software without restriction, including without limitation the rights
38 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39 copies of the Software, and to permit persons to whom the Software is
40 furnished to do so, subject to the following conditions:
42 The above copyright notice and this permission notice shall be included in
43 all copies or substantial portions of the Software.
45 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54 #ifdef BUILDING_ECERE_COM
58 // Note: Changed double to float from original version
61 * Compute the local gradient at edge pixels using convolution filters.
62 * The gradient is computed only at edge pixels. At other places in the
63 * image, it is never used, and it's mostly zero anyway.
65 void computegradient(float *img, int w, int h, float *gx, float *gy)
69 #define SQRT2 1.4142136f
70 for(i = 1; i < h-1; i++) { // Avoid edges where the kernels would spill over
71 for(j = 1; j < w-1; j++) {
73 if((img[k]>0.0) && (img[k]<1.0f)) { // Compute gradient for edge pixels only
74 gx[k] = -img[k-w-1] - SQRT2*img[k-1] - img[k+w-1] + img[k-w+1] + SQRT2*img[k+1] + img[k+w+1];
75 gy[k] = -img[k-w-1] - SQRT2*img[k-w] - img[k+w-1] + img[k-w+1] + SQRT2*img[k+w] + img[k+w+1];
76 glength = gx[k]*gx[k] + gy[k]*gy[k];
77 if(glength > 0.0f) { // Avoid division by zero
78 glength = (float)sqrt(glength);
85 // TODO: Compute reasonable values for gx, gy also around the image edges.
86 // (These are zero now, which reduces the accuracy for a 1-pixel wide region
87 // around the image edge.) 2x2 kernels would be suitable for this.
91 * A somewhat tricky function to approximate the distance to an edge in a
92 * certain pixel, with consideration to either the local gradient (gx,gy)
93 * or the direction to the pixel (dx,dy) and the pixel greyscale value a.
94 * The latter alternative, using (dx,dy), is the metric used by edtaa2().
95 * Using a local estimate of the edge gradient (gx,gy) yields much better
96 * accuracy at and near edges, and reduces the error even at distant pixels
97 * provided that the gradient direction is accurately estimated.
99 float edgedf(float gx, float gy, float a)
101 float df, glength, temp, a1;
103 if ((gx == 0) || (gy == 0)) { // Either A) gu or gv are zero, or B) both
104 df = 0.5f-a; // Linear approximation is A) correct or B) a fair guess
106 glength = (float)sqrt(gx*gx + gy*gy);
111 /* Everything is symmetric wrt sign and transposition,
112 * so move to first octant (gx>=0, gy>=0, gx>=gy) to
113 * avoid handling all possible edge directions.
115 gx = (float)fabs(gx);
116 gy = (float)fabs(gy);
123 if (a < a1) { // 0 <= a < a1
124 df = 0.5f*(gx + gy) - (float)sqrt(2.0*gx*gy*a);
125 } else if (a < (1.0-a1)) { // a1 <= a <= 1-a1
127 } else { // 1-a1 < a <= 1
128 df = -0.5f*(gx + gy) + (float)sqrt(2.0*gx*gy*(1.0-a));
134 float distaa3(float *img, float *gximg, float *gyimg, int w, int c, int xc, int yc, int xi, int yi)
136 float di, df, dx, dy, gx, gy, a;
139 closest = c-xc-yc*w; // Index to the edge pixel pointed to from c
140 a = img[closest]; // Grayscale value at the edge pixel
141 gx = gximg[closest]; // X gradient component at the edge pixel
142 gy = gyimg[closest]; // Y gradient component at the edge pixel
145 if(a < 0.0) a = 0.0; // Clip grayscale values outside the range [0,1]
146 if(a == 0.0) return 1000000.0; // Not an object pixel, return "very far" ("don't know yet")
150 di = (float)sqrt(dx*dx + dy*dy); // Length of integer vector, like a traditional EDT
151 if(di==0) { // Use local gradient only at edges
152 // Estimate based on local gradient only
153 df = edgedf(gx, gy, a);
155 // Estimate gradient based on direction to edge (accurate for large di)
156 df = edgedf(dx, dy, a);
158 return di + df; // Same metric as edtaa2, except at edges (where di=0)
161 // Shorthand macro: add ubiquitous parameters dist, gx, gy, img and w and call distaa3()
162 #define DISTAA(c,xc,yc,xi,yi) (distaa3(img, gx, gy, w, c, xc, yc, xi, yi))
164 void edtaa3(float *img, float *gx, float *gy, int w, int h, short *distx, short *disty, float *dist)
167 int offset_u, offset_ur, offset_r, offset_rd,
168 offset_d, offset_dl, offset_l, offset_lu;
169 float olddist, newdist;
170 int cdistx, cdisty, newdistx, newdisty;
172 float epsilon = 1e-3;
174 /* Initialize index offsets for the current image width */
184 /* Initialize the distance images */
185 for(i=0; i<w*h; i++) {
186 distx[i] = 0; // At first, all pixels point to
187 disty[i] = 0; // themselves as the closest known.
190 dist[i]= 1000000.0; // Big value, means "not set yet"
192 else if (img[i]<1.0) {
193 dist[i] = edgedf(gx[i], gy[i], img[i]); // Gradient-assisted estimate
196 dist[i]= 0.0; // Inside the object
200 /* Perform the transformation */
205 /* Scan rows, except first row */
209 /* move index to leftmost pixel of current row */
212 /* scan right, propagate distances from above & left */
214 /* Leftmost pixel is special, has no left neighbors */
216 if(olddist > 0) // If non-zero distance or not set yet
218 c = i + offset_u; // Index of candidate for testing
223 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
224 if(newdist < olddist-epsilon)
226 distx[i]=(short)newdistx;
227 disty[i]=(short)newdisty;
228 dist[i]=(short)newdist;
238 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
239 if(newdist < olddist-epsilon)
241 distx[i]=(short)newdistx;
242 disty[i]=(short)newdisty;
243 dist[i]=(short)newdist;
249 /* Middle pixels have all neighbors */
250 for(x=1; x<w-1; x++, i++)
253 if(olddist <= 0) continue; // No need to update further
260 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
261 if(newdist < olddist-epsilon)
263 distx[i]=(short)newdistx;
264 disty[i]=(short)newdisty;
265 dist[i]=(short)newdist;
275 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
276 if(newdist < olddist-epsilon)
278 distx[i]=(short)newdistx;
279 disty[i]=(short)newdisty;
280 dist[i]=(short)newdist;
290 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
291 if(newdist < olddist-epsilon)
293 distx[i]=(short)newdistx;
294 disty[i]=(short)newdisty;
295 dist[i]=(short)newdist;
305 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
306 if(newdist < olddist-epsilon)
308 distx[i]=(short)newdistx;
309 disty[i]=(short)newdisty;
310 dist[i]=(short)newdist;
315 /* Rightmost pixel of row is special, has no right neighbors */
317 if(olddist > 0) // If not already zero distance
324 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
325 if(newdist < olddist-epsilon)
327 distx[i]=(short)newdistx;
328 disty[i]=(short)newdisty;
329 dist[i]=(short)newdist;
339 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
340 if(newdist < olddist-epsilon)
342 distx[i]=(short)newdistx;
343 disty[i]=(short)newdisty;
344 dist[i]=(short)newdist;
354 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
355 if(newdist < olddist-epsilon)
357 distx[i]=(short)newdistx;
358 disty[i]=(short)newdisty;
359 dist[i]=(short)newdist;
364 /* Move index to second rightmost pixel of current row. */
365 /* Rightmost pixel is skipped, it has no right neighbor. */
368 /* scan left, propagate distance from right */
369 for(x=w-2; x>=0; x--, i--)
372 if(olddist <= 0) continue; // Already zero distance
379 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
380 if(newdist < olddist-epsilon)
382 distx[i]=(short)newdistx;
383 disty[i]=(short)newdisty;
384 dist[i]=(short)newdist;
390 /* Scan rows in reverse order, except last row */
391 for(y=h-2; y>=0; y--)
393 /* move index to rightmost pixel of current row */
396 /* Scan left, propagate distances from below & right */
398 /* Rightmost pixel is special, has no right neighbors */
400 if(olddist > 0) // If not already zero distance
407 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
408 if(newdist < olddist-epsilon)
410 distx[i]=(short)newdistx;
411 disty[i]=(short)newdisty;
412 dist[i]=(short)newdist;
422 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
423 if(newdist < olddist-epsilon)
425 distx[i]=(short)newdistx;
426 disty[i]=(short)newdisty;
427 dist[i]=(short)newdist;
433 /* Middle pixels have all neighbors */
434 for(x=w-2; x>0; x--, i--)
437 if(olddist <= 0) continue; // Already zero distance
444 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
445 if(newdist < olddist-epsilon)
447 distx[i]=(short)newdistx;
448 disty[i]=(short)newdisty;
449 dist[i]=(short)newdist;
459 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
460 if(newdist < olddist-epsilon)
462 distx[i]=(short)newdistx;
463 disty[i]=(short)newdisty;
464 dist[i]=(short)newdist;
474 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
475 if(newdist < olddist-epsilon)
477 distx[i]=(short)newdistx;
478 disty[i]=(short)newdisty;
479 dist[i]=(short)newdist;
489 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
490 if(newdist < olddist-epsilon)
492 distx[i]=(short)newdistx;
493 disty[i]=(short)newdisty;
494 dist[i]=(short)newdist;
498 /* Leftmost pixel is special, has no left neighbors */
500 if(olddist > 0) // If not already zero distance
507 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
508 if(newdist < olddist-epsilon)
510 distx[i]=(short)newdistx;
511 disty[i]=(short)newdisty;
512 dist[i]=(short)newdist;
522 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
523 if(newdist < olddist-epsilon)
525 distx[i]=(short)newdistx;
526 disty[i]=(short)newdisty;
527 dist[i]=(short)newdist;
537 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
538 if(newdist < olddist-epsilon)
540 distx[i]=(short)newdistx;
541 disty[i]=(short)newdisty;
542 dist[i]=(short)newdist;
547 /* Move index to second leftmost pixel of current row. */
548 /* Leftmost pixel is skipped, it has no left neighbor. */
550 for(x=1; x<w; x++, i++)
552 /* scan right, propagate distance from left */
554 if(olddist <= 0) continue; // Already zero distance
561 newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
562 if(newdist < olddist-epsilon)
564 distx[i]=(short)newdistx;
565 disty[i]=(short)newdisty;
566 dist[i]=(short)newdist;
572 while(changed); // Sweep until no more updates are made
574 /* The transformation is completed. */