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 | } |