/tags/R2009-05-08/main/image/src/edtfunc.c

# · C · 379 lines · 280 code · 38 blank · 61 comment · 41 complexity · 218261b4f63755521588bc8c7c826107 MD5 · raw file

  1. // edtfunc.c - Euclidean distance transform of a binary image
  2. /*
  3. Copyright (C) 2009 Stefan Gustavson (stefan.gustavson@gmail.com)
  4. This program is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; either version 3 of the License, or (at your
  7. option) any later version.
  8. This program is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  11. for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with Octave; see the file COPYING. If not, see
  14. <http://www.gnu.org/licenses/>.
  15. */
  16. /*
  17. * This is a sweep-and-update Euclidean distance transform of
  18. * a binary image. All positive pixels are considered object
  19. * pixels, zero or negative pixels are treated as background.
  20. *
  21. * By Stefan Gustavson (stefan.gustavson@gmail.com).
  22. *
  23. * Originally written in 1994, based on paper-only descriptions
  24. * of the SSED8 algorithm, invented by Per-Erik Danielsson
  25. * and improved by Ingemar Ragnemalm. This is a classic algorithm
  26. * with roots in the 1980s, still very good for the 2D case.
  27. *
  28. * Updated in 2004 to treat pixels at image edges correctly,
  29. * and to improve code readability.
  30. *
  31. * Edited in 2009 to form the foundation for Octave BWDIST:
  32. * added #define-configurable distance measure and function name
  33. *
  34. */
  35. #ifndef DIST
  36. #define DIST(x,y) ((int)(x) * (x) + (y) * (y))
  37. #endif
  38. #ifndef FUNCNAME
  39. #define FUNCNAME edt
  40. #endif
  41. void FUNCNAME(const Matrix &img, int w, int h, short *distx, short *disty)
  42. {
  43. int x, y, i;
  44. int offset_u, offset_ur, offset_r, offset_rd,
  45. offset_d, offset_dl, offset_l, offset_lu;
  46. double olddist2, newdist2, newdistx, newdisty;
  47. int changed;
  48. /* Initialize index offsets for the current image width */
  49. offset_u = -w;
  50. offset_ur = -w+1;
  51. offset_r = 1;
  52. offset_rd = w+1;
  53. offset_d = w;
  54. offset_dl = w-1;
  55. offset_l = -1;
  56. offset_lu = -w-1;
  57. /* Initialize the distance images to be all large values */
  58. for(i=0; i<w*h; i++)
  59. if(img(i) <= 0.0)
  60. {
  61. distx[i] = 32000; // Large but still representable in a short, and
  62. disty[i] = 32000; // 32000^2 + 32000^2 does not overflow an int
  63. }
  64. else
  65. {
  66. distx[i] = 0;
  67. disty[i] = 0;
  68. }
  69. /* Perform the transformation */
  70. do
  71. {
  72. changed = 0;
  73. /* Scan rows, except first row */
  74. for(y=1; y<h; y++)
  75. {
  76. /* move index to leftmost pixel of current row */
  77. i = y*w;
  78. /* scan right, propagate distances from above & left */
  79. /* Leftmost pixel is special, has no left neighbors */
  80. olddist2 = DIST(distx[i], disty[i]);
  81. if(olddist2 > 0) // If not already zero distance
  82. {
  83. newdistx = distx[i+offset_u];
  84. newdisty = disty[i+offset_u]+1;
  85. newdist2 = DIST(newdistx, newdisty);
  86. if(newdist2 < olddist2)
  87. {
  88. distx[i]=newdistx;
  89. disty[i]=newdisty;
  90. olddist2=newdist2;
  91. changed = 1;
  92. }
  93. newdistx = distx[i+offset_ur]-1;
  94. newdisty = disty[i+offset_ur]+1;
  95. newdist2 = DIST(newdistx, newdisty);
  96. if(newdist2 < olddist2)
  97. {
  98. distx[i]=newdistx;
  99. disty[i]=newdisty;
  100. changed = 1;
  101. }
  102. }
  103. i++;
  104. /* Middle pixels have all neighbors */
  105. for(x=1; x<w-1; x++, i++)
  106. {
  107. olddist2 = DIST(distx[i], disty[i]);
  108. if(olddist2 == 0) continue; // Already zero distance
  109. newdistx = distx[i+offset_l]+1;
  110. newdisty = disty[i+offset_l];
  111. newdist2 = DIST(newdistx, newdisty);
  112. if(newdist2 < olddist2)
  113. {
  114. distx[i]=newdistx;
  115. disty[i]=newdisty;
  116. olddist2=newdist2;
  117. changed = 1;
  118. }
  119. newdistx = distx[i+offset_lu]+1;
  120. newdisty = disty[i+offset_lu]+1;
  121. newdist2 = DIST(newdistx, newdisty);
  122. if(newdist2 < olddist2)
  123. {
  124. distx[i]=newdistx;
  125. disty[i]=newdisty;
  126. olddist2=newdist2;
  127. changed = 1;
  128. }
  129. newdistx = distx[i+offset_u];
  130. newdisty = disty[i+offset_u]+1;
  131. newdist2 = DIST(newdistx, newdisty);
  132. if(newdist2 < olddist2)
  133. {
  134. distx[i]=newdistx;
  135. disty[i]=newdisty;
  136. olddist2=newdist2;
  137. changed = 1;
  138. }
  139. newdistx = distx[i+offset_ur]-1;
  140. newdisty = disty[i+offset_ur]+1;
  141. newdist2 = DIST(newdistx, newdisty);
  142. if(newdist2 < olddist2)
  143. {
  144. distx[i]=newdistx;
  145. disty[i]=newdisty;
  146. changed = 1;
  147. }
  148. }
  149. /* Rightmost pixel of row is special, has no right neighbors */
  150. olddist2 = DIST(distx[i], disty[i]);
  151. if(olddist2 > 0) // If not already zero distance
  152. {
  153. newdistx = distx[i+offset_l]+1;
  154. newdisty = disty[i+offset_l];
  155. newdist2 = DIST(newdistx, newdisty);
  156. if(newdist2 < olddist2)
  157. {
  158. distx[i]=newdistx;
  159. disty[i]=newdisty;
  160. olddist2=newdist2;
  161. changed = 1;
  162. }
  163. newdistx = distx[i+offset_lu]+1;
  164. newdisty = disty[i+offset_lu]+1;
  165. newdist2 = DIST(newdistx, newdisty);
  166. if(newdist2 < olddist2)
  167. {
  168. distx[i]=newdistx;
  169. disty[i]=newdisty;
  170. olddist2=newdist2;
  171. changed = 1;
  172. }
  173. newdistx = distx[i+offset_u];
  174. newdisty = disty[i+offset_u]+1;
  175. newdist2 = DIST(newdistx, newdisty);
  176. if(newdist2 < olddist2)
  177. {
  178. distx[i]=newdistx;
  179. disty[i]=newdisty;
  180. olddist2=newdist2;
  181. changed = 1;
  182. }
  183. }
  184. /* Move index to second rightmost pixel of current row. */
  185. /* Rightmost pixel is skipped, it has no right neighbor. */
  186. i = y*w + w-2;
  187. /* scan left, propagate distance from right */
  188. for(x=w-2; x>=0; x--, i--)
  189. {
  190. olddist2 = DIST(distx[i], disty[i]);
  191. if(olddist2 == 0) continue; // Already zero distance
  192. newdistx = distx[i+offset_r]-1;
  193. newdisty = disty[i+offset_r];
  194. newdist2 = DIST(newdistx, newdisty);
  195. if(newdist2 < olddist2)
  196. {
  197. distx[i]=newdistx;
  198. disty[i]=newdisty;
  199. changed = 1;
  200. }
  201. }
  202. }
  203. /* Scan rows in reverse order, except last row */
  204. for(y=h-2; y>=0; y--)
  205. {
  206. /* move index to rightmost pixel of current row */
  207. i = y*w + w-1;
  208. /* Scan left, propagate distances from below & right */
  209. /* Rightmost pixel is special, has no right neighbors */
  210. olddist2 = DIST(distx[i], disty[i]);
  211. if(olddist2 > 0) // If not already zero distance
  212. {
  213. newdistx = distx[i+offset_d];
  214. newdisty = disty[i+offset_d]-1;
  215. newdist2 = DIST(newdistx, newdisty);
  216. if(newdist2 < olddist2)
  217. {
  218. distx[i]=newdistx;
  219. disty[i]=newdisty;
  220. olddist2=newdist2;
  221. changed = 1;
  222. }
  223. newdistx = distx[i+offset_dl]+1;
  224. newdisty = disty[i+offset_dl]-1;
  225. newdist2 = DIST(newdistx, newdisty);
  226. if(newdist2 < olddist2)
  227. {
  228. distx[i]=newdistx;
  229. disty[i]=newdisty;
  230. changed = 1;
  231. }
  232. }
  233. i--;
  234. /* Middle pixels have all neighbors */
  235. for(x=w-2; x>0; x--, i--)
  236. {
  237. olddist2 = DIST(distx[i], disty[i]);
  238. if(olddist2 == 0) continue; // Already zero distance
  239. newdistx = distx[i+offset_r]-1;
  240. newdisty = disty[i+offset_r];
  241. newdist2 = DIST(newdistx, newdisty);
  242. if(newdist2 < olddist2)
  243. {
  244. distx[i]=newdistx;
  245. disty[i]=newdisty;
  246. olddist2=newdist2;
  247. changed = 1;
  248. }
  249. newdistx = distx[i+offset_rd]-1;
  250. newdisty = disty[i+offset_rd]-1;
  251. newdist2 = DIST(newdistx, newdisty);
  252. if(newdist2 < olddist2)
  253. {
  254. distx[i]=newdistx;
  255. disty[i]=newdisty;
  256. olddist2=newdist2;
  257. changed = 1;
  258. }
  259. newdistx = distx[i+offset_d];
  260. newdisty = disty[i+offset_d]-1;
  261. newdist2 = DIST(newdistx, newdisty);
  262. if(newdist2 < olddist2)
  263. {
  264. distx[i]=newdistx;
  265. disty[i]=newdisty;
  266. olddist2=newdist2;
  267. changed = 1;
  268. }
  269. newdistx = distx[i+offset_dl]+1;
  270. newdisty = disty[i+offset_dl]-1;
  271. newdist2 = DIST(newdistx, newdisty);
  272. if(newdist2 < olddist2)
  273. {
  274. distx[i]=newdistx;
  275. disty[i]=newdisty;
  276. changed = 1;
  277. }
  278. }
  279. /* Leftmost pixel is special, has no left neighbors */
  280. olddist2 = DIST(distx[i], disty[i]);
  281. if(olddist2 > 0) // If not already zero distance
  282. {
  283. newdistx = distx[i+offset_r]-1;
  284. newdisty = disty[i+offset_r];
  285. newdist2 = DIST(newdistx, newdisty);
  286. if(newdist2 < olddist2)
  287. {
  288. distx[i]=newdistx;
  289. disty[i]=newdisty;
  290. olddist2=newdist2;
  291. changed = 1;
  292. }
  293. newdistx = distx[i+offset_rd]-1;
  294. newdisty = disty[i+offset_rd]-1;
  295. newdist2 = DIST(newdistx, newdisty);
  296. if(newdist2 < olddist2)
  297. {
  298. distx[i]=newdistx;
  299. disty[i]=newdisty;
  300. olddist2=newdist2;
  301. changed = 1;
  302. }
  303. newdistx = distx[i+offset_d];
  304. newdisty = disty[i+offset_d]-1;
  305. newdist2 = DIST(newdistx, newdisty);
  306. if(newdist2 < olddist2)
  307. {
  308. distx[i]=newdistx;
  309. disty[i]=newdisty;
  310. olddist2=newdist2;
  311. changed = 1;
  312. }
  313. }
  314. /* Move index to second leftmost pixel of current row. */
  315. /* Leftmost pixel is skipped, it has no left neighbor. */
  316. i = y*w + 1;
  317. for(x=1; x<w; x++, i++)
  318. {
  319. /* scan right, propagate distance from left */
  320. olddist2 = DIST(distx[i], disty[i]);
  321. if(olddist2 == 0) continue; // Already zero distance
  322. newdistx = distx[i+offset_l]+1;
  323. newdisty = disty[i+offset_l];
  324. newdist2 = DIST(newdistx, newdisty);
  325. if(newdist2 < olddist2)
  326. {
  327. distx[i]=newdistx;
  328. disty[i]=newdisty;
  329. changed = 1;
  330. }
  331. }
  332. }
  333. }
  334. while(changed); // Sweep until no more updates are made
  335. /* The transformation is completed. */
  336. }