Mercurial > hg > octave-image
changeset 744:7ca50fccb8cc
bwdist: changed to C++
* removed actual C edtfunc function and fit it into bwdist.cc
with C++ templates.
* most code reorganization by removing all preprocessor stuff
eased by inclusion of the C function
* approximatelly 25% performance increase for euclidean method
author | carandraug |
---|---|
date | Tue, 16 Apr 2013 03:05:46 +0000 (2013-04-16) |
parents | 4bb352ade7c7 |
children | 27d87f06dd99 |
files | src/bwdist.cc src/edtfunc.c |
diffstat | 2 files changed, 419 insertions(+), 444 deletions(-) [+] |
line wrap: on
line diff
--- a/src/bwdist.cc +++ b/src/bwdist.cc @@ -14,49 +14,416 @@ // You should have received a copy of the GNU General Public License along with // this program; if not, see <http://www.gnu.org/licenses/>. -// Depends on "edtfunc.c" for the actual computations +// TODO output Matrix must be single class +// class of IDX is uint32 for numel () <= 2^32 - 1 +// uint64 for numel () >= 2^32 +// check for any improvement in using boolean matrix #include <octave/oct.h> -#ifdef __cplusplus -extern "C" +/* + edtfunc - Euclidean distance transform of a binary image + + This is a sweep-and-update Euclidean distance transform of + a binary image. All positive pixels are considered object + pixels, zero or negative pixels are treated as background. + + By Stefan Gustavson (stefan.gustavson@gmail.com). + + Originally written in 1994, based on paper-only descriptions + of the SSED8 algorithm, invented by Per-Erik Danielsson + and improved by Ingemar Ragnemalm. This is a classic algorithm + with roots in the 1980s, still very good for the 2D case. + + Updated in 2004 to treat pixels at image edges correctly, + and to improve code readability. + + Edited in 2009 to form the foundation for Octave BWDIST: + added #define-configurable distance measure and function name + + Edited in 2013 for C++ and removed the #define stuff + */ + +/* + Using template for optimization. + Because func is called a lot of times in edtfunc, we instantiate edtfunc + multiple times for each of the different distance measuring functions. +*/ + +template<typename func> +void edtfunc (const Matrix &img, + short *distx, + short *disty) { -#endif + const int w = img.cols (); + const int h = img.rows (); + const int numel = img.numel (); + + int x, y, i; + double olddist2, newdist2, newdistx, newdisty; + bool changed; + + // Initialize index offsets for the current image width + const int offset_u = -w; + const int offset_ur = -w+1; + const int offset_r = 1; + const int offset_rd = w+1; + const int offset_d = w; + const int offset_dl = w-1; + const int offset_l = -1; + const int offset_lu = -w-1; + + // Initialize the distance images to be all large values + for (i = 0; i < numel; i++) + { + if(img(i) <= 0.0) + { + distx[i] = 32000; // Large but still representable in a short, and + disty[i] = 32000; // 32000^2 + 32000^2 does not overflow an int + } + else + { + distx[i] = 0; + disty[i] = 0; + } + } + + // Perform the transformation + do + { + changed = false; + + // Scan rows, except first row + for (y = 1; y < h; y++) + { + + // move index to leftmost pixel of current row + i = y*w; + + /* scan right, propagate distances from above & left */ + + /* Leftmost pixel is special, has no left neighbors */ + olddist2 = func::apply(distx[i], disty[i]); + if(olddist2 > 0) // If not already zero distance + { + newdistx = distx[i+offset_u]; + newdisty = disty[i+offset_u]+1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } -#define DIST_EUCLIDEAN(x,y) sqrt((int)(x)*(x) + (y)*(y)) -#define MAX(x,y) ((x)>(y) ? (x) : (y)) -#define DIST_CHESSBOARD(x,y) (MAX(abs(x), abs(y))) -#define DIST_CITYBLOCK(x,y) (abs(x) + abs(y)) -#define SQRT2_1 0.4142136536 -#define DIST_QUASI_EUCLIDEAN(x,y) (abs(x)>abs(y) ? (abs(x) + SQRT2_1 * abs(y)) : (SQRT2_1 * abs(x) + abs(y))) + newdistx = distx[i+offset_ur]-1; + newdisty = disty[i+offset_ur]+1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + changed = true; + } + } + i++; + + /* Middle pixels have all neighbors */ + for(x=1; x<w-1; x++, i++) + { + olddist2 = func::apply(distx[i], disty[i]); + if(olddist2 == 0) continue; // Already zero distance + + newdistx = distx[i+offset_l]+1; + newdisty = disty[i+offset_l]; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + + newdistx = distx[i+offset_lu]+1; + newdisty = disty[i+offset_lu]+1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + + newdistx = distx[i+offset_u]; + newdisty = disty[i+offset_u]+1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } -#define DIST(x,y) DIST_EUCLIDEAN(x,y) -#define FUNCNAME euclidean -#include "edtfunc.c" -#undef DIST -#undef FUNCNAME + newdistx = distx[i+offset_ur]-1; + newdisty = disty[i+offset_ur]+1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + changed = true; + } + } + + /* Rightmost pixel of row is special, has no right neighbors */ + olddist2 = func::apply(distx[i], disty[i]); + if(olddist2 > 0) // If not already zero distance + { + newdistx = distx[i+offset_l]+1; + newdisty = disty[i+offset_l]; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + + newdistx = distx[i+offset_lu]+1; + newdisty = disty[i+offset_lu]+1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + + newdistx = distx[i+offset_u]; + newdisty = disty[i+offset_u]+1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + } + + /* Move index to second rightmost pixel of current row. */ + /* Rightmost pixel is skipped, it has no right neighbor. */ + i = y*w + w-2; -#define DIST(x,y) DIST_CHESSBOARD(x,y) -#define FUNCNAME chessboard -#include "edtfunc.c" -#undef DIST -#undef FUNCNAME + /* scan left, propagate distance from right */ + for(x=w-2; x>=0; x--, i--) + { + olddist2 = func::apply(distx[i], disty[i]); + if(olddist2 == 0) continue; // Already zero distance + + newdistx = distx[i+offset_r]-1; + newdisty = disty[i+offset_r]; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + changed = true; + } + } + } + + /* Scan rows in reverse order, except last row */ + for(y=h-2; y>=0; y--) + { + /* move index to rightmost pixel of current row */ + i = y*w + w-1; + + /* Scan left, propagate distances from below & right */ + + /* Rightmost pixel is special, has no right neighbors */ + olddist2 = func::apply(distx[i], disty[i]); + if(olddist2 > 0) // If not already zero distance + { + newdistx = distx[i+offset_d]; + newdisty = disty[i+offset_d]-1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + + newdistx = distx[i+offset_dl]+1; + newdisty = disty[i+offset_dl]-1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + changed = true; + } + } + i--; + + /* Middle pixels have all neighbors */ + for(x=w-2; x>0; x--, i--) + { + olddist2 = func::apply(distx[i], disty[i]); + if(olddist2 == 0) continue; // Already zero distance + + newdistx = distx[i+offset_r]-1; + newdisty = disty[i+offset_r]; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + + newdistx = distx[i+offset_rd]-1; + newdisty = disty[i+offset_rd]-1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + + newdistx = distx[i+offset_d]; + newdisty = disty[i+offset_d]-1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } -#define DIST(x,y) DIST_CITYBLOCK(x,y) -#define FUNCNAME cityblock -#include "edtfunc.c" -#undef DIST -#undef FUNCNAME + newdistx = distx[i+offset_dl]+1; + newdisty = disty[i+offset_dl]-1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + changed = true; + } + } + /* Leftmost pixel is special, has no left neighbors */ + olddist2 = func::apply(distx[i], disty[i]); + if(olddist2 > 0) // If not already zero distance + { + newdistx = distx[i+offset_r]-1; + newdisty = disty[i+offset_r]; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + + newdistx = distx[i+offset_rd]-1; + newdisty = disty[i+offset_rd]-1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + + newdistx = distx[i+offset_d]; + newdisty = disty[i+offset_d]-1; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + olddist2=newdist2; + changed = true; + } + } -#define DIST(x,y) DIST_QUASI_EUCLIDEAN(x,y) -#define FUNCNAME quasi_euclidean -#include "edtfunc.c" -#undef DIST -#undef FUNCNAME + /* Move index to second leftmost pixel of current row. */ + /* Leftmost pixel is skipped, it has no left neighbor. */ + i = y*w + 1; + for(x=1; x<w; x++, i++) + { + /* scan right, propagate distance from left */ + olddist2 = func::apply(distx[i], disty[i]); + if(olddist2 == 0) continue; // Already zero distance + + newdistx = distx[i+offset_l]+1; + newdisty = disty[i+offset_l]; + newdist2 = func::apply(newdistx, newdisty); + if(newdist2 < olddist2) + { + distx[i]=newdistx; + disty[i]=newdisty; + changed = true; + } + } + } + } + while (changed); // Sweep until no more updates are made + // The transformation is completed +} -#ifdef __cplusplus -} /* end extern "C" */ -#endif +// The different functions used to calculate distance, as a +// class so its typename can be used for edtfunc template +struct euclidean +{ + static double apply(short x, short y) + { return sqrt ((int)(x)*(x) + (y)*(y)); } +}; +struct chessboard +{ + static double apply(short x, short y) + { return std::max (abs (y), abs (x)); } +}; +struct cityblock +{ + static double apply(short x, short y) + { return abs (x) + abs (y); } +}; +struct quasi_euclidean +{ + static double apply(short x, short y) + { + static const double sqrt2_1 = sqrt (2) - 1; + return abs(x)>abs(y) ? (abs(x) + sqrt2_1 * abs(y)) : + (sqrt2_1 * abs(x) + abs(y)) ; + } +}; + +template<typename func> +void loop_distance (const Matrix &bw, + Matrix &dist, + short *xdist, + short *ydist) +{ + edtfunc<func> (bw, xdist, ydist); + const int numel = bw.numel (); + for (int i = 0; i < numel; i++) + dist(i) = func::apply (xdist[i], ydist[i]); +} DEFUN_DLD (bwdist, args, nargout, "-*- texinfo -*-\n\ @@ -127,53 +494,36 @@ warning ("bwdist: specifying METHOD with abbreviation is deprecated"); warned = true; } + if (method == "e" ) { method = "euclidean"; } + else if (method == "ch") { method = "chessboard"; } + else if (method == "ci") { method = "cityblock"; } + else if (method == "q" ) { method = "quasi-euclidean"; } } - const int cols = bw.cols (); - const int rows = bw.rows (); + // Allocate two arrays for temporary output values const int numel = bw.numel (); - - // Allocate two arrays for temporary output values OCTAVE_LOCAL_BUFFER (short, xdist, numel); OCTAVE_LOCAL_BUFFER (short, ydist, numel); - Matrix dist (rows, cols); // the output distance matrix - - if (! method.compare ("euclidean") || ! method.compare ("e")) - { - euclidean (bw, rows, cols, xdist, ydist); - for (int i = 0; i < numel; i++) - dist(i) = DIST_EUCLIDEAN (xdist[i], ydist[i]); - } - else if (! method.compare ("chessboard") || ! method.compare ("ch")) - { - chessboard (bw, rows, cols, xdist, ydist); - for (int i = 0; i < numel; i++) - dist(i) = DIST_CHESSBOARD (xdist[i], ydist[i]); - } - else if (! method.compare ("cityblock") || ! method.compare ("ci")) - { - cityblock (bw, rows, cols, xdist, ydist); - for (int i = 0; i < numel; i++) - dist(i) = DIST_CITYBLOCK (xdist[i], ydist[i]); - } - else if (! method.compare ("quasi-euclidean") || ! method.compare ("q")) - { - quasi_euclidean (bw, rows, cols, xdist, ydist); - for (int i = 0; i < numel; i++) - dist(i) = DIST_QUASI_EUCLIDEAN (xdist[i], ydist[i]); - } + Matrix dist (bw.dims ()); // the output distance matrix + if (method == "euclidean") + loop_distance<euclidean> (bw, dist, xdist, ydist); + else if (method == "chessboard") + loop_distance<chessboard> (bw, dist, xdist, ydist); + else if (method == "cityblock") + loop_distance<cityblock> (bw, dist, xdist, ydist); + else if (method == "quasi-euclidean") + loop_distance<quasi_euclidean> (bw, dist, xdist, ydist); else - { - error ("bwdist: unknown METHOD '%s'", method.c_str ()); - } + error ("bwdist: unknown METHOD '%s'", method.c_str ()); retval(0) = dist; - if (nargout > 1) // only compute IDX, if requested + // Compute optional 'index to closest object pixel', only if requested + if (nargout > 1) { - Matrix idx (rows, cols); - // Compute optional 'index to closest object pixel' + Matrix idx (bw.dims ()); + const int rows = bw.rows (); for(int i = 0; i < numel; i++) idx (i) = i+1 - xdist[i] - ydist[i]*rows;
deleted file mode 100755 --- a/src/edtfunc.c +++ /dev/null @@ -1,375 +0,0 @@ -// Copyright (C) 2009 Stefan Gustavson <stefan.gustavson@gmail.com> -// -// This program is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free Software -// Foundation; either version 3 of the License, or (at your option) any later -// version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, see <http://www.gnu.org/licenses/>. - -/* - * edtfunc.c - Euclidean distance transform of a binary image - * - * This is a sweep-and-update Euclidean distance transform of - * a binary image. All positive pixels are considered object - * pixels, zero or negative pixels are treated as background. - * - * By Stefan Gustavson (stefan.gustavson@gmail.com). - * - * Originally written in 1994, based on paper-only descriptions - * of the SSED8 algorithm, invented by Per-Erik Danielsson - * and improved by Ingemar Ragnemalm. This is a classic algorithm - * with roots in the 1980s, still very good for the 2D case. - * - * Updated in 2004 to treat pixels at image edges correctly, - * and to improve code readability. - * - * Edited in 2009 to form the foundation for Octave BWDIST: - * added #define-configurable distance measure and function name - * - */ - -#ifndef DIST -#define DIST(x,y) ((int)(x) * (x) + (y) * (y)) -#endif - -#ifndef FUNCNAME -#define FUNCNAME edt -#endif - -void FUNCNAME(const Matrix &img, int w, int h, short *distx, short *disty) -{ - int x, y, i; - int offset_u, offset_ur, offset_r, offset_rd, - offset_d, offset_dl, offset_l, offset_lu; - double olddist2, newdist2, newdistx, newdisty; - int changed; - - /* Initialize index offsets for the current image width */ - offset_u = -w; - offset_ur = -w+1; - offset_r = 1; - offset_rd = w+1; - offset_d = w; - offset_dl = w-1; - offset_l = -1; - offset_lu = -w-1; - - /* Initialize the distance images to be all large values */ - for(i=0; i<w*h; i++) - if(img(i) <= 0.0) - { - distx[i] = 32000; // Large but still representable in a short, and - disty[i] = 32000; // 32000^2 + 32000^2 does not overflow an int - } - else - { - distx[i] = 0; - disty[i] = 0; - } - - /* Perform the transformation */ - do - { - changed = 0; - - /* Scan rows, except first row */ - for(y=1; y<h; y++) - { - - /* move index to leftmost pixel of current row */ - i = y*w; - - /* scan right, propagate distances from above & left */ - - /* Leftmost pixel is special, has no left neighbors */ - olddist2 = DIST(distx[i], disty[i]); - if(olddist2 > 0) // If not already zero distance - { - newdistx = distx[i+offset_u]; - newdisty = disty[i+offset_u]+1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_ur]-1; - newdisty = disty[i+offset_ur]+1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - changed = 1; - } - } - i++; - - /* Middle pixels have all neighbors */ - for(x=1; x<w-1; x++, i++) - { - olddist2 = DIST(distx[i], disty[i]); - if(olddist2 == 0) continue; // Already zero distance - - newdistx = distx[i+offset_l]+1; - newdisty = disty[i+offset_l]; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_lu]+1; - newdisty = disty[i+offset_lu]+1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_u]; - newdisty = disty[i+offset_u]+1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_ur]-1; - newdisty = disty[i+offset_ur]+1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - changed = 1; - } - } - - /* Rightmost pixel of row is special, has no right neighbors */ - olddist2 = DIST(distx[i], disty[i]); - if(olddist2 > 0) // If not already zero distance - { - newdistx = distx[i+offset_l]+1; - newdisty = disty[i+offset_l]; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_lu]+1; - newdisty = disty[i+offset_lu]+1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_u]; - newdisty = disty[i+offset_u]+1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - } - - /* Move index to second rightmost pixel of current row. */ - /* Rightmost pixel is skipped, it has no right neighbor. */ - i = y*w + w-2; - - /* scan left, propagate distance from right */ - for(x=w-2; x>=0; x--, i--) - { - olddist2 = DIST(distx[i], disty[i]); - if(olddist2 == 0) continue; // Already zero distance - - newdistx = distx[i+offset_r]-1; - newdisty = disty[i+offset_r]; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - changed = 1; - } - } - } - - /* Scan rows in reverse order, except last row */ - for(y=h-2; y>=0; y--) - { - /* move index to rightmost pixel of current row */ - i = y*w + w-1; - - /* Scan left, propagate distances from below & right */ - - /* Rightmost pixel is special, has no right neighbors */ - olddist2 = DIST(distx[i], disty[i]); - if(olddist2 > 0) // If not already zero distance - { - newdistx = distx[i+offset_d]; - newdisty = disty[i+offset_d]-1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_dl]+1; - newdisty = disty[i+offset_dl]-1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - changed = 1; - } - } - i--; - - /* Middle pixels have all neighbors */ - for(x=w-2; x>0; x--, i--) - { - olddist2 = DIST(distx[i], disty[i]); - if(olddist2 == 0) continue; // Already zero distance - - newdistx = distx[i+offset_r]-1; - newdisty = disty[i+offset_r]; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_rd]-1; - newdisty = disty[i+offset_rd]-1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_d]; - newdisty = disty[i+offset_d]-1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_dl]+1; - newdisty = disty[i+offset_dl]-1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - changed = 1; - } - } - /* Leftmost pixel is special, has no left neighbors */ - olddist2 = DIST(distx[i], disty[i]); - if(olddist2 > 0) // If not already zero distance - { - newdistx = distx[i+offset_r]-1; - newdisty = disty[i+offset_r]; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_rd]-1; - newdisty = disty[i+offset_rd]-1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - - newdistx = distx[i+offset_d]; - newdisty = disty[i+offset_d]-1; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - olddist2=newdist2; - changed = 1; - } - } - - /* Move index to second leftmost pixel of current row. */ - /* Leftmost pixel is skipped, it has no left neighbor. */ - i = y*w + 1; - for(x=1; x<w; x++, i++) - { - /* scan right, propagate distance from left */ - olddist2 = DIST(distx[i], disty[i]); - if(olddist2 == 0) continue; // Already zero distance - - newdistx = distx[i+offset_l]+1; - newdisty = disty[i+offset_l]; - newdist2 = DIST(newdistx, newdisty); - if(newdist2 < olddist2) - { - distx[i]=newdistx; - disty[i]=newdisty; - changed = 1; - } - } - } - } - while(changed); // Sweep until no more updates are made - - /* The transformation is completed. */ - -}