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 |
|
|
/* the non-histogram measures assume that there will be no NaNs in data */ |
28 |
|
|
void |
29 |
|
|
_nrrdMeasureUnknown(void *ans, int ansType, |
30 |
|
|
const void *line, int lineType, |
31 |
|
|
size_t len, double axmin, double axmax) { |
32 |
|
|
static const char me[]="_nrrdMeasureUnknown"; |
33 |
|
|
|
34 |
|
|
AIR_UNUSED(line); |
35 |
|
|
AIR_UNUSED(lineType); |
36 |
|
|
AIR_UNUSED(len); |
37 |
|
|
AIR_UNUSED(axmin); |
38 |
|
|
AIR_UNUSED(axmax); |
39 |
|
|
fprintf(stderr, "%s: Need To Specify A Measure !!! \n", me); |
40 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
41 |
|
|
} |
42 |
|
|
|
43 |
|
|
void |
44 |
|
|
_nrrdMeasureMin(void *ans, int ansType, |
45 |
|
|
const void *line, int lineType, size_t len, |
46 |
|
|
double axmin, double axmax) { |
47 |
|
|
double val, M, (*lup)(const void*, size_t); |
48 |
|
|
size_t ii; |
49 |
|
|
|
50 |
|
|
AIR_UNUSED(axmin); |
51 |
|
|
AIR_UNUSED(axmax); |
52 |
|
|
lup = nrrdDLookup[lineType]; |
53 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
54 |
|
|
M = lup(line, 0); |
55 |
|
|
for (ii=1; ii<len; ii++) { |
56 |
|
|
val = lup(line, ii); |
57 |
|
|
M = AIR_MIN(M, val); |
58 |
|
|
} |
59 |
|
|
} else { |
60 |
|
|
M = AIR_NAN; |
61 |
|
|
for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) { |
62 |
|
|
M = lup(line, ii); |
63 |
|
|
} |
64 |
|
|
for (; ii<len; ii++) { |
65 |
|
|
val = lup(line, ii); |
66 |
|
|
if (AIR_EXISTS(val)) { |
67 |
|
|
M = AIR_MIN(M, val); |
68 |
|
|
} |
69 |
|
|
} |
70 |
|
|
} |
71 |
|
|
nrrdDStore[ansType](ans, M); |
72 |
|
|
} |
73 |
|
|
|
74 |
|
|
|
75 |
|
|
void |
76 |
|
|
_nrrdMeasureMax(void *ans, int ansType, |
77 |
|
|
const void *line, int lineType, size_t len, |
78 |
|
|
double axmin, double axmax) { |
79 |
|
|
double val, M, (*lup)(const void*, size_t); |
80 |
|
|
size_t ii; |
81 |
|
|
|
82 |
|
|
AIR_UNUSED(axmin); |
83 |
|
|
AIR_UNUSED(axmax); |
84 |
|
|
lup = nrrdDLookup[lineType]; |
85 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
86 |
|
|
M = lup(line, 0); |
87 |
|
|
for (ii=1; ii<len; ii++) { |
88 |
|
|
val = lup(line, ii); |
89 |
|
|
M = AIR_MAX(M, val); |
90 |
|
|
} |
91 |
|
|
} else { |
92 |
|
|
M = AIR_NAN; |
93 |
|
|
for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) { |
94 |
|
|
M = lup(line, ii); |
95 |
|
|
} |
96 |
|
|
for (; ii<len; ii++) { |
97 |
|
|
val = lup(line, ii); |
98 |
|
|
if (AIR_EXISTS(val)) { |
99 |
|
|
M = AIR_MAX(M, val); |
100 |
|
|
} |
101 |
|
|
} |
102 |
|
|
} |
103 |
|
|
nrrdDStore[ansType](ans, M); |
104 |
|
|
} |
105 |
|
|
|
106 |
|
|
void |
107 |
|
|
_nrrdMeasureProduct(void *ans, int ansType, |
108 |
|
|
const void *line, int lineType, size_t len, |
109 |
|
|
double axmin, double axmax) { |
110 |
|
|
double val, P, (*lup)(const void*, size_t); |
111 |
|
|
size_t ii; |
112 |
|
|
|
113 |
|
|
AIR_UNUSED(axmin); |
114 |
|
|
AIR_UNUSED(axmax); |
115 |
|
|
lup = nrrdDLookup[lineType]; |
116 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
117 |
|
|
P = 1.0; |
118 |
|
|
for (ii=0; ii<len; ii++) { |
119 |
|
|
P *= lup(line, ii); |
120 |
|
|
} |
121 |
|
|
} else { |
122 |
|
|
P = AIR_NAN; |
123 |
|
|
/* the point of this is to ensure that that if there are NO |
124 |
|
|
existent values, then the return is NaN */ |
125 |
|
|
for (ii=0; !AIR_EXISTS(P) && ii<len; ii++) { |
126 |
|
|
P = lup(line, ii); |
127 |
|
|
} |
128 |
|
|
for (; ii<len; ii++) { |
129 |
|
|
val = lup(line, ii); |
130 |
|
|
if (AIR_EXISTS(val)) { |
131 |
|
|
P *= val; |
132 |
|
|
} |
133 |
|
|
} |
134 |
|
|
} |
135 |
|
|
nrrdDStore[ansType](ans, P); |
136 |
|
|
} |
137 |
|
|
|
138 |
|
|
void |
139 |
|
|
_nrrdMeasureSum(void *ans, int ansType, |
140 |
|
|
const void *line, int lineType, size_t len, |
141 |
|
|
double axmin, double axmax) { |
142 |
|
|
double val, S, (*lup)(const void*, size_t); |
143 |
|
|
size_t ii; |
144 |
|
|
|
145 |
|
|
AIR_UNUSED(axmin); |
146 |
|
|
AIR_UNUSED(axmax); |
147 |
|
|
lup = nrrdDLookup[lineType]; |
148 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
149 |
|
|
S = 0.0; |
150 |
|
|
for (ii=0; ii<len; ii++) { |
151 |
|
|
S += lup(line, ii); |
152 |
|
|
} |
153 |
|
|
} else { |
154 |
|
|
S = AIR_NAN; |
155 |
|
|
for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) |
156 |
|
|
S = lup(line, ii); |
157 |
|
|
for (; ii<len; ii++) { |
158 |
|
|
val = lup(line, ii); |
159 |
|
|
if (AIR_EXISTS(val)) { |
160 |
|
|
S += val; |
161 |
|
|
} |
162 |
|
|
} |
163 |
|
|
} |
164 |
|
|
nrrdDStore[ansType](ans, S); |
165 |
|
|
} |
166 |
|
|
|
167 |
|
|
void |
168 |
|
|
_nrrdMeasureMean(void *ans, int ansType, |
169 |
|
|
const void *line, int lineType, size_t len, |
170 |
|
|
double axmin, double axmax) { |
171 |
|
|
double val, S, M, (*lup)(const void*, size_t); |
172 |
|
|
size_t ii, count; |
173 |
|
|
|
174 |
|
|
AIR_UNUSED(axmin); |
175 |
|
|
AIR_UNUSED(axmax); |
176 |
|
|
lup = nrrdDLookup[lineType]; |
177 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
178 |
|
|
S = 0.0; |
179 |
|
|
for (ii=0; ii<len; ii++) { |
180 |
|
|
S += lup(line, ii); |
181 |
|
|
} |
182 |
|
|
M = S/len; |
183 |
|
|
} else { |
184 |
|
|
S = AIR_NAN; |
185 |
|
|
for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) { |
186 |
|
|
S = lup(line, ii); |
187 |
|
|
} |
188 |
|
|
if (AIR_EXISTS(S)) { |
189 |
|
|
/* there was an existent value */ |
190 |
|
|
count = 1; |
191 |
|
|
for (; ii<len; ii++) { |
192 |
|
|
val = lup(line, ii); |
193 |
|
|
if (AIR_EXISTS(val)) { |
194 |
|
|
count++; |
195 |
|
|
S += val; |
196 |
|
|
} |
197 |
|
|
} |
198 |
|
|
M = S/count; |
199 |
|
|
} else { |
200 |
|
|
/* there were NO existent values */ |
201 |
|
|
M = AIR_NAN; |
202 |
|
|
} |
203 |
|
|
} |
204 |
|
|
nrrdDStore[ansType](ans, M); |
205 |
|
|
} |
206 |
|
|
|
207 |
|
|
/* stupid little forward declaration */ |
208 |
|
|
void |
209 |
|
|
_nrrdMeasureHistoMode(void *ans, int ansType, |
210 |
|
|
const void *line, int lineType, size_t len, |
211 |
|
|
double axmin, double axmax); |
212 |
|
|
|
213 |
|
|
void |
214 |
|
|
_nrrdMeasureMode(void *ans, int ansType, |
215 |
|
|
const void *_line, int lineType, size_t len, |
216 |
|
|
double axmin, double axmax) { |
217 |
|
|
Nrrd *nline, *nhist; |
218 |
|
|
void *line; |
219 |
|
|
|
220 |
|
|
AIR_UNUSED(axmin); |
221 |
|
|
AIR_UNUSED(axmax); |
222 |
|
|
line = calloc(len, nrrdTypeSize[lineType]); |
223 |
|
|
if (line) { |
224 |
|
|
memcpy(line, _line, len*nrrdTypeSize[lineType]); |
225 |
|
|
|
226 |
|
|
nline = nrrdNew(); |
227 |
|
|
if (nrrdWrap_va(nline, line, lineType, 1, len)) { |
228 |
|
|
free(biffGetDone(NRRD)); |
229 |
|
|
nrrdNix(nline); |
230 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
231 |
|
|
return; |
232 |
|
|
} |
233 |
|
|
nhist = nrrdNew(); |
234 |
|
|
if (nrrdHisto(nhist, nline, NULL, NULL, |
235 |
|
|
nrrdStateMeasureModeBins, nrrdTypeInt)) { |
236 |
|
|
free(biffGetDone(NRRD)); |
237 |
|
|
nrrdNuke(nhist); |
238 |
|
|
nrrdNix(nline); |
239 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
240 |
|
|
return; |
241 |
|
|
} |
242 |
|
|
|
243 |
|
|
/* now we pass this histogram off to histo-mode */ |
244 |
|
|
_nrrdMeasureHistoMode(ans, ansType, |
245 |
|
|
nhist->data, nrrdTypeInt, nrrdStateMeasureModeBins, |
246 |
|
|
nhist->axis[0].min, nhist->axis[0].max); |
247 |
|
|
nrrdNuke(nhist); |
248 |
|
|
nrrdNix(nline); |
249 |
|
|
} else { |
250 |
|
|
nrrdDStore[ansType](ans, 0); |
251 |
|
|
} |
252 |
|
|
return; |
253 |
|
|
} |
254 |
|
|
|
255 |
|
|
void |
256 |
|
|
_nrrdMeasureMedian(void *ans, int ansType, |
257 |
|
|
const void *_line, int lineType, size_t len, |
258 |
|
|
double axmin, double axmax) { |
259 |
|
|
double M=0, (*lup)(const void*, size_t); |
260 |
|
|
size_t ii, mid; |
261 |
|
|
void *line; |
262 |
|
|
|
263 |
|
|
AIR_UNUSED(axmin); |
264 |
|
|
AIR_UNUSED(axmax); |
265 |
|
|
lup = nrrdDLookup[lineType]; |
266 |
|
|
line = calloc(len, nrrdTypeSize[lineType]); |
267 |
|
|
if (line) { |
268 |
|
|
memcpy(line, _line, len*nrrdTypeSize[lineType]); |
269 |
|
|
|
270 |
|
|
/* yes, I know, this is not the fastest median. I'll get to it ... */ |
271 |
|
|
qsort(line, len, nrrdTypeSize[lineType], nrrdValCompare[lineType]); |
272 |
|
|
M = AIR_NAN; |
273 |
|
|
for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) { |
274 |
|
|
M = lup(line, ii); |
275 |
|
|
} |
276 |
|
|
|
277 |
|
|
if (AIR_EXISTS(M)) { |
278 |
|
|
/* i is index AFTER first existent value */ |
279 |
|
|
ii--; |
280 |
|
|
len -= ii; |
281 |
|
|
mid = len/2; |
282 |
|
|
if (len % 2) { |
283 |
|
|
/* len is odd, there is a middle value, its at mid */ |
284 |
|
|
M = lup(line, ii+mid); |
285 |
|
|
} else { |
286 |
|
|
/* len is even, two middle values are at mid-1 and mid */ |
287 |
|
|
M = (lup(line, ii+mid-1) + lup(line, ii+mid))/2; |
288 |
|
|
} |
289 |
|
|
} |
290 |
|
|
} |
291 |
|
|
nrrdDStore[ansType](ans, M); |
292 |
|
|
} |
293 |
|
|
|
294 |
|
|
void |
295 |
|
|
_nrrdMeasureL1(void *ans, int ansType, |
296 |
|
|
const void *line, int lineType, size_t len, |
297 |
|
|
double axmin, double axmax) { |
298 |
|
|
double val, S, (*lup)(const void*, size_t); |
299 |
|
|
size_t ii; |
300 |
|
|
|
301 |
|
|
AIR_UNUSED(axmin); |
302 |
|
|
AIR_UNUSED(axmax); |
303 |
|
|
lup = nrrdDLookup[lineType]; |
304 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
305 |
|
|
S = 0.0; |
306 |
|
|
for (ii=0; ii<len; ii++) { |
307 |
|
|
val = lup(line, ii); |
308 |
|
|
S += AIR_ABS(val); |
309 |
|
|
} |
310 |
|
|
} else { |
311 |
|
|
S = AIR_NAN; |
312 |
|
|
for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) { |
313 |
|
|
S = lup(line, ii); |
314 |
|
|
} |
315 |
|
|
S = AIR_ABS(S); |
316 |
|
|
for (; ii<len; ii++) { |
317 |
|
|
val = lup(line, ii); |
318 |
|
|
if (AIR_EXISTS(val)) { |
319 |
|
|
S += AIR_ABS(val); |
320 |
|
|
} |
321 |
|
|
} |
322 |
|
|
} |
323 |
|
|
nrrdDStore[ansType](ans, S); |
324 |
|
|
} |
325 |
|
|
|
326 |
|
|
#define L2_BODY(FOUR) \ |
327 |
|
|
AIR_UNUSED(axmin); \ |
328 |
|
|
AIR_UNUSED(axmax); \ |
329 |
|
|
lup = nrrdDLookup[lineType]; \ |
330 |
|
|
if (nrrdTypeIsIntegral[lineType]) { \ |
331 |
|
|
S = 0.0; \ |
332 |
|
|
count = len; \ |
333 |
|
|
for (ii=0; ii<len; ii++) { \ |
334 |
|
|
val = lup(line, ii); \ |
335 |
|
|
S += (FOUR) ? val*val*val*val : val*val; \ |
336 |
|
|
} \ |
337 |
|
|
} else { \ |
338 |
|
|
S = AIR_NAN; \ |
339 |
|
|
count = 0; \ |
340 |
|
|
for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) { \ |
341 |
|
|
S = lup(line, ii); \ |
342 |
|
|
} \ |
343 |
|
|
if (AIR_EXISTS(S)) { \ |
344 |
|
|
/* there's at least one existing value */ \ |
345 |
|
|
count = 1; \ |
346 |
|
|
S *= (FOUR) ? S*S*S : S ; \ |
347 |
|
|
for (; ii<len; ii++) { \ |
348 |
|
|
val = lup(line, ii); \ |
349 |
|
|
if (AIR_EXISTS(val)) { \ |
350 |
|
|
count++; \ |
351 |
|
|
S += (FOUR) ? val*val*val*val : val*val; \ |
352 |
|
|
} \ |
353 |
|
|
} \ |
354 |
|
|
} \ |
355 |
|
|
} |
356 |
|
|
|
357 |
|
|
void |
358 |
|
|
_nrrdMeasureL2(void *ans, int ansType, |
359 |
|
|
const void *line, int lineType, size_t len, |
360 |
|
|
double axmin, double axmax) { |
361 |
|
|
double val, S, aa, (*lup)(const void*, size_t); |
362 |
|
|
size_t ii, count; |
363 |
|
|
|
364 |
|
|
L2_BODY(AIR_FALSE); |
365 |
|
|
if (AIR_EXISTS(S)) { |
366 |
|
|
aa = sqrt(S); |
367 |
|
|
} else { |
368 |
|
|
aa = AIR_NAN; |
369 |
|
|
} |
370 |
|
|
nrrdDStore[ansType](ans, aa); |
371 |
|
|
} |
372 |
|
|
|
373 |
|
|
void |
374 |
|
|
_nrrdMeasureL4(void *ans, int ansType, |
375 |
|
|
const void *line, int lineType, size_t len, |
376 |
|
|
double axmin, double axmax) { |
377 |
|
|
double val, S, aa, (*lup)(const void*, size_t); |
378 |
|
|
size_t ii, count; |
379 |
|
|
|
380 |
|
|
L2_BODY(AIR_TRUE); |
381 |
|
|
if (AIR_EXISTS(S)) { |
382 |
|
|
aa = sqrt(sqrt(S)); |
383 |
|
|
} else { |
384 |
|
|
aa = AIR_NAN; |
385 |
|
|
} |
386 |
|
|
nrrdDStore[ansType](ans, aa); |
387 |
|
|
} |
388 |
|
|
|
389 |
|
|
void |
390 |
|
|
_nrrdMeasureNormalizedL2(void *ans, int ansType, |
391 |
|
|
const void *line, int lineType, size_t len, |
392 |
|
|
double axmin, double axmax) { |
393 |
|
|
double val, S, aa, (*lup)(const void*, size_t); |
394 |
|
|
size_t ii, count; |
395 |
|
|
|
396 |
|
|
L2_BODY(AIR_FALSE); |
397 |
|
|
if (AIR_EXISTS(S)) { |
398 |
|
|
aa = sqrt(S)/count; |
399 |
|
|
} else { |
400 |
|
|
aa = AIR_NAN; |
401 |
|
|
} |
402 |
|
|
nrrdDStore[ansType](ans, aa); |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
void |
406 |
|
|
_nrrdMeasureRootMeanSquare(void *ans, int ansType, |
407 |
|
|
const void *line, int lineType, size_t len, |
408 |
|
|
double axmin, double axmax) { |
409 |
|
|
double val, S, aa, (*lup)(const void*, size_t); |
410 |
|
|
size_t ii, count; |
411 |
|
|
|
412 |
|
|
L2_BODY(AIR_FALSE); |
413 |
|
|
if (AIR_EXISTS(S)) { |
414 |
|
|
aa = sqrt(S/count); |
415 |
|
|
} else { |
416 |
|
|
aa = AIR_NAN; |
417 |
|
|
} |
418 |
|
|
nrrdDStore[ansType](ans, aa); |
419 |
|
|
} |
420 |
|
|
|
421 |
|
|
void |
422 |
|
|
_nrrdMeasureLinf(void *ans, int ansType, |
423 |
|
|
const void *line, int lineType, size_t len, |
424 |
|
|
double axmin, double axmax) { |
425 |
|
|
double val, M, (*lup)(const void*, size_t); |
426 |
|
|
size_t ii; |
427 |
|
|
|
428 |
|
|
AIR_UNUSED(axmin); |
429 |
|
|
AIR_UNUSED(axmax); |
430 |
|
|
lup = nrrdDLookup[lineType]; |
431 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
432 |
|
|
val = lup(line, 0); |
433 |
|
|
M = AIR_ABS(val); |
434 |
|
|
for (ii=1; ii<len; ii++) { |
435 |
|
|
val = lup(line, ii); |
436 |
|
|
val = AIR_ABS(val); |
437 |
|
|
M = AIR_MAX(M, val); |
438 |
|
|
} |
439 |
|
|
} else { |
440 |
|
|
M = AIR_NAN; |
441 |
|
|
for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) { |
442 |
|
|
M = lup(line, ii); |
443 |
|
|
} |
444 |
|
|
M = AIR_ABS(M); |
445 |
|
|
for (; ii<len; ii++) { |
446 |
|
|
val = lup(line, ii); |
447 |
|
|
if (AIR_EXISTS(val)) { |
448 |
|
|
val = AIR_ABS(val); |
449 |
|
|
M = AIR_MAX(M, val); |
450 |
|
|
} |
451 |
|
|
} |
452 |
|
|
} |
453 |
|
|
nrrdDStore[ansType](ans, M); |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
/* ========================================================== */ |
457 |
|
|
#if 0 /* two variance functions: |
458 |
|
|
0 for new two-pass (more accurate) |
459 |
|
|
1 for old single-pass */ |
460 |
|
|
|
461 |
|
|
void |
462 |
|
|
_nrrdMeasureVariance(void *ans, int ansType, |
463 |
|
|
const void *line, int lineType, size_t len, |
464 |
|
|
double axmin, double axmax) { |
465 |
|
|
double val, S, SS, (*lup)(const void*, size_t); |
466 |
|
|
size_t ii, count; |
467 |
|
|
|
468 |
|
|
AIR_UNUSED(axmin); |
469 |
|
|
AIR_UNUSED(axmax); |
470 |
|
|
SS = S = 0.0; |
471 |
|
|
lup = nrrdDLookup[lineType]; |
472 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
473 |
|
|
for (ii=0; ii<len; ii++) { |
474 |
|
|
val = lup(line, ii); |
475 |
|
|
S += val; |
476 |
|
|
SS += val*val; |
477 |
|
|
} |
478 |
|
|
S /= len; |
479 |
|
|
SS /= len; |
480 |
|
|
} else { |
481 |
|
|
count = 0; |
482 |
|
|
for (ii=0; ii<len; ii++) { |
483 |
|
|
val = lup(line, ii); |
484 |
|
|
if (AIR_EXISTS(val)) { |
485 |
|
|
count++; |
486 |
|
|
S += val; |
487 |
|
|
SS += val*val; |
488 |
|
|
} |
489 |
|
|
} |
490 |
|
|
if (count) { |
491 |
|
|
S /= count; |
492 |
|
|
SS /= count; |
493 |
|
|
} else { |
494 |
|
|
S = SS = AIR_NAN; |
495 |
|
|
} |
496 |
|
|
} |
497 |
|
|
/* HEY: the AIR_MAX is needed because precision errors |
498 |
|
|
can produce a negative value for SS - S*S; |
499 |
|
|
this may be a sign of the false economy of doing |
500 |
|
|
the variance calculation in a single pass */ |
501 |
|
|
nrrdDStore[ansType](ans, AIR_MAX(0.0, SS - S*S)); |
502 |
|
|
} |
503 |
|
|
|
504 |
|
|
#else /* ========================================================== */ |
505 |
|
|
|
506 |
|
|
void |
507 |
|
|
_nrrdMeasureVariance(void *ans, int ansType, |
508 |
|
|
const void *line, int lineType, size_t len, |
509 |
|
|
double axmin, double axmax) { |
510 |
|
|
double vari, mean, val, (*lup)(const void*, size_t); |
511 |
|
|
size_t ii, count; |
512 |
|
|
|
513 |
|
|
AIR_UNUSED(axmin); |
514 |
|
|
AIR_UNUSED(axmax); |
515 |
|
|
mean = vari = 0.0; |
516 |
|
|
lup = nrrdDLookup[lineType]; |
517 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
518 |
|
|
for (ii=0; ii<len; ii++) { |
519 |
|
|
mean += lup(line, ii); |
520 |
|
|
} |
521 |
|
|
mean /= len; |
522 |
|
|
for (ii=0; ii<len; ii++) { |
523 |
|
|
val = lup(line, ii); |
524 |
|
|
vari += (val-mean)*(val-mean); |
525 |
|
|
} |
526 |
|
|
vari /= len; |
527 |
|
|
} else { |
528 |
|
|
count = 0; |
529 |
|
|
for (ii=0; ii<len; ii++) { |
530 |
|
|
val = lup(line, ii); |
531 |
|
|
if (AIR_EXISTS(val)) { |
532 |
|
|
count++; |
533 |
|
|
mean += val; |
534 |
|
|
} |
535 |
|
|
} |
536 |
|
|
if (count) { |
537 |
|
|
mean /= count; |
538 |
|
|
for (ii=0; ii<len; ii++) { |
539 |
|
|
val = lup(line, ii); |
540 |
|
|
if (AIR_EXISTS(val)) { |
541 |
|
|
vari += (val-mean)*(val-mean); |
542 |
|
|
} |
543 |
|
|
} |
544 |
|
|
vari /= count; |
545 |
|
|
} else { |
546 |
|
|
vari = AIR_NAN; |
547 |
|
|
} |
548 |
|
|
} |
549 |
|
|
nrrdDStore[ansType](ans, vari); |
550 |
|
|
} |
551 |
|
|
|
552 |
|
|
#endif |
553 |
|
|
/* ========================================================== */ |
554 |
|
|
|
555 |
|
|
void |
556 |
|
|
_nrrdMeasureSD(void *ans, int ansType, |
557 |
|
|
const void *line, int lineType, size_t len, |
558 |
|
|
double axmin, double axmax) { |
559 |
|
|
double var; |
560 |
|
|
|
561 |
|
|
_nrrdMeasureVariance(ans, ansType, line, lineType, len, axmin, axmax); |
562 |
|
|
var = nrrdDLoad[ansType](ans); |
563 |
|
|
nrrdDStore[ansType](ans, sqrt(var)); |
564 |
|
|
} |
565 |
|
|
|
566 |
|
|
void |
567 |
|
|
_nrrdMeasureCoV(void *ans, int ansType, |
568 |
|
|
const void *line, int lineType, size_t len, |
569 |
|
|
double axmin, double axmax) { |
570 |
|
|
double val, S, M, (*lup)(const void*, size_t), diff, stdv; |
571 |
|
|
size_t ii, count; |
572 |
|
|
|
573 |
|
|
AIR_UNUSED(axmin); |
574 |
|
|
AIR_UNUSED(axmax); |
575 |
|
|
lup = nrrdDLookup[lineType]; |
576 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
577 |
|
|
S = 0.0; |
578 |
|
|
for (ii=0; ii<len; ii++) { |
579 |
|
|
S += lup(line, ii); |
580 |
|
|
} |
581 |
|
|
M = S/len; |
582 |
|
|
diff = 0.0; |
583 |
|
|
for (ii=0; ii<len; ii++) { |
584 |
|
|
val = lup(line, ii); |
585 |
|
|
diff += (M-val)*(M-val); |
586 |
|
|
} |
587 |
|
|
stdv = sqrt(diff/len); |
588 |
|
|
} else { |
589 |
|
|
S = AIR_NAN; |
590 |
|
|
for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) { |
591 |
|
|
S = lup(line, ii); |
592 |
|
|
} |
593 |
|
|
if (AIR_EXISTS(S)) { |
594 |
|
|
/* there was an existent value */ |
595 |
|
|
count = 1; |
596 |
|
|
for (; ii<len; ii++) { |
597 |
|
|
val = lup(line, ii); |
598 |
|
|
if (AIR_EXISTS(val)) { |
599 |
|
|
count++; |
600 |
|
|
S += val; |
601 |
|
|
} |
602 |
|
|
} |
603 |
|
|
M = S/count; |
604 |
|
|
diff = 0.0; |
605 |
|
|
for (ii=0; ii<len; ii++) { |
606 |
|
|
val = lup(line, ii); |
607 |
|
|
if (AIR_EXISTS(val)) { |
608 |
|
|
diff += (M-val)*(M-val); |
609 |
|
|
} |
610 |
|
|
} |
611 |
|
|
stdv = sqrt(diff/count); |
612 |
|
|
} else { |
613 |
|
|
/* there were NO existent values */ |
614 |
|
|
M = stdv = AIR_NAN; |
615 |
|
|
} |
616 |
|
|
} |
617 |
|
|
nrrdDStore[ansType](ans, stdv/M); |
618 |
|
|
} |
619 |
|
|
|
620 |
|
|
void |
621 |
|
|
_nrrdMeasureLineFit(double *intc, double *slope, |
622 |
|
|
const void *line, int lineType, size_t len, |
623 |
|
|
double axmin, double axmax) { |
624 |
|
|
double x, y, xi=0, yi=0, xiyi=0, xisq=0, det, (*lup)(const void*, size_t); |
625 |
|
|
size_t ii; |
626 |
|
|
|
627 |
|
|
lup = nrrdDLookup[lineType]; |
628 |
|
|
if (!( AIR_EXISTS(axmin) && AIR_EXISTS(axmax) )) { |
629 |
|
|
axmin = 0; |
630 |
|
|
axmax = AIR_CAST(double, len-1); |
631 |
|
|
} |
632 |
|
|
if (1 == len) { |
633 |
|
|
*slope = 0; |
634 |
|
|
*intc = lup(line, 0); |
635 |
|
|
} else { |
636 |
|
|
for (ii=0; ii<len; ii++) { |
637 |
|
|
x = NRRD_NODE_POS(axmin, axmax, len, ii); |
638 |
|
|
y = lup(line, ii); |
639 |
|
|
xi += x; |
640 |
|
|
yi += y; |
641 |
|
|
xiyi += x*y; |
642 |
|
|
xisq += x*x; |
643 |
|
|
} |
644 |
|
|
det = len*xisq - xi*xi; |
645 |
|
|
*slope = (len*xiyi - xi*yi)/det; |
646 |
|
|
*intc = (-xi*xiyi + xisq*yi)/det; |
647 |
|
|
} |
648 |
|
|
} |
649 |
|
|
|
650 |
|
|
void |
651 |
|
|
_nrrdMeasureLineSlope(void *ans, int ansType, |
652 |
|
|
const void *line, int lineType, size_t len, |
653 |
|
|
double axmin, double axmax) { |
654 |
|
|
double slope, intc; |
655 |
|
|
|
656 |
|
|
_nrrdMeasureLineFit(&intc, &slope, line, lineType, len, axmin, axmax); |
657 |
|
|
nrrdDStore[ansType](ans, slope); |
658 |
|
|
} |
659 |
|
|
|
660 |
|
|
void |
661 |
|
|
_nrrdMeasureLineIntercept(void *ans, int ansType, |
662 |
|
|
const void *line, int lineType, size_t len, |
663 |
|
|
double axmin, double axmax) { |
664 |
|
|
double slope, intc; |
665 |
|
|
|
666 |
|
|
_nrrdMeasureLineFit(&intc, &slope, line, lineType, len, axmin, axmax); |
667 |
|
|
nrrdDStore[ansType](ans, intc); |
668 |
|
|
} |
669 |
|
|
|
670 |
|
|
void |
671 |
|
|
_nrrdMeasureLineError(void *ans, int ansType, |
672 |
|
|
const void *line, int lineType, size_t len, |
673 |
|
|
double axmin, double axmax) { |
674 |
|
|
double x, y, slope, intc, tmp, err=0, (*lup)(const void*, size_t); |
675 |
|
|
size_t ii; |
676 |
|
|
|
677 |
|
|
_nrrdMeasureLineFit(&intc, &slope, line, lineType, len, axmin, axmax); |
678 |
|
|
|
679 |
|
|
if (!( AIR_EXISTS(axmin) && AIR_EXISTS(axmax) )) { |
680 |
|
|
axmin = 0; |
681 |
|
|
axmax = AIR_CAST(double, len-1); |
682 |
|
|
} |
683 |
|
|
lup = nrrdDLookup[lineType]; |
684 |
|
|
for (ii=0; ii<len; ii++) { |
685 |
|
|
x = NRRD_NODE_POS(axmin, axmax, len, ii); |
686 |
|
|
y = lup(line, ii); |
687 |
|
|
tmp = slope*x + intc - y; |
688 |
|
|
err += tmp*tmp; |
689 |
|
|
} |
690 |
|
|
nrrdDStore[ansType](ans, err); |
691 |
|
|
} |
692 |
|
|
|
693 |
|
|
void |
694 |
|
|
_nrrdMeasureSkew(void *ans, int ansType, |
695 |
|
|
const void *line, int lineType, size_t len, |
696 |
|
|
double axmin, double axmax) { |
697 |
|
|
double val, diff, mean, vari, third, (*lup)(const void*, size_t); |
698 |
|
|
size_t ii, count; |
699 |
|
|
|
700 |
|
|
AIR_UNUSED(axmin); |
701 |
|
|
AIR_UNUSED(axmax); |
702 |
|
|
/* we don't try to do any one-pass short-cuts */ |
703 |
|
|
|
704 |
|
|
/* find the mean */ |
705 |
|
|
mean = 0; |
706 |
|
|
lup = nrrdDLookup[lineType]; |
707 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
708 |
|
|
count = len; |
709 |
|
|
for (ii=0; ii<len; ii++) { |
710 |
|
|
val = lup(line, ii); |
711 |
|
|
mean += val; |
712 |
|
|
} |
713 |
|
|
} else { |
714 |
|
|
count = 0; |
715 |
|
|
for (ii=0; ii<len; ii++) { |
716 |
|
|
val = lup(line, ii); |
717 |
|
|
if (AIR_EXISTS(val)) { |
718 |
|
|
count++; |
719 |
|
|
mean += val; |
720 |
|
|
} |
721 |
|
|
} |
722 |
|
|
} |
723 |
|
|
if (0 == count) { |
724 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
725 |
|
|
return; |
726 |
|
|
} |
727 |
|
|
mean /= count; |
728 |
|
|
|
729 |
|
|
/* find the variance and third moment */ |
730 |
|
|
vari = third = 0; |
731 |
|
|
if (nrrdTypeIsIntegral[lineType]) { |
732 |
|
|
for (ii=0; ii<len; ii++) { |
733 |
|
|
diff = lup(line, ii) - mean; |
734 |
|
|
vari += diff*diff; |
735 |
|
|
third += diff*diff*diff; |
736 |
|
|
} |
737 |
|
|
} else { |
738 |
|
|
for (ii=0; ii<len; ii++) { |
739 |
|
|
val = lup(line, ii); |
740 |
|
|
if (AIR_EXISTS(val)) { |
741 |
|
|
diff = val - mean; |
742 |
|
|
vari += diff*diff; |
743 |
|
|
third += diff*diff*diff; |
744 |
|
|
} |
745 |
|
|
} |
746 |
|
|
} |
747 |
|
|
if (0 == vari) { |
748 |
|
|
/* why not have an existent value ... */ |
749 |
|
|
nrrdDStore[ansType](ans, 0); |
750 |
|
|
return; |
751 |
|
|
} |
752 |
|
|
vari /= count; |
753 |
|
|
third /= count; |
754 |
|
|
|
755 |
|
|
nrrdDStore[ansType](ans, third/(vari*sqrt(vari))); |
756 |
|
|
} |
757 |
|
|
|
758 |
|
|
/* |
759 |
|
|
** one thing which ALL the _nrrdMeasureHisto measures assume is that, |
760 |
|
|
** being a histogram, the input array will not have any non-existent |
761 |
|
|
** values. It can be floating point, because it is plausible to have |
762 |
|
|
** some histogram composed of fractionally weighted hits, but there is |
763 |
|
|
** no way that it is reasonable to have NaN in a bin, and it is extremely |
764 |
|
|
** unlikely that Inf could actually be created in a floating point |
765 |
|
|
** histogram. |
766 |
|
|
** |
767 |
|
|
** Values in the histogram can be positive or negative, but negative |
768 |
|
|
** values are always ignored. |
769 |
|
|
** |
770 |
|
|
** All the the _nrrdMeasureHisto measures assume that if not both |
771 |
|
|
** axmin and axmax are existent, then (axmin,axmax) = (-0.5,len-0.5). |
772 |
|
|
** Exercise for the reader: Show that |
773 |
|
|
** |
774 |
|
|
** i == NRRD_POS(nrrdCenterCell, 0, len-1, len, i) |
775 |
|
|
** |
776 |
|
|
** This justifies that fact that when axmin and axmax are not both |
777 |
|
|
** existent, then we can simply calculate the answer in index space, |
778 |
|
|
** and not have to do any shifting or scaling at the end to account |
779 |
|
|
** for the fact that we assume (axmin,axmax) = (-0.5,len-0.5). |
780 |
|
|
*/ |
781 |
|
|
|
782 |
|
|
void |
783 |
|
|
_nrrdMeasureHistoMedian(void *ans, int ansType, |
784 |
|
|
const void *line, int lineType, size_t len, |
785 |
|
|
double axmin, double axmax) { |
786 |
|
|
double sum, tmp, half, ansD, (*lup)(const void*, size_t); |
787 |
|
|
size_t ii; |
788 |
|
|
|
789 |
|
|
lup = nrrdDLookup[lineType]; |
790 |
|
|
sum = 0; |
791 |
|
|
for (ii=0; ii<len; ii++) { |
792 |
|
|
tmp = lup(line, ii); |
793 |
|
|
sum += (tmp > 0 ? tmp : 0); |
794 |
|
|
} |
795 |
|
|
if (!sum) { |
796 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
797 |
|
|
return; |
798 |
|
|
} |
799 |
|
|
/* else there was something in the histogram */ |
800 |
|
|
half = sum/2; |
801 |
|
|
sum = 0; |
802 |
|
|
for (ii=0; ii<len; ii++) { |
803 |
|
|
tmp = lup(line, ii); |
804 |
|
|
sum += (tmp > 0 ? tmp : 0); |
805 |
|
|
if (sum >= half) { |
806 |
|
|
break; |
807 |
|
|
} |
808 |
|
|
} |
809 |
|
|
ansD = AIR_CAST(double, ii); |
810 |
|
|
if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) { |
811 |
|
|
ansD = NRRD_CELL_POS(axmin, axmax, len, ansD); |
812 |
|
|
} |
813 |
|
|
nrrdDStore[ansType](ans, ansD); |
814 |
|
|
} |
815 |
|
|
|
816 |
|
|
void |
817 |
|
|
_nrrdMeasureHistoMode(void *ans, int ansType, |
818 |
|
|
const void *line, int lineType, size_t len, |
819 |
|
|
double axmin, double axmax) { |
820 |
|
|
double val, max, idxsum, ansD, (*lup)(const void*, size_t); |
821 |
|
|
size_t ii, idxcount; |
822 |
|
|
|
823 |
|
|
lup = nrrdDLookup[lineType]; |
824 |
|
|
max = -DBL_MAX; |
825 |
|
|
for (ii=0; ii<len; ii++) { |
826 |
|
|
val = lup(line, ii); |
827 |
|
|
if (AIR_EXISTS(val)) { |
828 |
|
|
max = AIR_MAX(max, val); |
829 |
|
|
} |
830 |
|
|
} |
831 |
|
|
if (-DBL_MAX == max) { |
832 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
833 |
|
|
return; |
834 |
|
|
} |
835 |
|
|
/* else there was something in the histogram */ |
836 |
|
|
/* we assume that there may be multiple bins which reach the maximum |
837 |
|
|
height, and we average all those indices. This may well be |
838 |
|
|
bone-headed, and is subject to change. 19 July 03: with the |
839 |
|
|
addition of the final "type" argument to nrrdProject, the |
840 |
|
|
bone-headedness has been alleviated somewhat, since you can pass |
841 |
|
|
nrrdTypeFloat or nrrdTypeDouble to get an accurate answer */ |
842 |
|
|
idxsum = 0; |
843 |
|
|
idxcount = 0; |
844 |
|
|
for (ii=0; ii<len; ii++) { |
845 |
|
|
val = lup(line, ii); |
846 |
|
|
if (val == max) { |
847 |
|
|
idxcount++; |
848 |
|
|
idxsum += ii; |
849 |
|
|
} |
850 |
|
|
} |
851 |
|
|
if (max == 0 && len == idxcount) { |
852 |
|
|
/* entire histogram was zeros => empty distribution => no mode */ |
853 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
854 |
|
|
return; |
855 |
|
|
} |
856 |
|
|
ansD = idxsum/idxcount; |
857 |
|
|
/* |
858 |
|
|
printf("idxsum = %g; idxcount = %d --> ansD = %g --> ", |
859 |
|
|
(float)idxsum, idxcount, ansD); |
860 |
|
|
*/ |
861 |
|
|
if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) { |
862 |
|
|
ansD = NRRD_CELL_POS(axmin, axmax, len, ansD); |
863 |
|
|
} |
864 |
|
|
/* |
865 |
|
|
printf("%g\n", ansD); |
866 |
|
|
*/ |
867 |
|
|
nrrdDStore[ansType](ans, ansD); |
868 |
|
|
} |
869 |
|
|
|
870 |
|
|
void |
871 |
|
|
_nrrdMeasureHistoMean(void *ans, int ansType, |
872 |
|
|
const void *line, int lineType, size_t len, |
873 |
|
|
double axmin, double axmax) { |
874 |
|
|
double count, hits, ansD, (*lup)(const void*, size_t); |
875 |
|
|
size_t ii; |
876 |
|
|
|
877 |
|
|
lup = nrrdDLookup[lineType]; |
878 |
|
|
ansD = count = 0; |
879 |
|
|
for (ii=0; ii<len; ii++) { |
880 |
|
|
hits = lup(line, ii); |
881 |
|
|
hits = AIR_MAX(hits, 0); |
882 |
|
|
count += hits; |
883 |
|
|
ansD += hits*ii; |
884 |
|
|
} |
885 |
|
|
if (!count) { |
886 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
887 |
|
|
return; |
888 |
|
|
} |
889 |
|
|
ansD /= count; |
890 |
|
|
if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) { |
891 |
|
|
ansD = NRRD_CELL_POS(axmin, axmax, len, ansD); |
892 |
|
|
} |
893 |
|
|
nrrdDStore[ansType](ans, ansD); |
894 |
|
|
} |
895 |
|
|
|
896 |
|
|
void |
897 |
|
|
_nrrdMeasureHistoVariance(void *ans, int ansType, |
898 |
|
|
const void *line, int lineType, size_t len, |
899 |
|
|
double axmin, double axmax) { |
900 |
|
|
double S, SS, count, hits, val, (*lup)(const void*, size_t); |
901 |
|
|
size_t ii; |
902 |
|
|
|
903 |
|
|
lup = nrrdDLookup[lineType]; |
904 |
|
|
count = 0; |
905 |
|
|
SS = S = 0.0; |
906 |
|
|
/* we fix axmin, axmax now because GK is better safe than sorry */ |
907 |
|
|
if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { |
908 |
|
|
axmin = -0.5; |
909 |
|
|
axmax = len-0.5; |
910 |
|
|
} |
911 |
|
|
for (ii=0; ii<len; ii++) { |
912 |
|
|
val = NRRD_CELL_POS(axmin, axmax, len, ii); |
913 |
|
|
hits = lup(line, ii); |
914 |
|
|
hits = AIR_MAX(hits, 0); |
915 |
|
|
count += hits; |
916 |
|
|
S += hits*val; |
917 |
|
|
SS += hits*val*val; |
918 |
|
|
} |
919 |
|
|
if (!count) { |
920 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
921 |
|
|
return; |
922 |
|
|
} |
923 |
|
|
S /= count; |
924 |
|
|
SS /= count; |
925 |
|
|
/* HEY: the AIR_MAX is needed because precision errors |
926 |
|
|
can produce a negative value for SS - S*S; |
927 |
|
|
this may be a sign of the false economy of doing |
928 |
|
|
the variance calculation in a single pass */ |
929 |
|
|
nrrdDStore[ansType](ans, AIR_MAX(0.0, SS - S*S)); |
930 |
|
|
} |
931 |
|
|
|
932 |
|
|
void |
933 |
|
|
_nrrdMeasureHistoSD(void *ans, int ansType, |
934 |
|
|
const void *line, int lineType, size_t len, |
935 |
|
|
double axmin, double axmax) { |
936 |
|
|
double var; |
937 |
|
|
|
938 |
|
|
_nrrdMeasureHistoVariance(ans, ansType, line, lineType, len, axmin, axmax); |
939 |
|
|
var = nrrdDLoad[ansType](ans); |
940 |
|
|
nrrdDStore[ansType](ans, sqrt(var)); |
941 |
|
|
} |
942 |
|
|
|
943 |
|
|
void |
944 |
|
|
_nrrdMeasureHistoProduct(void *ans, int ansType, |
945 |
|
|
const void *line, int lineType, size_t len, |
946 |
|
|
double axmin, double axmax) { |
947 |
|
|
double val, product, count, hits, (*lup)(const void*, size_t); |
948 |
|
|
size_t ii; |
949 |
|
|
|
950 |
|
|
if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { |
951 |
|
|
axmin = -0.5; |
952 |
|
|
axmax = len-0.5; |
953 |
|
|
} |
954 |
|
|
lup = nrrdDLookup[lineType]; |
955 |
|
|
product = 1.0; |
956 |
|
|
count = 0; |
957 |
|
|
for (ii=0; ii<len; ii++) { |
958 |
|
|
val = NRRD_CELL_POS(axmin, axmax, len, ii); |
959 |
|
|
hits = lup(line, ii); |
960 |
|
|
hits = AIR_MAX(hits, 0); |
961 |
|
|
count += hits; |
962 |
|
|
product *= pow(val, hits); |
963 |
|
|
} |
964 |
|
|
if (!count) { |
965 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
966 |
|
|
return; |
967 |
|
|
} |
968 |
|
|
nrrdDStore[ansType](ans, product); |
969 |
|
|
} |
970 |
|
|
|
971 |
|
|
void |
972 |
|
|
_nrrdMeasureHistoSum(void *ans, int ansType, |
973 |
|
|
const void *line, int lineType, size_t len, |
974 |
|
|
double axmin, double axmax) { |
975 |
|
|
double sum, hits, val, (*lup)(const void*, size_t); |
976 |
|
|
size_t ii; |
977 |
|
|
|
978 |
|
|
if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { |
979 |
|
|
axmin = -0.5; |
980 |
|
|
axmax = len-0.5; |
981 |
|
|
} |
982 |
|
|
lup = nrrdDLookup[lineType]; |
983 |
|
|
sum = 0; |
984 |
|
|
for (ii=0; ii<len; ii++) { |
985 |
|
|
val = NRRD_CELL_POS(axmin, axmax, len, ii); |
986 |
|
|
hits = lup(line, ii); |
987 |
|
|
hits = AIR_MAX(hits, 0); |
988 |
|
|
sum += hits*val; |
989 |
|
|
} |
990 |
|
|
nrrdDStore[ansType](ans, sum); |
991 |
|
|
} |
992 |
|
|
|
993 |
|
|
void |
994 |
|
|
_nrrdMeasureHistoL2(void *ans, int ansType, |
995 |
|
|
const void *line, int lineType, size_t len, |
996 |
|
|
double axmin, double axmax) { |
997 |
|
|
double l2, count, hits, val, (*lup)(const void*, size_t); |
998 |
|
|
size_t ii; |
999 |
|
|
|
1000 |
|
|
if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { |
1001 |
|
|
axmin = -0.5; |
1002 |
|
|
axmax = len-0.5; |
1003 |
|
|
} |
1004 |
|
|
lup = nrrdDLookup[lineType]; |
1005 |
|
|
l2 = count = 0; |
1006 |
|
|
for (ii=0; ii<len; ii++) { |
1007 |
|
|
val = NRRD_CELL_POS(axmin, axmax, len, ii); |
1008 |
|
|
hits = lup(line, ii); |
1009 |
|
|
hits = AIR_MAX(hits, 0); |
1010 |
|
|
count += hits; |
1011 |
|
|
l2 += hits*val*val; |
1012 |
|
|
} |
1013 |
|
|
if (!count) { |
1014 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
1015 |
|
|
return; |
1016 |
|
|
} |
1017 |
|
|
nrrdDStore[ansType](ans, l2); |
1018 |
|
|
} |
1019 |
|
|
|
1020 |
|
|
void |
1021 |
|
|
_nrrdMeasureHistoMax(void *ans, int ansType, |
1022 |
|
|
const void *line, int lineType, size_t len, |
1023 |
|
|
double axmin, double axmax) { |
1024 |
|
|
double val, (*lup)(const void*, size_t); |
1025 |
|
|
size_t ii; |
1026 |
|
|
|
1027 |
|
|
if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { |
1028 |
|
|
axmin = -0.5; |
1029 |
|
|
axmax = len-0.5; |
1030 |
|
|
} |
1031 |
|
|
lup = nrrdDLookup[lineType]; |
1032 |
|
|
/* we're using ii-1 as index to avoid wrap-around with size_t index */ |
1033 |
|
|
for (ii=len; ii>0; ii--) { |
1034 |
|
|
if (lup(line, ii-1) > 0) { |
1035 |
|
|
break; |
1036 |
|
|
} |
1037 |
|
|
} |
1038 |
|
|
if (ii==0) { |
1039 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
1040 |
|
|
return; |
1041 |
|
|
} |
1042 |
|
|
val = NRRD_CELL_POS(axmin, axmax, len, ii-1); |
1043 |
|
|
nrrdDStore[ansType](ans, val); |
1044 |
|
|
} |
1045 |
|
|
|
1046 |
|
|
void |
1047 |
|
|
_nrrdMeasureHistoMin(void *ans, int ansType, |
1048 |
|
|
const void *line, int lineType, size_t len, |
1049 |
|
|
double axmin, double axmax) { |
1050 |
|
|
double val, (*lup)(const void*, size_t); |
1051 |
|
|
size_t ii; |
1052 |
|
|
|
1053 |
|
|
if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { |
1054 |
|
|
axmin = -0.5; |
1055 |
|
|
axmax = len-0.5; |
1056 |
|
|
} |
1057 |
|
|
lup = nrrdDLookup[lineType]; |
1058 |
|
|
for (ii=0; ii<len; ii++) { |
1059 |
|
|
if (lup(line, ii) > 0) { |
1060 |
|
|
break; |
1061 |
|
|
} |
1062 |
|
|
} |
1063 |
|
|
if (ii==len) { |
1064 |
|
|
nrrdDStore[ansType](ans, AIR_NAN); |
1065 |
|
|
return; |
1066 |
|
|
} |
1067 |
|
|
val = NRRD_CELL_POS(axmin, axmax, len, ii); |
1068 |
|
|
nrrdDStore[ansType](ans, val); |
1069 |
|
|
} |
1070 |
|
|
|
1071 |
|
|
void (* |
1072 |
|
|
nrrdMeasureLine[NRRD_MEASURE_MAX+1])(void *, int, |
1073 |
|
|
const void *, int, size_t, |
1074 |
|
|
double, double) = { |
1075 |
|
|
_nrrdMeasureUnknown, |
1076 |
|
|
_nrrdMeasureMin, |
1077 |
|
|
_nrrdMeasureMax, |
1078 |
|
|
_nrrdMeasureMean, |
1079 |
|
|
_nrrdMeasureMedian, |
1080 |
|
|
_nrrdMeasureMode, |
1081 |
|
|
_nrrdMeasureProduct, |
1082 |
|
|
_nrrdMeasureSum, |
1083 |
|
|
_nrrdMeasureL1, |
1084 |
|
|
_nrrdMeasureL2, |
1085 |
|
|
_nrrdMeasureL4, |
1086 |
|
|
_nrrdMeasureNormalizedL2, |
1087 |
|
|
_nrrdMeasureRootMeanSquare, |
1088 |
|
|
_nrrdMeasureLinf, |
1089 |
|
|
_nrrdMeasureVariance, |
1090 |
|
|
_nrrdMeasureSD, |
1091 |
|
|
_nrrdMeasureCoV, |
1092 |
|
|
_nrrdMeasureSkew, |
1093 |
|
|
_nrrdMeasureLineSlope, |
1094 |
|
|
_nrrdMeasureLineIntercept, |
1095 |
|
|
_nrrdMeasureLineError, |
1096 |
|
|
_nrrdMeasureHistoMin, |
1097 |
|
|
_nrrdMeasureHistoMax, |
1098 |
|
|
_nrrdMeasureHistoMean, |
1099 |
|
|
_nrrdMeasureHistoMedian, |
1100 |
|
|
_nrrdMeasureHistoMode, |
1101 |
|
|
_nrrdMeasureHistoProduct, |
1102 |
|
|
_nrrdMeasureHistoSum, |
1103 |
|
|
_nrrdMeasureHistoL2, |
1104 |
|
|
_nrrdMeasureHistoVariance, |
1105 |
|
|
_nrrdMeasureHistoSD |
1106 |
|
|
}; |
1107 |
|
|
|
1108 |
|
|
int |
1109 |
|
|
_nrrdMeasureType(const Nrrd *nin, int measr) { |
1110 |
|
|
static const char me[]="_nrrdMeasureType"; |
1111 |
|
|
int type=nrrdTypeUnknown; |
1112 |
|
|
|
1113 |
|
|
switch(measr) { |
1114 |
|
|
case nrrdMeasureMin: |
1115 |
|
|
case nrrdMeasureMax: |
1116 |
|
|
case nrrdMeasureMedian: |
1117 |
|
|
case nrrdMeasureMode: |
1118 |
|
|
type = nin->type; |
1119 |
|
|
break; |
1120 |
|
|
case nrrdMeasureMean: |
1121 |
|
|
/* the rational for this is that if you're after the average value |
1122 |
|
|
along a scanline, you probably want it in the same format as |
1123 |
|
|
what you started with, and if you really want an exact answer |
1124 |
|
|
than you can always use nrrdMeasureSum and then divide. This may |
1125 |
|
|
well be bone-headed, so is subject to change */ |
1126 |
|
|
type = nin->type; |
1127 |
|
|
break; |
1128 |
|
|
case nrrdMeasureProduct: |
1129 |
|
|
case nrrdMeasureSum: |
1130 |
|
|
case nrrdMeasureL1: |
1131 |
|
|
case nrrdMeasureL2: |
1132 |
|
|
case nrrdMeasureL4: |
1133 |
|
|
case nrrdMeasureNormalizedL2: |
1134 |
|
|
case nrrdMeasureRootMeanSquare: |
1135 |
|
|
case nrrdMeasureLinf: |
1136 |
|
|
case nrrdMeasureVariance: |
1137 |
|
|
case nrrdMeasureSD: |
1138 |
|
|
case nrrdMeasureCoV: |
1139 |
|
|
case nrrdMeasureSkew: |
1140 |
|
|
case nrrdMeasureLineSlope: |
1141 |
|
|
case nrrdMeasureLineIntercept: |
1142 |
|
|
case nrrdMeasureLineError: |
1143 |
|
|
type = nrrdStateMeasureType; |
1144 |
|
|
break; |
1145 |
|
|
case nrrdMeasureHistoMin: |
1146 |
|
|
case nrrdMeasureHistoMax: |
1147 |
|
|
case nrrdMeasureHistoProduct: |
1148 |
|
|
case nrrdMeasureHistoSum: |
1149 |
|
|
case nrrdMeasureHistoL2: |
1150 |
|
|
case nrrdMeasureHistoMean: |
1151 |
|
|
case nrrdMeasureHistoMedian: |
1152 |
|
|
case nrrdMeasureHistoMode: |
1153 |
|
|
case nrrdMeasureHistoVariance: |
1154 |
|
|
case nrrdMeasureHistoSD: |
1155 |
|
|
/* We (currently) don't keep track of the type of the original |
1156 |
|
|
values which generated the histogram, and we may not even |
1157 |
|
|
have access to that information. So we end up choosing one |
1158 |
|
|
type for all these histogram-based measures */ |
1159 |
|
|
type = nrrdStateMeasureHistoType; |
1160 |
|
|
break; |
1161 |
|
|
default: |
1162 |
|
|
fprintf(stderr, "%s: PANIC: measr %d not handled\n", me, measr); |
1163 |
|
|
exit(1); |
1164 |
|
|
} |
1165 |
|
|
|
1166 |
|
|
return type; |
1167 |
|
|
} |
1168 |
|
|
|
1169 |
|
|
int |
1170 |
|
|
nrrdProject(Nrrd *nout, const Nrrd *cnin, unsigned int axis, |
1171 |
|
|
int measr, int type) { |
1172 |
|
|
static const char me[]="nrrdProject", func[]="project"; |
1173 |
|
|
int iType, oType, axmap[NRRD_DIM_MAX]; |
1174 |
|
|
unsigned int ai, ei; |
1175 |
|
|
size_t iElSz, oElSz, iSize[NRRD_DIM_MAX], oSize[NRRD_DIM_MAX], linLen, |
1176 |
|
|
rowIdx, rowNum, colIdx, colNum, colStep; |
1177 |
|
|
const char *ptr, *iData; |
1178 |
|
|
char *oData, *line; |
1179 |
|
|
double axmin, axmax; |
1180 |
|
|
Nrrd *nin; |
1181 |
|
|
airArray *mop; |
1182 |
|
|
|
1183 |
|
|
if (!(cnin && nout)) { |
1184 |
|
|
biffAddf(NRRD, "%s: got NULL pointer", me); |
1185 |
|
|
return 1; |
1186 |
|
|
} |
1187 |
|
|
if (nout == cnin) { |
1188 |
|
|
biffAddf(NRRD, "%s: nout==nin disallowed", me); |
1189 |
|
|
return 1; |
1190 |
|
|
} |
1191 |
|
|
if (nrrdTypeBlock == cnin->type) { |
1192 |
|
|
biffAddf(NRRD, "%s: can't project nrrd type %s", me, |
1193 |
|
|
airEnumStr(nrrdType, nrrdTypeBlock)); |
1194 |
|
|
return 1; |
1195 |
|
|
} |
1196 |
|
|
if (!AIR_IN_OP(nrrdMeasureUnknown, measr, nrrdMeasureLast)) { |
1197 |
|
|
biffAddf(NRRD, "%s: measure %d not recognized", me, measr); |
1198 |
|
|
return 1; |
1199 |
|
|
} |
1200 |
|
|
if (1 == cnin->dim) { |
1201 |
|
|
if (0 != axis) { |
1202 |
|
|
biffAddf(NRRD, "%s: axis must be 0, not %u, for 1-D array", me, axis); |
1203 |
|
|
return 1; |
1204 |
|
|
} |
1205 |
|
|
} else { |
1206 |
|
|
if (!( axis <= cnin->dim-1 )) { |
1207 |
|
|
biffAddf(NRRD, "%s: axis %u not in range [0,%d]", me, axis, cnin->dim-1); |
1208 |
|
|
return 1; |
1209 |
|
|
} |
1210 |
|
|
} |
1211 |
|
|
if (nrrdTypeDefault != type) { |
1212 |
|
|
if (!( AIR_IN_OP(nrrdTypeUnknown, type, nrrdTypeLast) )) { |
1213 |
|
|
biffAddf(NRRD, "%s: got invalid target type %d", me, type); |
1214 |
|
|
return 1; |
1215 |
|
|
} |
1216 |
|
|
} |
1217 |
|
|
|
1218 |
|
|
mop = airMopNew(); |
1219 |
|
|
if (1 == cnin->dim) { |
1220 |
|
|
/* There are more efficient ways of dealing with this case; this way is |
1221 |
|
|
easy to implement because it leaves most of the established code below |
1222 |
|
|
only superficially changed; uniformly replacing nin with (nin ? nin : |
1223 |
|
|
cnin), even if pointlessly so; this expression that can't be assigned |
1224 |
|
|
to a new variable because of the difference in const. */ |
1225 |
|
|
nin = nrrdNew(); |
1226 |
|
|
airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways); |
1227 |
|
|
if (nrrdAxesInsert(nin, cnin, 1)) { |
1228 |
|
|
biffAddf(NRRD, "%s: trouble inserting axis on 1-D array", me); |
1229 |
|
|
airMopError(mop); return 1; |
1230 |
|
|
} |
1231 |
|
|
} else { |
1232 |
|
|
nin = NULL; |
1233 |
|
|
} |
1234 |
|
|
|
1235 |
|
|
iType = (nin ? nin : cnin)->type; |
1236 |
|
|
oType = (nrrdTypeDefault != type |
1237 |
|
|
? type |
1238 |
|
|
: _nrrdMeasureType((nin ? nin : cnin), measr)); |
1239 |
|
|
iElSz = nrrdTypeSize[iType]; |
1240 |
|
|
oElSz = nrrdTypeSize[oType]; |
1241 |
|
|
nrrdAxisInfoGet_nva((nin ? nin : cnin), nrrdAxisInfoSize, iSize); |
1242 |
|
|
colNum = rowNum = 1; |
1243 |
|
|
for (ai=0; ai<(nin ? nin : cnin)->dim; ai++) { |
1244 |
|
|
if (ai < axis) { |
1245 |
|
|
colNum *= iSize[ai]; |
1246 |
|
|
} else if (ai > axis) { |
1247 |
|
|
rowNum *= iSize[ai]; |
1248 |
|
|
} |
1249 |
|
|
} |
1250 |
|
|
linLen = iSize[axis]; |
1251 |
|
|
colStep = linLen*colNum; |
1252 |
|
|
for (ai=0; ai<=(nin ? nin : cnin)->dim-2; ai++) { |
1253 |
|
|
axmap[ai] = ai + (ai >= axis); |
1254 |
|
|
} |
1255 |
|
|
for (ai=0; ai<=(nin ? nin : cnin)->dim-2; ai++) { |
1256 |
|
|
oSize[ai] = iSize[axmap[ai]]; |
1257 |
|
|
} |
1258 |
|
|
if (nrrdMaybeAlloc_nva(nout, oType, (nin ? nin : cnin)->dim-1, oSize)) { |
1259 |
|
|
biffAddf(NRRD, "%s: failed to create output", me); |
1260 |
|
|
airMopError(mop); return 1; |
1261 |
|
|
} |
1262 |
|
|
|
1263 |
|
|
/* allocate a scanline buffer */ |
1264 |
|
|
if (!(line = AIR_CALLOC(linLen*iElSz, char))) { |
1265 |
|
|
char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL]; |
1266 |
|
|
biffAddf(NRRD, "%s: couldn't calloc(%s,%s) scanline buffer", me, |
1267 |
|
|
airSprintSize_t(stmp1, linLen), |
1268 |
|
|
airSprintSize_t(stmp2, iElSz)); |
1269 |
|
|
airMopError(mop); return 1; |
1270 |
|
|
} |
1271 |
|
|
airMopAdd(mop, line, airFree, airMopAlways); |
1272 |
|
|
|
1273 |
|
|
/* the skinny */ |
1274 |
|
|
axmin = (nin ? nin : cnin)->axis[axis].min; |
1275 |
|
|
axmax = (nin ? nin : cnin)->axis[axis].max; |
1276 |
|
|
iData = AIR_CAST(char *, (nin ? nin : cnin)->data); |
1277 |
|
|
oData = AIR_CAST(char *, nout->data); |
1278 |
|
|
for (rowIdx=0; rowIdx<rowNum; rowIdx++) { |
1279 |
|
|
for (colIdx=0; colIdx<colNum; colIdx++) { |
1280 |
|
|
ptr = iData + iElSz*(colIdx + rowIdx*colStep); |
1281 |
|
|
for (ei=0; ei<linLen; ei++) { |
1282 |
|
|
memcpy(line + ei*iElSz, ptr + ei*iElSz*colNum, iElSz); |
1283 |
|
|
} |
1284 |
|
|
nrrdMeasureLine[measr](oData, oType, line, iType, linLen, |
1285 |
|
|
axmin, axmax); |
1286 |
|
|
oData += oElSz; |
1287 |
|
|
} |
1288 |
|
|
} |
1289 |
|
|
|
1290 |
|
|
/* copy the peripheral information */ |
1291 |
|
|
if (nrrdAxisInfoCopy(nout, (nin ? nin : cnin), axmap, NRRD_AXIS_INFO_NONE)) { |
1292 |
|
|
biffAddf(NRRD, "%s:", me); |
1293 |
|
|
airMopError(mop); return 1; |
1294 |
|
|
} |
1295 |
|
|
if (nrrdContentSet_va(nout, func, cnin /* hide possible axinsert */, |
1296 |
|
|
"%d,%s", axis, airEnumStr(nrrdMeasure, measr))) { |
1297 |
|
|
biffAddf(NRRD, "%s:", me); |
1298 |
|
|
airMopError(mop); return 1; |
1299 |
|
|
} |
1300 |
|
|
/* this will copy the space origin over directly, which is reasonable */ |
1301 |
|
|
if (nrrdBasicInfoCopy(nout, (nin ? nin : cnin), |
1302 |
|
|
NRRD_BASIC_INFO_DATA_BIT |
1303 |
|
|
| NRRD_BASIC_INFO_TYPE_BIT |
1304 |
|
|
| NRRD_BASIC_INFO_BLOCKSIZE_BIT |
1305 |
|
|
| NRRD_BASIC_INFO_DIMENSION_BIT |
1306 |
|
|
| NRRD_BASIC_INFO_CONTENT_BIT |
1307 |
|
|
| NRRD_BASIC_INFO_COMMENTS_BIT |
1308 |
|
|
| (nrrdStateKeyValuePairsPropagate |
1309 |
|
|
? 0 |
1310 |
|
|
: NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) { |
1311 |
|
|
biffAddf(NRRD, "%s:", me); |
1312 |
|
|
airMopError(mop); return 1; |
1313 |
|
|
} |
1314 |
|
|
|
1315 |
|
|
airMopOkay(mop); |
1316 |
|
|
return 0; |
1317 |
|
|
} |