naev 0.12.6
edtaa3func.c
1/*
2 * edtaa3()
3 *
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.
13 *
14 * By Stefan Gustavson (stefan.gustavson@gmail.com).
15 *
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.
20 *
21 * Updated in 2004 to treat border pixels correctly,
22 * and cleaned up the code to improve readability.
23 *
24 * Updated in 2009 to handle anti-aliased edges.
25 *
26 * Updated in 2011 to avoid a corner case infinite loop.
27 *
28 * Updated 2012 to change license from LGPL to MIT.
29 *
30 * Updated 2014 to fix a bug with the 'gy' gradient computation.
31 *
32 */
33
34/*
35 Copyright (C) 2009-2012 Stefan Gustavson (stefan.gustavson@gmail.com)
36 The code in this file is distributed under the MIT license:
37
38 Permission is hereby granted, free of charge, to any person obtaining a copy
39 of this software and associated documentation files (the "Software"), to deal
40 in the Software without restriction, including without limitation the rights
41 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42 copies of the Software, and to permit persons to whom the Software is
43 furnished to do so, subject to the following conditions:
44
45 The above copyright notice and this permission notice shall be included in
46 all copies or substantial portions of the Software.
47
48 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54 THE SOFTWARE.
55 */
56
58#include <math.h>
60#include "edtaa3func.h"
61
62/*
63 * Compute the local gradient at edge pixels using convolution filters.
64 * The gradient is computed only at edge pixels. At other places in the
65 * image, it is never used, and it's mostly zero anyway.
66 */
67void computegradient( double *img, int w, int h, double *gx, double *gy )
68{
69 int i, j, k; //,p,q;
70 double glength; //, phi, phiscaled, ascaled, errsign, pfrac, qfrac, err0,
71 // err1, err;
72#define SQRT2 1.4142136
73 for ( i = 1; i < h - 1;
74 i++ ) { // Avoid edges where the kernels would spill over
75 for ( j = 1; j < w - 1; j++ ) {
76 k = i * w + j;
77 if ( ( img[k] > 0.0 ) &&
78 ( img[k] < 1.0 ) ) { // Compute gradient for edge pixels only
79 gx[k] = -img[k - w - 1] - SQRT2 * img[k - 1] - img[k + w - 1] +
80 img[k - w + 1] + SQRT2 * img[k + 1] + img[k + w + 1];
81 gy[k] = -img[k - w - 1] - SQRT2 * img[k - w] - img[k - w + 1] +
82 img[k + w - 1] + SQRT2 * img[k + w] + img[k + w + 1];
83 glength = gx[k] * gx[k] + gy[k] * gy[k];
84 if ( glength > 0.0 ) { // Avoid division by zero
85 glength = sqrt( glength );
86 gx[k] = gx[k] / glength;
87 gy[k] = gy[k] / glength;
88 }
89 }
90 }
91 }
92 // TODO: Compute reasonable values for gx, gy also around the image edges.
93 // (These are zero now, which reduces the accuracy for a 1-pixel wide region
94 // around the image edge.) 2x2 kernels would be suitable for this.
95}
96
97/*
98 * A somewhat tricky function to approximate the distance to an edge in a
99 * certain pixel, with consideration to either the local gradient (gx,gy)
100 * or the direction to the pixel (dx,dy) and the pixel greyscale value a.
101 * The latter alternative, using (dx,dy), is the metric used by edtaa2().
102 * Using a local estimate of the edge gradient (gx,gy) yields much better
103 * accuracy at and near edges, and reduces the error even at distant pixels
104 * provided that the gradient direction is accurately estimated.
105 */
106double edgedf( double gx, double gy, double a )
107{
108 double df, glength, temp, a1;
109
110 if ( ( gx == 0 ) ||
111 ( gy == 0 ) ) { // Either A) gu or gv are zero, or B) both
112 df = 0.5 - a; // Linear approximation is A) correct or B) a fair guess
113 } else {
114 glength = sqrt( gx * gx + gy * gy );
115 if ( glength > 0 ) {
116 gx = gx / glength;
117 gy = gy / glength;
118 }
119 /* Everything is symmetric wrt sign and transposition,
120 * so move to first octant (gx>=0, gy>=0, gx>=gy) to
121 * avoid handling all possible edge directions.
122 */
123 gx = fabs( gx );
124 gy = fabs( gy );
125 if ( gx < gy ) {
126 temp = gx;
127 gx = gy;
128 gy = temp;
129 }
130 a1 = 0.5 * gy / gx;
131 if ( a < a1 ) { // 0 <= a < a1
132 df = 0.5 * ( gx + gy ) - sqrt( 2.0 * gx * gy * a );
133 } else if ( a < ( 1.0 - a1 ) ) { // a1 <= a <= 1-a1
134 df = ( 0.5 - a ) * gx;
135 } else { // 1-a1 < a <= 1
136 df = -0.5 * ( gx + gy ) + sqrt( 2.0 * gx * gy * ( 1.0 - a ) );
137 }
138 }
139 return df;
140}
141
142double distaa3( double *img, double *gximg, double *gyimg, int w, int c, int xc,
143 int yc, int xi, int yi )
144{
145 double di, df, dx, dy, gx, gy, a;
146 int closest;
147
148 closest = c - xc - yc * w; // Index to the edge pixel pointed to from c
149 a = img[closest]; // Grayscale value at the edge pixel
150 gx = gximg[closest]; // X gradient component at the edge pixel
151 gy = gyimg[closest]; // Y gradient component at the edge pixel
152
153 if ( a > 1.0 )
154 a = 1.0;
155 if ( a < 0.0 )
156 a = 0.0; // Clip grayscale values outside the range [0,1]
157 if ( a == 0.0 )
158 return 1000000.0; // Not an object pixel, return "very far" ("don't know
159 // yet")
160
161 dx = (double)xi;
162 dy = (double)yi;
163 di = sqrt( dx * dx +
164 dy * dy ); // Length of integer vector, like a traditional EDT
165 if ( di == 0 ) { // Use local gradient only at edges
166 // Estimate based on local gradient only
167 df = edgedf( gx, gy, a );
168 } else {
169 // Estimate gradient based on direction to edge (accurate for large di)
170 df = edgedf( dx, dy, a );
171 }
172 return di + df; // Same metric as edtaa2, except at edges (where di=0)
173}
174
175// Shorthand macro: add ubiquitous parameters dist, gx, gy, img and w and call
176// distaa3()
177#define DISTAA( c, xc, yc, xi, yi ) \
178 ( distaa3( img, gx, gy, w, c, xc, yc, xi, yi ) )
179
180void edtaa3( double *img, double *gx, double *gy, int w, int h, short *distx,
181 short *disty, double *dist )
182{
183 int x, y, i, c;
184 int offset_u, offset_ur, offset_r, offset_rd, offset_d, offset_dl, offset_l,
185 offset_lu;
186 double olddist, newdist;
187 int cdistx, cdisty, newdistx, newdisty;
188 int changed;
189 double epsilon = 1e-3;
190
191 /* Initialize index offsets for the current image width */
192 offset_u = -w;
193 offset_ur = -w + 1;
194 offset_r = 1;
195 offset_rd = w + 1;
196 offset_d = w;
197 offset_dl = w - 1;
198 offset_l = -1;
199 offset_lu = -w - 1;
200
201 /* Initialize the distance images */
202 for ( i = 0; i < w * h; i++ ) {
203 distx[i] = 0; // At first, all pixels point to
204 disty[i] = 0; // themselves as the closest known.
205 if ( img[i] <= 0.0 ) {
206 dist[i] = 1000000.0; // Big value, means "not set yet"
207 } else if ( img[i] < 1.0 ) {
208 dist[i] = edgedf( gx[i], gy[i], img[i] ); // Gradient-assisted estimate
209 } else {
210 dist[i] = 0.0; // Inside the object
211 }
212 }
213
214 /* Perform the transformation */
215 do {
216 changed = 0;
217
218 /* Scan rows, except first row */
219 for ( y = 1; y < h; y++ ) {
220
221 /* move index to leftmost pixel of current row */
222 i = y * w;
223
224 /* scan right, propagate distances from above & left */
225
226 /* Leftmost pixel is special, has no left neighbors */
227 olddist = dist[i];
228 if ( olddist > 0 ) // If non-zero distance or not set yet
229 {
230 c = i + offset_u; // Index of candidate for testing
231 cdistx = distx[c];
232 cdisty = disty[c];
233 newdistx = cdistx;
234 newdisty = cdisty + 1;
235 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
236 if ( newdist < olddist - epsilon ) {
237 distx[i] = newdistx;
238 disty[i] = newdisty;
239 dist[i] = newdist;
240 olddist = newdist;
241 changed = 1;
242 }
243
244 c = i + offset_ur;
245 cdistx = distx[c];
246 cdisty = disty[c];
247 newdistx = cdistx - 1;
248 newdisty = cdisty + 1;
249 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
250 if ( newdist < olddist - epsilon ) {
251 distx[i] = newdistx;
252 disty[i] = newdisty;
253 dist[i] = newdist;
254 changed = 1;
255 }
256 }
257 i++;
258
259 /* Middle pixels have all neighbors */
260 for ( x = 1; x < w - 1; x++, i++ ) {
261 olddist = dist[i];
262 if ( olddist <= 0 )
263 continue; // No need to update further
264
265 c = i + offset_l;
266 cdistx = distx[c];
267 cdisty = disty[c];
268 newdistx = cdistx + 1;
269 newdisty = cdisty;
270 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
271 if ( newdist < olddist - epsilon ) {
272 distx[i] = newdistx;
273 disty[i] = newdisty;
274 dist[i] = newdist;
275 olddist = newdist;
276 changed = 1;
277 }
278
279 c = i + offset_lu;
280 cdistx = distx[c];
281 cdisty = disty[c];
282 newdistx = cdistx + 1;
283 newdisty = cdisty + 1;
284 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
285 if ( newdist < olddist - epsilon ) {
286 distx[i] = newdistx;
287 disty[i] = newdisty;
288 dist[i] = newdist;
289 olddist = newdist;
290 changed = 1;
291 }
292
293 c = i + offset_u;
294 cdistx = distx[c];
295 cdisty = disty[c];
296 newdistx = cdistx;
297 newdisty = cdisty + 1;
298 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
299 if ( newdist < olddist - epsilon ) {
300 distx[i] = newdistx;
301 disty[i] = newdisty;
302 dist[i] = newdist;
303 olddist = newdist;
304 changed = 1;
305 }
306
307 c = i + offset_ur;
308 cdistx = distx[c];
309 cdisty = disty[c];
310 newdistx = cdistx - 1;
311 newdisty = cdisty + 1;
312 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
313 if ( newdist < olddist - epsilon ) {
314 distx[i] = newdistx;
315 disty[i] = newdisty;
316 dist[i] = newdist;
317 changed = 1;
318 }
319 }
320
321 /* Rightmost pixel of row is special, has no right neighbors */
322 olddist = dist[i];
323 if ( olddist > 0 ) // If not already zero distance
324 {
325 c = i + offset_l;
326 cdistx = distx[c];
327 cdisty = disty[c];
328 newdistx = cdistx + 1;
329 newdisty = cdisty;
330 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
331 if ( newdist < olddist - epsilon ) {
332 distx[i] = newdistx;
333 disty[i] = newdisty;
334 dist[i] = newdist;
335 olddist = newdist;
336 changed = 1;
337 }
338
339 c = i + offset_lu;
340 cdistx = distx[c];
341 cdisty = disty[c];
342 newdistx = cdistx + 1;
343 newdisty = cdisty + 1;
344 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
345 if ( newdist < olddist - epsilon ) {
346 distx[i] = newdistx;
347 disty[i] = newdisty;
348 dist[i] = newdist;
349 olddist = newdist;
350 changed = 1;
351 }
352
353 c = i + offset_u;
354 cdistx = distx[c];
355 cdisty = disty[c];
356 newdistx = cdistx;
357 newdisty = cdisty + 1;
358 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
359 if ( newdist < olddist - epsilon ) {
360 distx[i] = newdistx;
361 disty[i] = newdisty;
362 dist[i] = newdist;
363 changed = 1;
364 }
365 }
366
367 /* Move index to second rightmost pixel of current row. */
368 /* Rightmost pixel is skipped, it has no right neighbor. */
369 i = y * w + w - 2;
370
371 /* scan left, propagate distance from right */
372 for ( x = w - 2; x >= 0; x--, i-- ) {
373 olddist = dist[i];
374 if ( olddist <= 0 )
375 continue; // Already zero distance
376
377 c = i + offset_r;
378 cdistx = distx[c];
379 cdisty = disty[c];
380 newdistx = cdistx - 1;
381 newdisty = cdisty;
382 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
383 if ( newdist < olddist - epsilon ) {
384 distx[i] = newdistx;
385 disty[i] = newdisty;
386 dist[i] = newdist;
387 changed = 1;
388 }
389 }
390 }
391
392 /* Scan rows in reverse order, except last row */
393 for ( y = h - 2; y >= 0; y-- ) {
394 /* move index to rightmost pixel of current row */
395 i = y * w + w - 1;
396
397 /* Scan left, propagate distances from below & right */
398
399 /* Rightmost pixel is special, has no right neighbors */
400 olddist = dist[i];
401 if ( olddist > 0 ) // If not already zero distance
402 {
403 c = i + offset_d;
404 cdistx = distx[c];
405 cdisty = disty[c];
406 newdistx = cdistx;
407 newdisty = cdisty - 1;
408 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
409 if ( newdist < olddist - epsilon ) {
410 distx[i] = newdistx;
411 disty[i] = newdisty;
412 dist[i] = newdist;
413 olddist = newdist;
414 changed = 1;
415 }
416
417 c = i + offset_dl;
418 cdistx = distx[c];
419 cdisty = disty[c];
420 newdistx = cdistx + 1;
421 newdisty = cdisty - 1;
422 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
423 if ( newdist < olddist - epsilon ) {
424 distx[i] = newdistx;
425 disty[i] = newdisty;
426 dist[i] = newdist;
427 changed = 1;
428 }
429 }
430 i--;
431
432 /* Middle pixels have all neighbors */
433 for ( x = w - 2; x > 0; x--, i-- ) {
434 olddist = dist[i];
435 if ( olddist <= 0 )
436 continue; // Already zero distance
437
438 c = i + offset_r;
439 cdistx = distx[c];
440 cdisty = disty[c];
441 newdistx = cdistx - 1;
442 newdisty = cdisty;
443 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
444 if ( newdist < olddist - epsilon ) {
445 distx[i] = newdistx;
446 disty[i] = newdisty;
447 dist[i] = newdist;
448 olddist = newdist;
449 changed = 1;
450 }
451
452 c = i + offset_rd;
453 cdistx = distx[c];
454 cdisty = disty[c];
455 newdistx = cdistx - 1;
456 newdisty = cdisty - 1;
457 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
458 if ( newdist < olddist - epsilon ) {
459 distx[i] = newdistx;
460 disty[i] = newdisty;
461 dist[i] = newdist;
462 olddist = newdist;
463 changed = 1;
464 }
465
466 c = i + offset_d;
467 cdistx = distx[c];
468 cdisty = disty[c];
469 newdistx = cdistx;
470 newdisty = cdisty - 1;
471 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
472 if ( newdist < olddist - epsilon ) {
473 distx[i] = newdistx;
474 disty[i] = newdisty;
475 dist[i] = newdist;
476 olddist = newdist;
477 changed = 1;
478 }
479
480 c = i + offset_dl;
481 cdistx = distx[c];
482 cdisty = disty[c];
483 newdistx = cdistx + 1;
484 newdisty = cdisty - 1;
485 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
486 if ( newdist < olddist - epsilon ) {
487 distx[i] = newdistx;
488 disty[i] = newdisty;
489 dist[i] = newdist;
490 changed = 1;
491 }
492 }
493 /* Leftmost pixel is special, has no left neighbors */
494 olddist = dist[i];
495 if ( olddist > 0 ) // If not already zero distance
496 {
497 c = i + offset_r;
498 cdistx = distx[c];
499 cdisty = disty[c];
500 newdistx = cdistx - 1;
501 newdisty = cdisty;
502 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
503 if ( newdist < olddist - epsilon ) {
504 distx[i] = newdistx;
505 disty[i] = newdisty;
506 dist[i] = newdist;
507 olddist = newdist;
508 changed = 1;
509 }
510
511 c = i + offset_rd;
512 cdistx = distx[c];
513 cdisty = disty[c];
514 newdistx = cdistx - 1;
515 newdisty = cdisty - 1;
516 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
517 if ( newdist < olddist - epsilon ) {
518 distx[i] = newdistx;
519 disty[i] = newdisty;
520 dist[i] = newdist;
521 olddist = newdist;
522 changed = 1;
523 }
524
525 c = i + offset_d;
526 cdistx = distx[c];
527 cdisty = disty[c];
528 newdistx = cdistx;
529 newdisty = cdisty - 1;
530 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
531 if ( newdist < olddist - epsilon ) {
532 distx[i] = newdistx;
533 disty[i] = newdisty;
534 dist[i] = newdist;
535 changed = 1;
536 }
537 }
538
539 /* Move index to second leftmost pixel of current row. */
540 /* Leftmost pixel is skipped, it has no left neighbor. */
541 i = y * w + 1;
542 for ( x = 1; x < w; x++, i++ ) {
543 /* scan right, propagate distance from left */
544 olddist = dist[i];
545 if ( olddist <= 0 )
546 continue; // Already zero distance
547
548 c = i + offset_l;
549 cdistx = distx[c];
550 cdisty = disty[c];
551 newdistx = cdistx + 1;
552 newdisty = cdisty;
553 newdist = DISTAA( c, cdistx, cdisty, newdistx, newdisty );
554 if ( newdist < olddist - epsilon ) {
555 distx[i] = newdistx;
556 disty[i] = newdisty;
557 dist[i] = newdist;
558 changed = 1;
559 }
560 }
561 }
562 } while ( changed ); // Sweep until no more updates are made
563
564 /* The transformation is completed. */
565}
static const double c[]
Definition rng.c:256