| File: | src/nrrd/filt.c |
| Location: | line 671, column 8 |
| Description: | Call to 'calloc' has an allocation size of 0 bytes |
| 1 | /* | |||||
| 2 | Teem: Tools to process and visualize scientific data and images . | |||||
| 3 | Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago | |||||
| 4 | Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann | |||||
| 5 | Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah | |||||
| 6 | ||||||
| 7 | This library is free software; you can redistribute it and/or | |||||
| 8 | modify it under the terms of the GNU Lesser General Public License | |||||
| 9 | (LGPL) as published by the Free Software Foundation; either | |||||
| 10 | version 2.1 of the License, or (at your option) any later version. | |||||
| 11 | The terms of redistributing and/or modifying this software also | |||||
| 12 | include exceptions to the LGPL that facilitate static linking. | |||||
| 13 | ||||||
| 14 | This library is distributed in the hope that it will be useful, | |||||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| 17 | Lesser General Public License for more details. | |||||
| 18 | ||||||
| 19 | You should have received a copy of the GNU Lesser General Public License | |||||
| 20 | along with this library; if not, write to Free Software Foundation, Inc., | |||||
| 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
| 22 | */ | |||||
| 23 | ||||||
| 24 | #include "nrrd.h" | |||||
| 25 | #include "privateNrrd.h" | |||||
| 26 | ||||||
| 27 | int | |||||
| 28 | _nrrdCM_median(const float *hist, float half) { | |||||
| 29 | float sum = 0; | |||||
| 30 | const float *hpt; | |||||
| 31 | ||||||
| 32 | hpt = hist; | |||||
| 33 | ||||||
| 34 | while(sum < half) | |||||
| 35 | sum += *hpt++; | |||||
| 36 | ||||||
| 37 | return AIR_CAST(int, hpt - 1 - hist)((int)(hpt - 1 - hist)); | |||||
| 38 | } | |||||
| 39 | ||||||
| 40 | int | |||||
| 41 | _nrrdCM_mode(const float *hist, int bins) { | |||||
| 42 | float max; | |||||
| 43 | int i, mi; | |||||
| 44 | ||||||
| 45 | mi = -1; | |||||
| 46 | max = 0; | |||||
| 47 | for (i=0; i<bins; i++) { | |||||
| 48 | if (hist[i] && (!max || hist[i] > max) ) { | |||||
| 49 | max = hist[i]; | |||||
| 50 | mi = i; | |||||
| 51 | } | |||||
| 52 | } | |||||
| 53 | ||||||
| 54 | return mi; | |||||
| 55 | } | |||||
| 56 | ||||||
| 57 | #define INDEX(nin, range, lup, idxIn, bins, val)( val = (lup)((nin)->data, (idxIn)), airIndex((range)-> min, (val), (range)->max, bins) ) ( \ | |||||
| 58 | val = (lup)((nin)->data, (idxIn)), \ | |||||
| 59 | airIndex((range)->min, (val), (range)->max, bins) \ | |||||
| 60 | ) | |||||
| 61 | ||||||
| 62 | void | |||||
| 63 | _nrrdCM_printhist(const float *hist, int bins, const char *desc) { | |||||
| 64 | int i; | |||||
| 65 | ||||||
| 66 | printf("%s:\n", desc); | |||||
| 67 | for (i=0; i<bins; i++) { | |||||
| 68 | if (hist[i]) { | |||||
| 69 | printf(" %d: %g\n", i, hist[i]); | |||||
| 70 | } | |||||
| 71 | } | |||||
| 72 | } | |||||
| 73 | ||||||
| 74 | float * | |||||
| 75 | _nrrdCM_wtAlloc(int radius, float wght) { | |||||
| 76 | float *wt, sum; | |||||
| 77 | int diam, r; | |||||
| 78 | ||||||
| 79 | diam = 2*radius + 1; | |||||
| 80 | wt = (float *)calloc(diam, sizeof(float)); | |||||
| 81 | wt[radius] = 1.0; | |||||
| 82 | for (r=1; r<=radius; r++) { | |||||
| 83 | wt[radius+r] = AIR_CAST(float, pow(1.0/wght, r))((float)(pow(1.0/wght, r))); | |||||
| 84 | wt[radius-r] = AIR_CAST(float, pow(1.0/wght, r))((float)(pow(1.0/wght, r))); | |||||
| 85 | } | |||||
| 86 | sum = 0.0; | |||||
| 87 | for (r=0; r<diam; r++) { | |||||
| 88 | sum += wt[r]; | |||||
| 89 | } | |||||
| 90 | for (r=0; r<diam; r++) { | |||||
| 91 | wt[r] /= sum; | |||||
| 92 | } | |||||
| 93 | /* | |||||
| 94 | for (r=0; r<diam; r++) { | |||||
| 95 | fprintf(stderr, "!%s: wt[%d] = %g\n", "_nrrdCM_wtAlloc", r, wt[r]); | |||||
| 96 | } | |||||
| 97 | */ | |||||
| 98 | return wt; | |||||
| 99 | } | |||||
| 100 | ||||||
| 101 | void | |||||
| 102 | _nrrdCheapMedian1D(Nrrd *nout, const Nrrd *nin, const NrrdRange *range, | |||||
| 103 | int radius, float wght, | |||||
| 104 | int bins, int mode, float *hist) { | |||||
| 105 | /* static const char me[]="_nrrdCheapMedian1D"; */ | |||||
| 106 | size_t num; | |||||
| 107 | int X, I, idx, diam; | |||||
| 108 | float half, *wt; | |||||
| 109 | double val, (*lup)(const void *, size_t); | |||||
| 110 | ||||||
| 111 | diam = 2*radius + 1; | |||||
| 112 | lup = nrrdDLookup[nin->type]; | |||||
| 113 | num = nrrdElementNumber(nin); | |||||
| 114 | if (1 == wght) { | |||||
| 115 | /* uniform weighting-> can do sliding histogram optimization */ | |||||
| 116 | /* initialize histogram */ | |||||
| 117 | half = AIR_CAST(float, diam/2 + 1)((float)(diam/2 + 1)); | |||||
| 118 | memset(hist, 0, bins*sizeof(float))__builtin___memset_chk (hist, 0, bins*sizeof(float), __builtin_object_size (hist, 0)); | |||||
| 119 | for (X=0; X<diam; X++) { | |||||
| 120 | hist[INDEX(nin, range, lup, X, bins, val)( val = (lup)((nin)->data, (X)), airIndex((range)->min, (val), (range)->max, bins) )]++; | |||||
| 121 | } | |||||
| 122 | /* _nrrdCM_printhist(hist, bins, "after init"); */ | |||||
| 123 | /* find median at each point using existing histogram */ | |||||
| 124 | for (X=radius; X<(int)num-radius; X++) { | |||||
| 125 | /* _nrrdCM_printhist(hist, bins, "----------"); */ | |||||
| 126 | idx = mode ? _nrrdCM_mode(hist, bins) : _nrrdCM_median(hist, half); | |||||
| 127 | val = NRRD_NODE_POS(range->min, range->max, bins, idx)( ((double)((range->max))-((range->min)))*((double)((idx ))-(0)) / ((double)((bins)-1)-(0)) + ((range->min))); | |||||
| 128 | /* printf(" median idx = %d -> val = %g\n", idx, val); */ | |||||
| 129 | nrrdDInsert[nout->type](nout->data, X, val); | |||||
| 130 | /* probably update histogram for next iteration */ | |||||
| 131 | if (X < (int)num-radius-1) { | |||||
| 132 | hist[INDEX(nin, range, lup, X+radius+1, bins, val)( val = (lup)((nin)->data, (X+radius+1)), airIndex((range) ->min, (val), (range)->max, bins) )]++; | |||||
| 133 | hist[INDEX(nin, range, lup, X-radius, bins, val)( val = (lup)((nin)->data, (X-radius)), airIndex((range)-> min, (val), (range)->max, bins) )]--; | |||||
| 134 | } | |||||
| 135 | } | |||||
| 136 | } else { | |||||
| 137 | /* non-uniform weighting --> slow and stupid */ | |||||
| 138 | wt = _nrrdCM_wtAlloc(radius, wght); | |||||
| 139 | half = 0.5; | |||||
| 140 | for (X=radius; X<(int)num-radius; X++) { | |||||
| 141 | memset(hist, 0, bins*sizeof(float))__builtin___memset_chk (hist, 0, bins*sizeof(float), __builtin_object_size (hist, 0)); | |||||
| 142 | for (I=-radius; I<=radius; I++) { | |||||
| 143 | hist[INDEX(nin, range, lup, I+X, bins, val)( val = (lup)((nin)->data, (I+X)), airIndex((range)->min , (val), (range)->max, bins) )] += wt[I+radius]; | |||||
| 144 | } | |||||
| 145 | idx = mode ? _nrrdCM_mode(hist, bins) : _nrrdCM_median(hist, half); | |||||
| 146 | val = NRRD_NODE_POS(range->min, range->max, bins, idx)( ((double)((range->max))-((range->min)))*((double)((idx ))-(0)) / ((double)((bins)-1)-(0)) + ((range->min))); | |||||
| 147 | nrrdDInsert[nout->type](nout->data, X, val); | |||||
| 148 | } | |||||
| 149 | free(wt); | |||||
| 150 | } | |||||
| 151 | } | |||||
| 152 | ||||||
| 153 | void | |||||
| 154 | _nrrdCheapMedian2D(Nrrd *nout, const Nrrd *nin, const NrrdRange *range, | |||||
| 155 | int radius, float wght, | |||||
| 156 | int bins, int mode, float *hist) { | |||||
| 157 | /* static const char me[]="_nrrdCheapMedian2D"; */ | |||||
| 158 | int X, Y, I, J; | |||||
| 159 | int sx, sy, idx, diam; | |||||
| 160 | float half, *wt; | |||||
| 161 | double val, (*lup)(const void *, size_t); | |||||
| 162 | ||||||
| 163 | diam = 2*radius + 1; | |||||
| 164 | sx = AIR_CAST(unsigned int, nin->axis[0].size)((unsigned int)(nin->axis[0].size)); | |||||
| 165 | sy = AIR_CAST(unsigned int, nin->axis[1].size)((unsigned int)(nin->axis[1].size)); | |||||
| 166 | lup = nrrdDLookup[nin->type]; | |||||
| 167 | if (1 == wght) { | |||||
| 168 | /* uniform weighting-> can do sliding histogram optimization */ | |||||
| 169 | half = AIR_CAST(float, diam*diam/2 + 1)((float)(diam*diam/2 + 1)); | |||||
| 170 | for (Y=radius; Y<sy-radius; Y++) { | |||||
| 171 | /* initialize histogram */ | |||||
| 172 | memset(hist, 0, bins*sizeof(float))__builtin___memset_chk (hist, 0, bins*sizeof(float), __builtin_object_size (hist, 0)); | |||||
| 173 | X = radius; | |||||
| 174 | for (J=-radius; J<=radius; J++) { | |||||
| 175 | for (I=-radius; I<=radius; I++) { | |||||
| 176 | hist[INDEX(nin, range, lup, X+I + sx*(J+Y), bins, val)( val = (lup)((nin)->data, (X+I + sx*(J+Y))), airIndex((range )->min, (val), (range)->max, bins) )]++; | |||||
| 177 | } | |||||
| 178 | } | |||||
| 179 | /* _nrrdCM_printhist(hist, bins, "after init"); */ | |||||
| 180 | /* find median at each point using existing histogram */ | |||||
| 181 | for (X=radius; X<sx-radius; X++) { | |||||
| 182 | idx = mode ? _nrrdCM_mode(hist, bins) : _nrrdCM_median(hist, half); | |||||
| 183 | val = NRRD_NODE_POS(range->min, range->max, bins, idx)( ((double)((range->max))-((range->min)))*((double)((idx ))-(0)) / ((double)((bins)-1)-(0)) + ((range->min))); | |||||
| 184 | nrrdDInsert[nout->type](nout->data, X + sx*Y, val); | |||||
| 185 | /* probably update histogram for next iteration */ | |||||
| 186 | if (X < sx-radius-1) { | |||||
| 187 | for (J=-radius; J<=radius; J++) { | |||||
| 188 | hist[INDEX(nin, range, lup, X+radius+1 + sx*(J+Y), bins, val)( val = (lup)((nin)->data, (X+radius+1 + sx*(J+Y))), airIndex ((range)->min, (val), (range)->max, bins) )]++; | |||||
| 189 | hist[INDEX(nin, range, lup, X-radius + sx*(J+Y), bins, val)( val = (lup)((nin)->data, (X-radius + sx*(J+Y))), airIndex ((range)->min, (val), (range)->max, bins) )]--; | |||||
| 190 | } | |||||
| 191 | } | |||||
| 192 | } | |||||
| 193 | } | |||||
| 194 | } else { | |||||
| 195 | /* non-uniform weighting --> slow and stupid */ | |||||
| 196 | wt = _nrrdCM_wtAlloc(radius, wght); | |||||
| 197 | half = 0.5; | |||||
| 198 | for (Y=radius; Y<sy-radius; Y++) { | |||||
| 199 | for (X=radius; X<sx-radius; X++) { | |||||
| 200 | memset(hist, 0, bins*sizeof(float))__builtin___memset_chk (hist, 0, bins*sizeof(float), __builtin_object_size (hist, 0)); | |||||
| 201 | for (J=-radius; J<=radius; J++) { | |||||
| 202 | for (I=-radius; I<=radius; I++) { | |||||
| 203 | hist[INDEX(nin, range, lup, I+X + sx*(J+Y),( val = (lup)((nin)->data, (I+X + sx*(J+Y))), airIndex((range )->min, (val), (range)->max, bins) ) | |||||
| 204 | bins, val)( val = (lup)((nin)->data, (I+X + sx*(J+Y))), airIndex((range )->min, (val), (range)->max, bins) )] += wt[I+radius]*wt[J+radius]; | |||||
| 205 | } | |||||
| 206 | } | |||||
| 207 | idx = mode ? _nrrdCM_mode(hist, bins) : _nrrdCM_median(hist, half); | |||||
| 208 | val = NRRD_NODE_POS(range->min, range->max, bins, idx)( ((double)((range->max))-((range->min)))*((double)((idx ))-(0)) / ((double)((bins)-1)-(0)) + ((range->min))); | |||||
| 209 | nrrdDInsert[nout->type](nout->data, X + sx*Y, val); | |||||
| 210 | } | |||||
| 211 | } | |||||
| 212 | free(wt); | |||||
| 213 | } | |||||
| 214 | } | |||||
| 215 | ||||||
| 216 | void | |||||
| 217 | _nrrdCheapMedian3D(Nrrd *nout, const Nrrd *nin, const NrrdRange *range, | |||||
| 218 | int radius, float wght, | |||||
| 219 | int bins, int mode, float *hist) { | |||||
| 220 | static const char me[]="_nrrdCheapMedian3D"; | |||||
| 221 | char done[13]; | |||||
| 222 | int X, Y, Z, I, J, K; | |||||
| 223 | int sx, sy, sz, idx, diam; | |||||
| 224 | float half, *wt; | |||||
| 225 | double val, (*lup)(const void *, size_t); | |||||
| 226 | ||||||
| 227 | diam = 2*radius + 1; | |||||
| 228 | sx = AIR_CAST(int, nin->axis[0].size)((int)(nin->axis[0].size)); | |||||
| 229 | sy = AIR_CAST(int, nin->axis[1].size)((int)(nin->axis[1].size)); | |||||
| 230 | sz = AIR_CAST(int, nin->axis[2].size)((int)(nin->axis[2].size)); | |||||
| 231 | lup = nrrdDLookup[nin->type]; | |||||
| 232 | fprintf(stderr__stderrp, "%s: ... ", me); | |||||
| 233 | if (1 == wght) { | |||||
| 234 | /* uniform weighting-> can do sliding histogram optimization */ | |||||
| 235 | half = AIR_CAST(float, diam*diam*diam/2 + 1)((float)(diam*diam*diam/2 + 1)); | |||||
| 236 | fflush(stderr__stderrp); | |||||
| 237 | for (Z=radius; Z<sz-radius; Z++) { | |||||
| 238 | fprintf(stderr__stderrp, "%s", airDoneStr(radius, Z, sz-radius-1, done)); | |||||
| 239 | fflush(stderr__stderrp); | |||||
| 240 | for (Y=radius; Y<sy-radius; Y++) { | |||||
| 241 | /* initialize histogram */ | |||||
| 242 | memset(hist, 0, bins*sizeof(float))__builtin___memset_chk (hist, 0, bins*sizeof(float), __builtin_object_size (hist, 0)); | |||||
| 243 | X = radius; | |||||
| 244 | for (K=-radius; K<=radius; K++) { | |||||
| 245 | for (J=-radius; J<=radius; J++) { | |||||
| 246 | for (I=-radius; I<=radius; I++) { | |||||
| 247 | hist[INDEX(nin, range, lup, I+X + sx*(J+Y + sy*(K+Z)),( val = (lup)((nin)->data, (I+X + sx*(J+Y + sy*(K+Z)))), airIndex ((range)->min, (val), (range)->max, bins) ) | |||||
| 248 | bins, val)( val = (lup)((nin)->data, (I+X + sx*(J+Y + sy*(K+Z)))), airIndex ((range)->min, (val), (range)->max, bins) )]++; | |||||
| 249 | } | |||||
| 250 | } | |||||
| 251 | } | |||||
| 252 | /* find median at each point using existing histogram */ | |||||
| 253 | for (X=radius; X<sx-radius; X++) { | |||||
| 254 | idx = mode ? _nrrdCM_mode(hist, bins) : _nrrdCM_median(hist, half); | |||||
| 255 | val = NRRD_NODE_POS(range->min, range->max, bins, idx)( ((double)((range->max))-((range->min)))*((double)((idx ))-(0)) / ((double)((bins)-1)-(0)) + ((range->min))); | |||||
| 256 | nrrdDInsert[nout->type](nout->data, X + sx*(Y + sy*Z), val); | |||||
| 257 | /* probably update histogram for next iteration */ | |||||
| 258 | if (X < sx-radius-1) { | |||||
| 259 | for (K=-radius; K<=radius; K++) { | |||||
| 260 | for (J=-radius; J<=radius; J++) { | |||||
| 261 | hist[INDEX(nin, range, lup, X+radius+1 + sx*(J+Y + sy*(K+Z)),( val = (lup)((nin)->data, (X+radius+1 + sx*(J+Y + sy*(K+Z )))), airIndex((range)->min, (val), (range)->max, bins) ) | |||||
| 262 | bins, val)( val = (lup)((nin)->data, (X+radius+1 + sx*(J+Y + sy*(K+Z )))), airIndex((range)->min, (val), (range)->max, bins) )]++; | |||||
| 263 | hist[INDEX(nin, range, lup, X-radius + sx*(J+Y + sy*(K+Z)),( val = (lup)((nin)->data, (X-radius + sx*(J+Y + sy*(K+Z)) )), airIndex((range)->min, (val), (range)->max, bins) ) | |||||
| 264 | bins, val)( val = (lup)((nin)->data, (X-radius + sx*(J+Y + sy*(K+Z)) )), airIndex((range)->min, (val), (range)->max, bins) )]--; | |||||
| 265 | } | |||||
| 266 | } | |||||
| 267 | } | |||||
| 268 | } | |||||
| 269 | } | |||||
| 270 | } | |||||
| 271 | } else { | |||||
| 272 | /* non-uniform weighting --> slow and stupid */ | |||||
| 273 | wt = _nrrdCM_wtAlloc(radius, wght); | |||||
| 274 | half = 0.5; | |||||
| 275 | for (Z=radius; Z<sz-radius; Z++) { | |||||
| 276 | fprintf(stderr__stderrp, "%s", airDoneStr(radius, Z, sz-radius-1, done)); | |||||
| 277 | fflush(stderr__stderrp); | |||||
| 278 | for (Y=radius; Y<sy-radius; Y++) { | |||||
| 279 | for (X=radius; X<sx-radius; X++) { | |||||
| 280 | memset(hist, 0, bins*sizeof(float))__builtin___memset_chk (hist, 0, bins*sizeof(float), __builtin_object_size (hist, 0)); | |||||
| 281 | for (K=-radius; K<=radius; K++) { | |||||
| 282 | for (J=-radius; J<=radius; J++) { | |||||
| 283 | for (I=-radius; I<=radius; I++) { | |||||
| 284 | hist[INDEX(nin, range, lup, I+X + sx*(J+Y + sy*(K+Z)),( val = (lup)((nin)->data, (I+X + sx*(J+Y + sy*(K+Z)))), airIndex ((range)->min, (val), (range)->max, bins) ) | |||||
| 285 | bins, val)( val = (lup)((nin)->data, (I+X + sx*(J+Y + sy*(K+Z)))), airIndex ((range)->min, (val), (range)->max, bins) )] | |||||
| 286 | += wt[I+radius]*wt[J+radius]*wt[K+radius]; | |||||
| 287 | } | |||||
| 288 | } | |||||
| 289 | } | |||||
| 290 | idx = mode ? _nrrdCM_mode(hist, bins) : _nrrdCM_median(hist, half); | |||||
| 291 | val = NRRD_NODE_POS(range->min, range->max, bins, idx)( ((double)((range->max))-((range->min)))*((double)((idx ))-(0)) / ((double)((bins)-1)-(0)) + ((range->min))); | |||||
| 292 | nrrdDInsert[nout->type](nout->data, X + sx*(Y + sy*Z), val); | |||||
| 293 | } | |||||
| 294 | } | |||||
| 295 | } | |||||
| 296 | free(wt); | |||||
| 297 | } | |||||
| 298 | fprintf(stderr__stderrp, "\b\b\b\b\b\b done\n"); | |||||
| 299 | } | |||||
| 300 | ||||||
| 301 | /* HEY: total copy-and-paste from _nrrdCheapMedian3D */ | |||||
| 302 | void | |||||
| 303 | _nrrdCheapMedian4D(Nrrd *nout, const Nrrd *nin, const NrrdRange *range, | |||||
| 304 | int radius, float wght, | |||||
| 305 | int bins, int mode, float *hist) { | |||||
| 306 | static const char me[]="_nrrdCheapMedian4D"; | |||||
| 307 | char done[13]; | |||||
| 308 | int W, X, Y, Z, H, I, J, K; | |||||
| 309 | int sw, sx, sy, sz, idx, diam; | |||||
| 310 | float half, *wt; | |||||
| 311 | double val, (*lup)(const void *, size_t); | |||||
| 312 | ||||||
| 313 | diam = 2*radius + 1; | |||||
| 314 | sw = AIR_CAST(int, nin->axis[0].size)((int)(nin->axis[0].size)); | |||||
| 315 | sx = AIR_CAST(int, nin->axis[1].size)((int)(nin->axis[1].size)); | |||||
| 316 | sy = AIR_CAST(int, nin->axis[2].size)((int)(nin->axis[2].size)); | |||||
| 317 | sz = AIR_CAST(int, nin->axis[3].size)((int)(nin->axis[3].size)); | |||||
| 318 | lup = nrrdDLookup[nin->type]; | |||||
| 319 | fprintf(stderr__stderrp, "%s: ... ", me); | |||||
| 320 | if (1 == wght) { | |||||
| 321 | /* uniform weighting-> can do sliding histogram optimization */ | |||||
| 322 | half = AIR_CAST(float, diam*diam*diam*diam/2 + 1)((float)(diam*diam*diam*diam/2 + 1)); | |||||
| 323 | fflush(stderr__stderrp); | |||||
| 324 | for (Z=radius; Z<sz-radius; Z++) { | |||||
| 325 | fprintf(stderr__stderrp, "%s", airDoneStr(radius, Z, sz-radius-1, done)); | |||||
| 326 | fflush(stderr__stderrp); | |||||
| 327 | for (Y=radius; Y<sy-radius; Y++) { | |||||
| 328 | for (X=radius; X<sx-radius; X++) { | |||||
| 329 | /* initialize histogram */ | |||||
| 330 | memset(hist, 0, bins*sizeof(float))__builtin___memset_chk (hist, 0, bins*sizeof(float), __builtin_object_size (hist, 0)); | |||||
| 331 | W = radius; | |||||
| 332 | for (K=-radius; K<=radius; K++) { | |||||
| 333 | for (J=-radius; J<=radius; J++) { | |||||
| 334 | for (I=-radius; I<=radius; I++) { | |||||
| 335 | for (H=-radius; H<=radius; H++) { | |||||
| 336 | hist[INDEX(nin, range, lup,( val = (lup)((nin)->data, (H+W + sw*(I+X + sx*(J+Y + sy*( K+Z))))), airIndex((range)->min, (val), (range)->max, bins ) ) | |||||
| 337 | H+W + sw*(I+X + sx*(J+Y + sy*(K+Z))),( val = (lup)((nin)->data, (H+W + sw*(I+X + sx*(J+Y + sy*( K+Z))))), airIndex((range)->min, (val), (range)->max, bins ) ) | |||||
| 338 | bins, val)( val = (lup)((nin)->data, (H+W + sw*(I+X + sx*(J+Y + sy*( K+Z))))), airIndex((range)->min, (val), (range)->max, bins ) )]++; | |||||
| 339 | } | |||||
| 340 | } | |||||
| 341 | } | |||||
| 342 | } | |||||
| 343 | /* find median at each point using existing histogram */ | |||||
| 344 | for (W=radius; W<sw-radius; W++) { | |||||
| 345 | idx = mode ? _nrrdCM_mode(hist, bins) : _nrrdCM_median(hist, half); | |||||
| 346 | val = NRRD_NODE_POS(range->min, range->max, bins, idx)( ((double)((range->max))-((range->min)))*((double)((idx ))-(0)) / ((double)((bins)-1)-(0)) + ((range->min))); | |||||
| 347 | nrrdDInsert[nout->type](nout->data, W + sw*(X + sx*(Y + sy*Z)), val); | |||||
| 348 | /* probably update histogram for next iteration */ | |||||
| 349 | if (W < sw-radius-1) { | |||||
| 350 | for (K=-radius; K<=radius; K++) { | |||||
| 351 | for (J=-radius; J<=radius; J++) { | |||||
| 352 | for (I=-radius; I<=radius; I++) { | |||||
| 353 | hist[INDEX(nin, range, lup, W+radius+1 + sw*(I+X + sx*(J+Y + sy*(K+Z))),( val = (lup)((nin)->data, (W+radius+1 + sw*(I+X + sx*(J+Y + sy*(K+Z))))), airIndex((range)->min, (val), (range)-> max, bins) ) | |||||
| 354 | bins, val)( val = (lup)((nin)->data, (W+radius+1 + sw*(I+X + sx*(J+Y + sy*(K+Z))))), airIndex((range)->min, (val), (range)-> max, bins) )]++; | |||||
| 355 | hist[INDEX(nin, range, lup, W-radius + sw*(I+X + sx*(J+Y + sy*(K+Z))),( val = (lup)((nin)->data, (W-radius + sw*(I+X + sx*(J+Y + sy*(K+Z))))), airIndex((range)->min, (val), (range)->max , bins) ) | |||||
| 356 | bins, val)( val = (lup)((nin)->data, (W-radius + sw*(I+X + sx*(J+Y + sy*(K+Z))))), airIndex((range)->min, (val), (range)->max , bins) )]--; | |||||
| 357 | } | |||||
| 358 | } | |||||
| 359 | } | |||||
| 360 | } | |||||
| 361 | } | |||||
| 362 | } | |||||
| 363 | } | |||||
| 364 | } | |||||
| 365 | } else { | |||||
| 366 | /* non-uniform weighting --> slow and stupid */ | |||||
| 367 | wt = _nrrdCM_wtAlloc(radius, wght); | |||||
| 368 | half = 0.5; | |||||
| 369 | for (Z=radius; Z<sz-radius; Z++) { | |||||
| 370 | fprintf(stderr__stderrp, "%s", airDoneStr(radius, Z, sz-radius-1, done)); | |||||
| 371 | fflush(stderr__stderrp); | |||||
| 372 | for (Y=radius; Y<sy-radius; Y++) { | |||||
| 373 | for (X=radius; X<sx-radius; X++) { | |||||
| 374 | for (W=radius; W<sw-radius; W++) { | |||||
| 375 | memset(hist, 0, bins*sizeof(float))__builtin___memset_chk (hist, 0, bins*sizeof(float), __builtin_object_size (hist, 0)); | |||||
| 376 | for (K=-radius; K<=radius; K++) { | |||||
| 377 | for (J=-radius; J<=radius; J++) { | |||||
| 378 | for (I=-radius; I<=radius; I++) { | |||||
| 379 | for (H=-radius; H<=radius; H++) { | |||||
| 380 | hist[INDEX(nin, range, lup,( val = (lup)((nin)->data, (H+W + sw*(I+X + sx*(J+Y + sy*( K+Z))))), airIndex((range)->min, (val), (range)->max, bins ) ) | |||||
| 381 | H+W + sw*(I+X + sx*(J+Y + sy*(K+Z))),( val = (lup)((nin)->data, (H+W + sw*(I+X + sx*(J+Y + sy*( K+Z))))), airIndex((range)->min, (val), (range)->max, bins ) ) | |||||
| 382 | bins, val)( val = (lup)((nin)->data, (H+W + sw*(I+X + sx*(J+Y + sy*( K+Z))))), airIndex((range)->min, (val), (range)->max, bins ) )] | |||||
| 383 | += wt[H+radius]*wt[I+radius]*wt[J+radius]*wt[K+radius]; | |||||
| 384 | } | |||||
| 385 | } | |||||
| 386 | } | |||||
| 387 | } | |||||
| 388 | idx = mode ? _nrrdCM_mode(hist, bins) : _nrrdCM_median(hist, half); | |||||
| 389 | val = NRRD_NODE_POS(range->min, range->max, bins, idx)( ((double)((range->max))-((range->min)))*((double)((idx ))-(0)) / ((double)((bins)-1)-(0)) + ((range->min))); | |||||
| 390 | nrrdDInsert[nout->type](nout->data, W + sw*(X + sx*(Y + sy*Z)), val); | |||||
| 391 | } | |||||
| 392 | } | |||||
| 393 | } | |||||
| 394 | } | |||||
| 395 | free(wt); | |||||
| 396 | } | |||||
| 397 | fprintf(stderr__stderrp, "\b\b\b\b\b\b done\n"); | |||||
| 398 | } | |||||
| 399 | ||||||
| 400 | /* | |||||
| 401 | ******** nrrdCheapMedian | |||||
| 402 | ** | |||||
| 403 | ** histogram-based median or mode filtering | |||||
| 404 | ** !mode: median filtering | |||||
| 405 | ** mode: mode filtering | |||||
| 406 | */ | |||||
| 407 | int | |||||
| 408 | nrrdCheapMedian(Nrrd *_nout, const Nrrd *_nin, | |||||
| 409 | int pad, int mode, | |||||
| 410 | unsigned int radius, float wght, unsigned int bins) { | |||||
| 411 | static const char me[]="nrrdCheapMedian", func[]="cmedian"; | |||||
| 412 | NrrdRange *range; | |||||
| 413 | float *hist; | |||||
| 414 | Nrrd *nout, *nin; | |||||
| 415 | airArray *mop; | |||||
| 416 | unsigned int minsize; | |||||
| 417 | ||||||
| 418 | if (!(_nin && _nout)) { | |||||
| 419 | biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer", me); | |||||
| 420 | return 1; | |||||
| 421 | } | |||||
| 422 | if (!(radius >= 1)) { | |||||
| 423 | biffAddf(NRRDnrrdBiffKey, "%s: need radius >= 1 (got %d)", me, radius); | |||||
| 424 | return 1; | |||||
| 425 | } | |||||
| 426 | if (!(bins >= 1)) { | |||||
| 427 | biffAddf(NRRDnrrdBiffKey, "%s: need bins >= 1 (got %d)", me, bins); | |||||
| 428 | return 1; | |||||
| 429 | } | |||||
| 430 | if (!(AIR_IN_CL(1, _nin->dim, 4)((1) <= (_nin->dim) && (_nin->dim) <= (4) ))) { | |||||
| 431 | biffAddf(NRRDnrrdBiffKey, "%s: sorry, can only handle dim 1, 2, 3 (not %d)", | |||||
| 432 | me, _nin->dim); | |||||
| 433 | return 1; | |||||
| 434 | } | |||||
| 435 | minsize = AIR_CAST(unsigned int, _nin->axis[0].size)((unsigned int)(_nin->axis[0].size)); | |||||
| 436 | if (_nin->dim > 1) { | |||||
| 437 | minsize = AIR_MIN(minsize, AIR_CAST(unsigned int, _nin->axis[1].size))((minsize) < (((unsigned int)(_nin->axis[1].size))) ? ( minsize) : (((unsigned int)(_nin->axis[1].size)))); | |||||
| 438 | } | |||||
| 439 | if (_nin->dim > 2) { | |||||
| 440 | minsize = AIR_MIN(minsize, AIR_CAST(unsigned int, _nin->axis[2].size))((minsize) < (((unsigned int)(_nin->axis[2].size))) ? ( minsize) : (((unsigned int)(_nin->axis[2].size)))); | |||||
| 441 | } | |||||
| 442 | if (!pad && minsize < 2*radius+1) { | |||||
| 443 | biffAddf(NRRDnrrdBiffKey, "%s: minimum nrrd size (%d) smaller than filtering " | |||||
| 444 | "window size (%d) with radius %d; must enable padding", me, | |||||
| 445 | minsize, 2*radius+1, radius); | |||||
| 446 | return 1; | |||||
| 447 | } | |||||
| 448 | if (_nout == _nin) { | |||||
| 449 | biffAddf(NRRDnrrdBiffKey, "%s: nout==nin disallowed", me); | |||||
| 450 | return 1; | |||||
| 451 | } | |||||
| 452 | if (nrrdTypeBlock == _nin->type) { | |||||
| 453 | biffAddf(NRRDnrrdBiffKey, "%s: can't filter nrrd type %s", me, | |||||
| 454 | airEnumStr(nrrdType, nrrdTypeBlock)); | |||||
| 455 | return 1; | |||||
| 456 | } | |||||
| 457 | ||||||
| 458 | mop = airMopNew(); | |||||
| 459 | /* set nin based on _nin */ | |||||
| 460 | airMopAdd(mop, nin=nrrdNew(), (airMopper)nrrdNuke, airMopAlways); | |||||
| 461 | if (pad) { | |||||
| 462 | airMopAdd(mop, nout=nrrdNew(), (airMopper)nrrdNuke, airMopAlways); | |||||
| 463 | if (nrrdSimplePad_va(nin, _nin, radius, nrrdBoundaryBleed)) { | |||||
| 464 | biffAddf(NRRDnrrdBiffKey, "%s: trouble padding input", me); | |||||
| 465 | airMopError(mop); return 1; | |||||
| 466 | } | |||||
| 467 | } else { | |||||
| 468 | if (nrrdCopy(nin, _nin)) { | |||||
| 469 | biffAddf(NRRDnrrdBiffKey, "%s: trouble copying input", me); | |||||
| 470 | airMopError(mop); return 1; | |||||
| 471 | } | |||||
| 472 | nout = _nout; | |||||
| 473 | } | |||||
| 474 | if (nrrdCopy(nout, nin)) { | |||||
| 475 | biffAddf(NRRDnrrdBiffKey, "%s: failed to create initial copy of input", me); | |||||
| 476 | airMopError(mop); return 1; | |||||
| 477 | } | |||||
| 478 | range = nrrdRangeNewSet(nin, nrrdBlind8BitRangeFalse); | |||||
| 479 | airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); | |||||
| 480 | if (!(hist = (float*)calloc(bins, sizeof(float)))) { | |||||
| 481 | biffAddf(NRRDnrrdBiffKey, "%s: couldn't allocate histogram (%d bins)", me, bins); | |||||
| 482 | airMopError(mop); return 1; | |||||
| 483 | } | |||||
| 484 | airMopAdd(mop, hist, airFree, airMopAlways); | |||||
| 485 | if (!AIR_EXISTS(wght)(((int)(!((wght) - (wght)))))) { | |||||
| 486 | wght = 1.0; | |||||
| 487 | } | |||||
| 488 | switch (nin->dim) { | |||||
| 489 | case 1: | |||||
| 490 | _nrrdCheapMedian1D(nout, nin, range, radius, wght, bins, mode, hist); | |||||
| 491 | break; | |||||
| 492 | case 2: | |||||
| 493 | _nrrdCheapMedian2D(nout, nin, range, radius, wght, bins, mode, hist); | |||||
| 494 | break; | |||||
| 495 | case 3: | |||||
| 496 | _nrrdCheapMedian3D(nout, nin, range, radius, wght, bins, mode, hist); | |||||
| 497 | break; | |||||
| 498 | case 4: | |||||
| 499 | _nrrdCheapMedian4D(nout, nin, range, radius, wght, bins, mode, hist); | |||||
| 500 | break; | |||||
| 501 | default: | |||||
| 502 | biffAddf(NRRDnrrdBiffKey, "%s: sorry, %d-dimensional median unimplemented", | |||||
| 503 | me, nin->dim); | |||||
| 504 | airMopError(mop); return 1; | |||||
| 505 | } | |||||
| 506 | ||||||
| 507 | nrrdAxisInfoCopy(nout, nin, NULL((void*)0), NRRD_AXIS_INFO_NONE0); | |||||
| 508 | if (nrrdContentSet_va(nout, func, nin, "%d,%d,%g,%d", | |||||
| 509 | mode, radius, wght, bins)) { | |||||
| 510 | biffAddf(NRRDnrrdBiffKey, "%s:", me); | |||||
| 511 | airMopError(mop); return 1; | |||||
| 512 | } | |||||
| 513 | /* basic info handled by nrrdCopy above */ | |||||
| 514 | ||||||
| 515 | /* set _nout based on nout */ | |||||
| 516 | if (pad) { | |||||
| 517 | if (nrrdSimpleCrop(_nout, nout, radius)) { | |||||
| 518 | biffAddf(NRRDnrrdBiffKey, "%s: trouble cropping output", me); | |||||
| 519 | airMopError(mop); return 1; | |||||
| 520 | } | |||||
| 521 | } else { | |||||
| 522 | /* we've already set output in _nout == nout */ | |||||
| 523 | } | |||||
| 524 | ||||||
| 525 | airMopOkay(mop); | |||||
| 526 | return 0; | |||||
| 527 | } | |||||
| 528 | ||||||
| 529 | /* | |||||
| 530 | ** returns intersection of parabolas c(x) = spc^2 (x - xi)^2 + yi | |||||
| 531 | */ | |||||
| 532 | static double | |||||
| 533 | intx(double xx0, double yy0, double xx1, double yy1, double spc) { | |||||
| 534 | double ss; | |||||
| 535 | ||||||
| 536 | ss = spc*spc; | |||||
| 537 | return (yy1/ss + xx1*xx1 - (yy0/ss + xx0*xx0))/(2*(xx1 - xx0)); | |||||
| 538 | } | |||||
| 539 | ||||||
| 540 | /* | |||||
| 541 | ** squared-distance transform of single scanline | |||||
| 542 | ** | |||||
| 543 | ** based on code published with: | |||||
| 544 | ** Distance Transforms of Sampled Functions | |||||
| 545 | ** Pedro F. Felzenszwalb and Daniel P. Huttenlocher | |||||
| 546 | ** Cornell Computing and Information Science TR2004-1963 | |||||
| 547 | ** | |||||
| 548 | ** dd: output (pre-allocated for "len") | |||||
| 549 | ** ff: input function (pre-allocated for "len") | |||||
| 550 | ** zz: buffer (pre-allocated for "len"+1) for locations of | |||||
| 551 | ** boundaries between parabolas | |||||
| 552 | ** vv: buffer (pre-allocated for "len") for locations of | |||||
| 553 | ** parabolas in lower envelope | |||||
| 554 | ** | |||||
| 555 | ** The major modification from the published method is the inclusion | |||||
| 556 | ** of the "spc" parameter that gives the inter-sample spacing, so that | |||||
| 557 | ** the multi-dimensional version can work on non-isotropic samples. | |||||
| 558 | ** | |||||
| 559 | ** FLT_MIN and FLT_MAX are used to be consistent with the | |||||
| 560 | ** initialization in nrrdDistanceL2(), which uses FLT_MAX | |||||
| 561 | ** to be compatible with the case of using floats | |||||
| 562 | */ | |||||
| 563 | static void | |||||
| 564 | distanceL2Sqrd1D(double *dd, const double *ff, | |||||
| 565 | double *zz, unsigned int *vv, | |||||
| 566 | size_t len, double spc) { | |||||
| 567 | size_t kk, qq; | |||||
| 568 | ||||||
| 569 | if (!( dd && ff && zz && vv && len > 0 )) { | |||||
| 570 | /* error */ | |||||
| 571 | return; | |||||
| 572 | } | |||||
| 573 | ||||||
| 574 | kk = 0; | |||||
| 575 | vv[0] = 0; | |||||
| 576 | zz[0] = -FLT_MAX3.40282347e+38F; | |||||
| 577 | zz[1] = +FLT_MAX3.40282347e+38F; | |||||
| 578 | for (qq=1; qq<len; qq++) { | |||||
| 579 | double ss; | |||||
| 580 | ss = intx(AIR_CAST(double, qq)((double)(qq)), ff[qq], vv[kk], ff[vv[kk]], spc); | |||||
| 581 | /* while (ss <= zz[kk]) { | |||||
| 582 | ** HEY this can have kk going to -1 and into memory errors! | |||||
| 583 | */ | |||||
| 584 | while (ss <= zz[kk] && kk) { | |||||
| 585 | kk--; | |||||
| 586 | ss = intx(AIR_CAST(double, qq)((double)(qq)), ff[qq], vv[kk], ff[vv[kk]], spc); | |||||
| 587 | } | |||||
| 588 | kk++; | |||||
| 589 | vv[kk] = AIR_CAST(unsigned int, qq)((unsigned int)(qq)); | |||||
| 590 | zz[kk] = ss; | |||||
| 591 | zz[kk+1] = +FLT_MAX3.40282347e+38F; | |||||
| 592 | } | |||||
| 593 | ||||||
| 594 | kk = 0; | |||||
| 595 | for (qq=00; qq<len; qq++) { | |||||
| 596 | double dx; | |||||
| 597 | while (zz[kk+1] < qq) { | |||||
| 598 | kk++; | |||||
| 599 | } | |||||
| 600 | /* cast to avoid overflow weirdness on the unsigned ints */ | |||||
| 601 | dx = AIR_CAST(double, qq)((double)(qq)) - vv[kk]; | |||||
| 602 | dd[qq] = spc*spc*dx*dx + ff[vv[kk]]; | |||||
| 603 | } | |||||
| 604 | ||||||
| 605 | return; | |||||
| 606 | } | |||||
| 607 | ||||||
| 608 | static int | |||||
| 609 | distanceL2Sqrd(Nrrd *ndist, double *spcMean) { | |||||
| 610 | static const char me[]="distanceL2Sqrd"; | |||||
| 611 | size_t sizeMax; /* max size of all axes */ | |||||
| 612 | Nrrd *ntmpA, *ntmpB, *npass[NRRD_DIM_MAX16+1]; | |||||
| 613 | int spcSomeExist, spcSomeNonExist; | |||||
| 614 | unsigned int di, *vv; | |||||
| 615 | double *dd, *ff, *zz; | |||||
| 616 | double spc[NRRD_DIM_MAX16], vector[NRRD_SPACE_DIM_MAX8]; | |||||
| 617 | double (*lup)(const void *, size_t), (*ins)(void *, size_t, double); | |||||
| 618 | airArray *mop; | |||||
| 619 | ||||||
| 620 | if (!( nrrdTypeFloat == ndist->type || nrrdTypeDouble == ndist->type )) { | |||||
| ||||||
| 621 | /* MWC: This error condition was/is being ignored. */ | |||||
| 622 | /* biffAddf(NRRD, "%s: sorry, can only process type %s or %s (not %s)", | |||||
| 623 | me, | |||||
| 624 | airEnumStr(nrrdType, nrrdTypeFloat), | |||||
| 625 | airEnumStr(nrrdType, nrrdTypeDouble), | |||||
| 626 | airEnumStr(nrrdType, ndist->type)); | |||||
| 627 | */ | |||||
| 628 | } | |||||
| 629 | ||||||
| 630 | spcSomeExist = AIR_FALSE0; | |||||
| 631 | spcSomeNonExist = AIR_FALSE0; | |||||
| 632 | for (di=0; di<ndist->dim; di++) { | |||||
| 633 | nrrdSpacingCalculate(ndist, di, spc + di, vector); | |||||
| 634 | spcSomeExist |= AIR_EXISTS(spc[di])(((int)(!((spc[di]) - (spc[di]))))); | |||||
| 635 | spcSomeNonExist |= !AIR_EXISTS(spc[di])(((int)(!((spc[di]) - (spc[di]))))); | |||||
| 636 | } | |||||
| 637 | if (spcSomeExist && spcSomeNonExist) { | |||||
| 638 | biffAddf(NRRDnrrdBiffKey, "%s: axis spacings must all exist or all non-exist", me); | |||||
| 639 | return 1; | |||||
| 640 | } | |||||
| 641 | if (!spcSomeExist) { | |||||
| 642 | for (di=0; di<ndist->dim; di++) { | |||||
| 643 | spc[di] = 1.0; | |||||
| 644 | } | |||||
| 645 | } | |||||
| 646 | *spcMean = 0; | |||||
| 647 | for (di=0; di<ndist->dim; di++) { | |||||
| 648 | *spcMean += spc[di]; | |||||
| 649 | } | |||||
| 650 | *spcMean /= ndist->dim; | |||||
| 651 | ||||||
| 652 | sizeMax = 0; | |||||
| 653 | for (di=0; di<ndist->dim; di++) { | |||||
| 654 | sizeMax = AIR_MAX(sizeMax, ndist->axis[di].size)((sizeMax) > (ndist->axis[di].size) ? (sizeMax) : (ndist ->axis[di].size)); | |||||
| 655 | } | |||||
| 656 | ||||||
| 657 | /* create mop and allocate tmp buffers */ | |||||
| 658 | mop = airMopNew(); | |||||
| 659 | ntmpA = nrrdNew(); | |||||
| 660 | airMopAdd(mop, ntmpA, (airMopper)nrrdNuke, airMopAlways); | |||||
| 661 | if (ndist->dim > 2) { | |||||
| 662 | ntmpB = nrrdNew(); | |||||
| 663 | airMopAdd(mop, ntmpB, (airMopper)nrrdNuke, airMopAlways); | |||||
| 664 | } else { | |||||
| 665 | ntmpB = NULL((void*)0); | |||||
| 666 | } | |||||
| 667 | if (nrrdCopy(ntmpA, ndist) | |||||
| 668 | || (ndist->dim > 2 && nrrdCopy(ntmpB, ndist))) { | |||||
| 669 | biffAddf(NRRDnrrdBiffKey, "%s: couldn't allocate image buffers", me); | |||||
| 670 | } | |||||
| 671 | dd = AIR_CAST(double *, calloc(sizeMax, sizeof(double)))((double *)(calloc(sizeMax, sizeof(double)))); | |||||
| ||||||
| 672 | ff = AIR_CAST(double *, calloc(sizeMax, sizeof(double)))((double *)(calloc(sizeMax, sizeof(double)))); | |||||
| 673 | zz = AIR_CAST(double *, calloc(sizeMax+1, sizeof(double)))((double *)(calloc(sizeMax+1, sizeof(double)))); | |||||
| 674 | vv = AIR_CAST(unsigned int *, calloc(sizeMax, sizeof(unsigned int)))((unsigned int *)(calloc(sizeMax, sizeof(unsigned int)))); | |||||
| 675 | airMopAdd(mop, dd, airFree, airMopAlways); | |||||
| 676 | airMopAdd(mop, ff, airFree, airMopAlways); | |||||
| 677 | airMopAdd(mop, zz, airFree, airMopAlways); | |||||
| 678 | airMopAdd(mop, vv, airFree, airMopAlways); | |||||
| 679 | if (!( dd && ff && zz && vv )) { | |||||
| 680 | /* MWC: This error condition was/is being ignored. */ | |||||
| 681 | /* biffAddf(NRRD, "%s: couldn't allocate scanline buffers", me); */ | |||||
| 682 | } | |||||
| 683 | ||||||
| 684 | /* set up array of buffers */ | |||||
| 685 | npass[0] = ndist; | |||||
| 686 | for (di=1; di<ndist->dim; di++) { | |||||
| 687 | npass[di] = (di % 2) ? ntmpA : ntmpB; | |||||
| 688 | } | |||||
| 689 | npass[ndist->dim] = ndist; | |||||
| 690 | ||||||
| 691 | /* run the multiple passes */ | |||||
| 692 | /* what makes the indexing here so simple is that by assuming that | |||||
| 693 | we're processing every axis, the input to any given pass can be | |||||
| 694 | logically considered a 2-D image (a list of scanlines), where the | |||||
| 695 | second axis is the merge of all input axes but the first. With | |||||
| 696 | the rotational shuffle of axes through passes, the initial axis | |||||
| 697 | and the set of other axes swap places, so its like the 2-D image | |||||
| 698 | is being transposed. NOTE: the Nrrds that were allocated as | |||||
| 699 | buffers are really being mis-used, in that the axis sizes and | |||||
| 700 | raster ordering of what we're storing there is *not* the same as | |||||
| 701 | told by axis[].size */ | |||||
| 702 | lup = nrrdDLookup[ndist->type]; | |||||
| 703 | ins = nrrdDInsert[ndist->type]; | |||||
| 704 | for (di=0; di<ndist->dim; di++) { | |||||
| 705 | size_t lineIdx, lineNum, valIdx, valNum; | |||||
| 706 | ||||||
| 707 | valNum = ndist->axis[di].size; | |||||
| 708 | lineNum = nrrdElementNumber(ndist)/valNum; | |||||
| 709 | for (lineIdx=0; lineIdx<lineNum; lineIdx++) { | |||||
| 710 | /* read input scanline into ff */ | |||||
| 711 | for (valIdx=0; valIdx<valNum; valIdx++) { | |||||
| 712 | ff[valIdx] = lup(npass[di]->data, valIdx + valNum*lineIdx); | |||||
| 713 | } | |||||
| 714 | /* do the transform */ | |||||
| 715 | distanceL2Sqrd1D(dd, ff, zz, vv, valNum, spc[di]); | |||||
| 716 | /* write dd to output scanline */ | |||||
| 717 | for (valIdx=0; valIdx<valNum; valIdx++) { | |||||
| 718 | ins(npass[di+1]->data, lineIdx + lineNum*valIdx, dd[valIdx]); | |||||
| 719 | } | |||||
| 720 | } | |||||
| 721 | } | |||||
| 722 | ||||||
| 723 | airMopOkay(mop); | |||||
| 724 | return 0; | |||||
| 725 | } | |||||
| 726 | ||||||
| 727 | /* | |||||
| 728 | ** helper function for distance transforms, is called by things that want to do | |||||
| 729 | ** specific kinds of transforms. | |||||
| 730 | */ | |||||
| 731 | static int | |||||
| 732 | _distanceBase(Nrrd *nout, const Nrrd *nin, | |||||
| 733 | int typeOut, const int *axisDo, | |||||
| 734 | double thresh, double bias, int insideHigher) { | |||||
| 735 | static const char me[]="_distanceBase"; | |||||
| 736 | size_t ii, nn; | |||||
| 737 | double (*lup)(const void *, size_t), (*ins)(void *, size_t, double); | |||||
| 738 | double spcMean; | |||||
| 739 | ||||||
| 740 | if (!( nout && nin )) { | |||||
| 741 | biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer", me); | |||||
| 742 | return 1; | |||||
| 743 | } | |||||
| 744 | if (nrrdTypeBlock == nin->type) { | |||||
| 745 | biffAddf(NRRDnrrdBiffKey, "%s: need scalar type for distance transform (not %s)", | |||||
| 746 | me, airEnumStr(nrrdType, nrrdTypeBlock)); | |||||
| 747 | return 1; | |||||
| 748 | } | |||||
| 749 | if (!( nrrdTypeDouble == typeOut || nrrdTypeFloat == typeOut )) { | |||||
| 750 | biffAddf(NRRDnrrdBiffKey, "%s: sorry, can only transform to type %s or %s " | |||||
| 751 | "(not %s)", me, | |||||
| 752 | airEnumStr(nrrdType, nrrdTypeFloat), | |||||
| 753 | airEnumStr(nrrdType, nrrdTypeDouble), | |||||
| 754 | airEnumStr(nrrdType, typeOut)); | |||||
| 755 | return 1; | |||||
| 756 | } | |||||
| 757 | if (axisDo) { | |||||
| 758 | biffAddf(NRRDnrrdBiffKey, "%s: sorry, selective axis transform not implemented", | |||||
| 759 | me); | |||||
| 760 | return 1; | |||||
| 761 | } | |||||
| 762 | if (!AIR_EXISTS(thresh)(((int)(!((thresh) - (thresh)))))) { | |||||
| 763 | biffAddf(NRRDnrrdBiffKey, "%s: threshold (%g) doesn't exist", me, thresh); | |||||
| 764 | return 1; | |||||
| 765 | } | |||||
| 766 | ||||||
| 767 | if (nrrdConvert(nout, nin, typeOut)) { | |||||
| 768 | biffAddf(NRRDnrrdBiffKey, "%s: couldn't allocate output", me); | |||||
| 769 | return 1; | |||||
| 770 | } | |||||
| 771 | lup = nrrdDLookup[nout->type]; | |||||
| 772 | ins = nrrdDInsert[nout->type]; | |||||
| 773 | ||||||
| 774 | nn = nrrdElementNumber(nout); | |||||
| 775 | for (ii=0; ii<nn; ii++) { | |||||
| 776 | double val, bb; | |||||
| 777 | val = lup(nout->data, ii); | |||||
| 778 | if (insideHigher) { | |||||
| 779 | bb = bias*(val - thresh); | |||||
| 780 | ins(nout->data, ii, val > thresh ? bb*bb : FLT_MAX3.40282347e+38F); | |||||
| 781 | } else { | |||||
| 782 | bb = bias*(thresh - val); | |||||
| 783 | ins(nout->data, ii, val <= thresh ? bb*bb : FLT_MAX3.40282347e+38F); | |||||
| 784 | } | |||||
| 785 | } | |||||
| 786 | ||||||
| 787 | if (distanceL2Sqrd(nout, &spcMean)) { | |||||
| 788 | biffAddf(NRRDnrrdBiffKey, "%s: trouble doing transform", me); | |||||
| 789 | return 1; | |||||
| 790 | } | |||||
| 791 | ||||||
| 792 | for (ii=0; ii<nn; ii++) { | |||||
| 793 | double val; | |||||
| 794 | val = sqrt(lup(nout->data, ii)); | |||||
| 795 | /* here's where the distance is tweaked downwards by half a sample width */ | |||||
| 796 | ins(nout->data, ii, AIR_MAX(0, val - spcMean/2)((0) > (val - spcMean/2) ? (0) : (val - spcMean/2))); | |||||
| 797 | } | |||||
| 798 | ||||||
| 799 | return 0; | |||||
| 800 | } | |||||
| 801 | ||||||
| 802 | /* | |||||
| 803 | ******** nrrdDistanceL2 | |||||
| 804 | ** | |||||
| 805 | ** computes euclidean (L2) distance transform of input image, after | |||||
| 806 | ** thresholding at "thresh". | |||||
| 807 | ** | |||||
| 808 | ** NOTE: the output of this is slightly offset from what one might | |||||
| 809 | ** expect; decreased by half of the average (over all axes) sample | |||||
| 810 | ** spacing. The reason for this is so that when the transform is | |||||
| 811 | ** applied to the inverted image and negated, to create a full | |||||
| 812 | ** signed distance map, the transition from interior to exterior | |||||
| 813 | ** distance values is smooth. Without this trick, there is a | |||||
| 814 | ** small little plateau at the transition. | |||||
| 815 | */ | |||||
| 816 | int | |||||
| 817 | nrrdDistanceL2(Nrrd *nout, const Nrrd *nin, | |||||
| 818 | int typeOut, const int *axisDo, | |||||
| 819 | double thresh, int insideHigher) { | |||||
| 820 | static const char me[]="nrrdDistanceL2"; | |||||
| 821 | ||||||
| 822 | if (_distanceBase(nout, nin, typeOut, axisDo, thresh, 0, insideHigher)) { | |||||
| 823 | biffAddf(NRRDnrrdBiffKey, "%s: trouble doing distance transform", me); | |||||
| 824 | return 1; | |||||
| 825 | } | |||||
| 826 | return 0; | |||||
| 827 | } | |||||
| 828 | ||||||
| 829 | int | |||||
| 830 | nrrdDistanceL2Biased(Nrrd *nout, const Nrrd *nin, | |||||
| 831 | int typeOut, const int *axisDo, | |||||
| 832 | double thresh, double bias, int insideHigher) { | |||||
| 833 | static const char me[]="nrrdDistanceL2Biased"; | |||||
| 834 | ||||||
| 835 | if (_distanceBase(nout, nin, typeOut, axisDo, thresh, bias, insideHigher)) { | |||||
| 836 | biffAddf(NRRDnrrdBiffKey, "%s: trouble doing distance transform", me); | |||||
| 837 | return 1; | |||||
| 838 | } | |||||
| 839 | return 0; | |||||
| 840 | } | |||||
| 841 | ||||||
| 842 | int | |||||
| 843 | nrrdDistanceL2Signed(Nrrd *nout, const Nrrd *nin, | |||||
| 844 | int typeOut, const int *axisDo, | |||||
| 845 | double thresh, int insideHigher) { | |||||
| 846 | static const char me[]="nrrdDistanceL2Signed"; | |||||
| 847 | airArray *mop; | |||||
| 848 | Nrrd *ninv; | |||||
| 849 | ||||||
| 850 | if (!(nout && nin)) { | |||||
| 851 | biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer", me); | |||||
| 852 | return 1; | |||||
| 853 | } | |||||
| 854 | ||||||
| 855 | mop = airMopNew(); | |||||
| 856 | ninv = nrrdNew(); | |||||
| 857 | airMopAdd(mop, ninv, (airMopper)nrrdNuke, airMopAlways); | |||||
| 858 | ||||||
| 859 | if (nrrdDistanceL2(nout, nin, typeOut, axisDo, thresh, insideHigher) | |||||
| 860 | || nrrdDistanceL2(ninv, nin, typeOut, axisDo, thresh, !insideHigher) | |||||
| 861 | || nrrdArithUnaryOp(ninv, nrrdUnaryOpNegative, ninv) | |||||
| 862 | || nrrdArithBinaryOp(nout, nrrdBinaryOpAdd, nout, ninv)) { | |||||
| 863 | biffAddf(NRRDnrrdBiffKey, "%s: trouble doing or combining transforms", me); | |||||
| 864 | airMopError(mop); return 1; | |||||
| 865 | } | |||||
| 866 | ||||||
| 867 | airMopOkay(mop); | |||||
| 868 | return 0; | |||||
| 869 | } |