void _nrrdMeasureHistoMedian(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double sum, tmp, half, ansD, (*lup)(const void*, size_t); size_t ii; lup = nrrdDLookup[lineType]; sum = 0; for (ii=0; ii<len; ii++) { tmp = lup(line, ii); sum += (tmp > 0 ? tmp : 0); } if (!sum) { nrrdDStore[ansType](ans, AIR_NAN); return; } /* else there was something in the histogram */ half = sum/2; sum = 0; for (ii=0; ii<len; ii++) { tmp = lup(line, ii); sum += (tmp > 0 ? tmp : 0); if (sum >= half) { break; } } ansD = ii; if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) { ansD = NRRD_CELL_POS(axmin, axmax, len, ansD); } nrrdDStore[ansType](ans, ansD); }
void _nrrdMeasureProduct(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double val, P, (*lup)(const void*, size_t); size_t ii; AIR_UNUSED(axmin); AIR_UNUSED(axmax); lup = nrrdDLookup[lineType]; if (nrrdTypeIsIntegral[lineType]) { P = 1.0; for (ii=0; ii<len; ii++) { P *= lup(line, ii); } } else { P = AIR_NAN; /* the point of this is to ensure that that if there are NO existant values, then the return is NaN */ for (ii=0; !AIR_EXISTS(P) && ii<len; ii++) { P = lup(line, ii); } for (; ii<len; ii++) { val = lup(line, ii); if (AIR_EXISTS(val)) { P *= val; } } } nrrdDStore[ansType](ans, P); }
void _nrrdMeasureMax(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double val, M, (*lup)(const void*, size_t); size_t ii; AIR_UNUSED(axmin); AIR_UNUSED(axmax); lup = nrrdDLookup[lineType]; if (nrrdTypeIsIntegral[lineType]) { M = lup(line, 0); for (ii=1; ii<len; ii++) { val = lup(line, ii); M = AIR_MAX(M, val); } } else { M = AIR_NAN; for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) { M = lup(line, ii); } for (; ii<len; ii++) { val = lup(line, ii); if (AIR_EXISTS(val)) { M = AIR_MAX(M, val); } } } nrrdDStore[ansType](ans, M); }
void _nrrdMeasureL2(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double val, S, (*lup)(const void*, size_t); size_t ii; AIR_UNUSED(axmin); AIR_UNUSED(axmax); lup = nrrdDLookup[lineType]; if (nrrdTypeIsIntegral[lineType]) { S = 0.0; for (ii=0; ii<len; ii++) { val = lup(line, ii); S += val*val; } } else { S = AIR_NAN; for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) { S = lup(line, ii); } S *= S; for (; ii<len; ii++) { val = lup(line, ii); if (AIR_EXISTS(val)) { S += val*val; } } } nrrdDStore[ansType](ans, sqrt(S)); }
void _nrrdMeasureLineFit(double *intc, double *slope, const void *line, int lineType, size_t len, double axmin, double axmax) { double x, y, xi=0, yi=0, xiyi=0, xisq=0, det, (*lup)(const void*, size_t); size_t ii; lup = nrrdDLookup[lineType]; if (!( AIR_EXISTS(axmin) && AIR_EXISTS(axmax) )) { axmin = 0; axmax = len-1; } if (1 == len) { *slope = 0; *intc = lup(line, 0); } else { for (ii=0; ii<len; ii++) { x = NRRD_NODE_POS(axmin, axmax, len, ii); y = lup(line, ii); xi += x; yi += y; xiyi += x*y; xisq += x*x; } det = len*xisq - xi*xi; *slope = (len*xiyi - xi*yi)/det; *intc = (-xi*xiyi + xisq*yi)/det; } }
int tenTripleConvert(Nrrd *nout, int dstType, const Nrrd *nin, int srcType) { static const char me[]="tenTripleConvert"; size_t II, NN; double (*ins)(void *, size_t, double), (*lup)(const void *, size_t); if (!( nout && nin )) { biffAddf(TEN, "%s: got NULL pointer", me); return 1; } if ( airEnumValCheck(tenTripleType, dstType) || airEnumValCheck(tenTripleType, srcType) ) { biffAddf(TEN, "%s: got invalid %s dst (%d) or src (%d)", me, tenTripleType->name, dstType, srcType); return 1; } if (3 != nin->axis[0].size) { char stmp[AIR_STRLEN_SMALL]; biffAddf(TEN, "%s: need axis[0].size 3, not %s", me, airSprintSize_t(stmp, nin->axis[0].size)); return 1; } if (nrrdTypeBlock == nin->type) { biffAddf(TEN, "%s: input has non-scalar %s type", me, airEnumStr(nrrdType, nrrdTypeBlock)); return 1; } if (nrrdCopy(nout, nin)) { biffMovef(TEN, NRRD, "%s: couldn't initialize output", me); return 1; } lup = nrrdDLookup[nin->type]; ins = nrrdDInsert[nout->type]; NN = nrrdElementNumber(nin)/3; for (II=0; II<NN; II++) { double src[3], dst[3]; src[0] = lup(nin->data, 0 + 3*II); src[1] = lup(nin->data, 1 + 3*II); src[2] = lup(nin->data, 2 + 3*II); tenTripleConvertSingle_d(dst, dstType, src, srcType); ins(nout->data, 0 + 3*II, dst[0]); ins(nout->data, 1 + 3*II, dst[1]); ins(nout->data, 2 + 3*II, dst[2]); } return 0; }
void _nrrdMeasureHistoMean(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double count, hits, ansD, (*lup)(const void*, size_t); size_t ii; lup = nrrdDLookup[lineType]; ansD = count = 0; for (ii=0; ii<len; ii++) { hits = lup(line, ii); hits = AIR_MAX(hits, 0); count += hits; ansD += hits*ii; } if (!count) { nrrdDStore[ansType](ans, AIR_NAN); return; } ansD /= count; if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) { ansD = NRRD_CELL_POS(axmin, axmax, len, ansD); } nrrdDStore[ansType](ans, ansD); }
void _nrrdMeasureHistoVariance(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double S, SS, count, hits, val, (*lup)(const void*, size_t); size_t ii; lup = nrrdDLookup[lineType]; count = 0; SS = S = 0.0; /* we fix axmin, axmax now because GK is better safe than sorry */ if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { axmin = -0.5; axmax = len-0.5; } for (ii=0; ii<len; ii++) { val = NRRD_CELL_POS(axmin, axmax, len, ii); hits = lup(line, ii); hits = AIR_MAX(hits, 0); count += hits; S += hits*val; SS += hits*val*val; } if (!count) { nrrdDStore[ansType](ans, AIR_NAN); return; } S /= count; SS /= count; nrrdDStore[ansType](ans, SS - S*S); }
void _nrrdMeasureHistoL2(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double l2, count, hits, val, (*lup)(const void*, size_t); size_t ii; if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { axmin = -0.5; axmax = len-0.5; } lup = nrrdDLookup[lineType]; l2 = count = 0; for (ii=0; ii<len; ii++) { val = NRRD_CELL_POS(axmin, axmax, len, ii); hits = lup(line, ii); hits = AIR_MAX(hits, 0); count += hits; l2 += hits*val*val; } if (!count) { nrrdDStore[ansType](ans, AIR_NAN); return; } nrrdDStore[ansType](ans, l2); }
void _nrrdMeasureHistoMax(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double val, (*lup)(const void*, size_t); size_t ii; if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { axmin = -0.5; axmax = len-0.5; } lup = nrrdDLookup[lineType]; /* we're using ii-1 as index to avoid wrap-around with size_t index */ for (ii=len; ii>0; ii--) { if (lup(line, ii-1) > 0) { break; } } if (ii==0) { nrrdDStore[ansType](ans, AIR_NAN); return; } val = NRRD_CELL_POS(axmin, axmax, len, ii-1); nrrdDStore[ansType](ans, val); }
void _nrrdMeasureHistoMode(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double val, max, idxsum, ansD, (*lup)(const void*, size_t); size_t ii, idxcount; lup = nrrdDLookup[lineType]; max = -DBL_MAX; for (ii=0; ii<len; ii++) { val = lup(line, ii); max = AIR_MAX(max, val); } if (-DBL_MAX == max) { nrrdDStore[ansType](ans, AIR_NAN); return; } /* else there was something in the histogram */ /* we assume that there may be multiple bins which reach the maximum height, and we average all those indices. This may well be bone-headed, and is subject to change. 19 July 03: with the addition of the final "type" argument to nrrdProject, the bone-headedness has been alleviated somewhat, since you can pass nrrdTypeFloat or nrrdTypeDouble to get an accurate answer */ idxsum = 0; idxcount = 0; for (ii=0; ii<len; ii++) { val = lup(line, ii); if (val == max) { idxcount++; idxsum += ii; } } ansD = idxsum/idxcount; /* printf("idxsum = %g; idxcount = %d --> ansD = %g --> ", (float)idxsum, idxcount, ansD); */ if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) { ansD = NRRD_CELL_POS(axmin, axmax, len, ansD); } /* printf("%g\n", ansD); */ nrrdDStore[ansType](ans, ansD); }
void _nrrdMeasureMean(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double val, S, M, (*lup)(const void*, size_t); size_t ii, count; AIR_UNUSED(axmin); AIR_UNUSED(axmax); lup = nrrdDLookup[lineType]; if (nrrdTypeIsIntegral[lineType]) { S = 0.0; for (ii=0; ii<len; ii++) { S += lup(line, ii); } M = S/len; } else { S = AIR_NAN; for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) { S = lup(line, ii); } if (AIR_EXISTS(S)) { /* there was an existant value */ count = 1; for (; ii<len; ii++) { val = lup(line, ii); if (AIR_EXISTS(val)) { count++; S += val; } } M = S/count; } else { /* there were NO existant values */ M = AIR_NAN; } } nrrdDStore[ansType](ans, M); }
void _nrrdMeasureMedian(void *ans, int ansType, const void *_line, int lineType, size_t len, double axmin, double axmax) { double M=0, (*lup)(const void*, size_t); size_t ii, mid; void *line; AIR_UNUSED(axmin); AIR_UNUSED(axmax); lup = nrrdDLookup[lineType]; line = calloc(len, nrrdTypeSize[lineType]); if (line) { memcpy(line, _line, len*nrrdTypeSize[lineType]); /* yes, I know, this is not the fastest median. I'll get to it ... */ qsort(line, len, nrrdTypeSize[lineType], nrrdValCompare[lineType]); M = AIR_NAN; for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) { M = lup(line, ii); } if (AIR_EXISTS(M)) { /* i is index AFTER first existant value */ ii--; len -= ii; mid = len/2; if (len % 2) { /* len is odd, there is a middle value, its at mid */ M = lup(line, ii+mid); } else { /* len is even, two middle values are at mid-1 and mid */ M = (lup(line, ii+mid-1) + lup(line, ii+mid))/2; } } } nrrdDStore[ansType](ans, M); }
void _nrrdMeasureVariance(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double val, S, SS, (*lup)(const void*, size_t); size_t ii, count; AIR_UNUSED(axmin); AIR_UNUSED(axmax); SS = S = 0.0; lup = nrrdDLookup[lineType]; if (nrrdTypeIsIntegral[lineType]) { for (ii=0; ii<len; ii++) { val = lup(line, ii); S += val; SS += val*val; } S /= len; SS /= len; } else { count = 0; for (ii=0; ii<len; ii++) { val = lup(line, ii); if (AIR_EXISTS(val)) { count++; S += val; SS += val*val; } } if (count) { S /= count; SS /= count; } else { S = SS = AIR_NAN; } } nrrdDStore[ansType](ans, SS - S*S); }
int nrrdArithAffine(Nrrd *nout, double minIn, const Nrrd *nin, double maxIn, double minOut, double maxOut, int clamp) { static const char me[]="nrrdArithAffine"; size_t I, N; double (*ins)(void *v, size_t I, double d), (*lup)(const void *v, size_t I), mmin, mmax; if ( !nout || nrrdCheck(nin) ) { biffAddf(NRRD, "%s: got NULL pointer or invalid input", me); return 1; } if (nout != nin) { if (nrrdCopy(nout, nin)) { biffAddf(NRRD, "%s: couldn't initialize output", me); return 1; } } N = nrrdElementNumber(nin); ins = nrrdDInsert[nout->type]; lup = nrrdDLookup[nin->type]; mmin = AIR_MIN(minOut, maxOut); mmax = AIR_MAX(minOut, maxOut); for (I=0; I<N; I++) { double val; val = lup(nin->data, I); val = AIR_AFFINE(minIn, val, maxIn, minOut, maxOut); if (clamp) { val = AIR_CLAMP(mmin, val, mmax); } ins(nout->data, I, val); } /* HEY: it would be much better if the ordering here was the same as in AIR_AFFINE, but that's not easy with the way the content functions are now set up */ if (nrrdContentSet_va(nout, "affine", nin, "%g,%g,%g,%g", minIn, maxIn, minOut, maxOut)) { biffAddf(NRRD, "%s:", me); } return 0; }
void _nrrdMeasureHistoSum(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double sum, hits, val, (*lup)(const void*, size_t); size_t ii; if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { axmin = -0.5; axmax = len-0.5; } lup = nrrdDLookup[lineType]; sum = 0; for (ii=0; ii<len; ii++) { val = NRRD_CELL_POS(axmin, axmax, len, ii); hits = lup(line, ii); hits = AIR_MAX(hits, 0); sum += hits*val; } nrrdDStore[ansType](ans, sum); }
void _nrrdMeasureLineError(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double x, y, slope, intc, tmp, err=0, (*lup)(const void*, size_t); size_t ii; _nrrdMeasureLineFit(&intc, &slope, line, lineType, len, axmin, axmax); if (!( AIR_EXISTS(axmin) && AIR_EXISTS(axmax) )) { axmin = 0; axmax = len-1; } lup = nrrdDLookup[lineType]; for (ii=0; ii<len; ii++) { x = NRRD_NODE_POS(axmin, axmax, len, ii); y = lup(line, ii); tmp = slope*x + intc - y; err += tmp*tmp; } nrrdDStore[ansType](ans, err); }
int limnSplineNrrdEvaluate(Nrrd *nout, limnSpline *spline, Nrrd *nin) { char me[]="limnSplineNrrdEvaluate", err[BIFF_STRLEN]; double tt, *out, (*lup)(const void *, size_t); int odim, infoSize; size_t I, M, size[NRRD_DIM_MAX+1]; if (!(nout && spline && nin)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(LIMN, err); return 1; } if (limnSplineInfoScalar == spline->info) { nrrdAxisInfoGet_va(nin, nrrdAxisInfoSize, size); infoSize = 1; odim = nin->dim; } else { nrrdAxisInfoGet_va(nin, nrrdAxisInfoSize, size+1); infoSize = size[0] = limnSplineInfoSize[spline->info]; odim = 1 + nin->dim; } if (nrrdMaybeAlloc_nva(nout, nrrdTypeDouble, odim, size)) { sprintf(err, "%s: output allocation failed", me); biffMove(LIMN, err, NRRD); return 1; } lup = nrrdDLookup[nin->type]; out = (double*)(nout->data); M = nrrdElementNumber(nin); for (I=0; I<M; I++) { tt = lup(nin->data, I); limnSplineEvaluate(out, spline, tt); out += infoSize; } /* HEY: peripheral info copying? */ return 0; }
void _nrrdMeasureHistoMin(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double val, (*lup)(const void*, size_t); size_t ii; if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) { axmin = -0.5; axmax = len-0.5; } lup = nrrdDLookup[lineType]; for (ii=0; ii<len; ii++) { if (lup(line, ii) > 0) { break; } } if (ii==len) { nrrdDStore[ansType](ans, AIR_NAN); return; } val = NRRD_CELL_POS(axmin, axmax, len, ii); nrrdDStore[ansType](ans, val); }
/* ******** nrrdApply1DSubstitution ** ** A "subst" is a substitution table, i.e. a list of pairs that ** describes what values should be substituted with what (substitution ** rules). So, nsubst must be a scalar 2xN array. The output is a ** copy of the input with values substituted using this table. ** ** Unlike with lookup tables and maps (irregular and regular), we ** aren't at liberty to change the dimensionality of the data (can't ** substitute a grayscale with a color). The ability to apply ** substitutions to non-scalar data will be in a different function. ** Also unlike lookup tables and maps, the output type is the SAME as ** the input type; the output does NOT inherit the type of the ** substitution */ int nrrdApply1DSubstitution(Nrrd *nout, const Nrrd *nin, const Nrrd *_nsubst) { char me[]="nrrdApply1DSubstitution", err[BIFF_STRLEN]; double (*lup)(const void *, size_t); double (*ins)(void *, size_t, double); Nrrd *nsubst; double val, *subst; size_t ii, num; int jj, asize0, asize1, changed; airArray *mop; if (!(nout && _nsubst && nin)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(NRRD, err); return 1; } if (nrrdTypeBlock == nin->type || nrrdTypeBlock == _nsubst->type) { sprintf(err, "%s: input or substitution type is %s, need scalar", me, airEnumStr(nrrdType, nrrdTypeBlock)); biffAdd(NRRD, err); return 1; } if (2 != _nsubst->dim) { sprintf(err, "%s: substitution table has to be 2-D, not %d-D", me, _nsubst->dim); biffAdd(NRRD, err); return 1; } nrrdAxisInfoGet_va(_nsubst, nrrdAxisInfoSize, &asize0, &asize1); if (2 != asize0) { sprintf(err, "%s: substitution table has to be 2xN, not %dxN", me, asize0); biffAdd(NRRD, err); return 1; } if (nout != nin) { if (nrrdCopy(nout, nin)) { sprintf(err, "%s: couldn't initialize by copy to output", me); biffAdd(NRRD, err); return 1; } } mop = airMopNew(); nsubst = nrrdNew(); airMopAdd(mop, nsubst, (airMopper)nrrdNuke, airMopAlways); if (nrrdConvert(nsubst, _nsubst, nrrdTypeDouble)) { sprintf(err, "%s: couldn't create double copy of substitution table", me); biffAdd(NRRD, err); airMopError(mop); return 1; } lup = nrrdDLookup[nout->type]; ins = nrrdDInsert[nout->type]; subst = (double *)nsubst->data; num = nrrdElementNumber(nout); for (ii=0; ii<num; ii++) { val = lup(nout->data, ii); changed = AIR_FALSE; for (jj=0; jj<asize1; jj++) { if (val == subst[jj*2+0]) { val = subst[jj*2+1]; changed = AIR_TRUE; } } if (changed) { ins(nout->data, ii, val); } } airMopOkay(mop); return 0; }
/* ******** nrrdArithGamma() ** ** map the values in a nrrd through a power function; essentially: ** val = pow(val, 1/gamma), but this is after the val has been normalized ** to be in the range of 0.0 to 1.0 (assuming that the given min and ** max really are the full range of the values in the nrrd). Thus, ** the given min and max values are fixed points of this ** transformation. Using a negative gamma means that after the pow() ** function has been applied, the value is inverted with respect to ** min and max (like in xv). */ int nrrdArithGamma(Nrrd *nout, const Nrrd *nin, const NrrdRange *_range, double Gamma) { static const char me[]="nrrdArithGamma", func[]="gamma"; double val, min, max; size_t I, num; NrrdRange *range; airArray *mop; double (*lup)(const void *, size_t); double (*ins)(void *, size_t, double); if (!(nout && nin)) { /* _range can be NULL */ biffAddf(NRRD, "%s: got NULL pointer", me); return 1; } if (!( AIR_EXISTS(Gamma) )) { biffAddf(NRRD, "%s: gamma doesn't exist", me); return 1; } if (!( nrrdTypeBlock != nin->type && nrrdTypeBlock != nout->type )) { biffAddf(NRRD, "%s: can't deal with %s type", me, airEnumStr(nrrdType, nrrdTypeBlock)); return 1; } if (nout != nin) { if (nrrdCopy(nout, nin)) { biffAddf(NRRD, "%s: couldn't initialize by copy to output", me); return 1; } } mop = airMopNew(); if (_range) { range = nrrdRangeCopy(_range); nrrdRangeSafeSet(range, nin, nrrdBlind8BitRangeState); } else { range = nrrdRangeNewSet(nin, nrrdBlind8BitRangeTrue); } airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); min = range->min; max = range->max; if (min == max) { /* this is stupid. We want min < max to avoid making NaNs */ max += 1; } lup = nrrdDLookup[nin->type]; ins = nrrdDInsert[nout->type]; Gamma = 1/Gamma; num = nrrdElementNumber(nin); if (Gamma < 0.0) { Gamma = -Gamma; for (I=0; I<num; I++) { val = lup(nin->data, I); val = AIR_AFFINE(min, val, max, 0.0, 1.0); val = pow(val, Gamma); val = AIR_AFFINE(1.0, val, 0.0, min, max); ins(nout->data, I, val); } } else { for (I=0; I<num; I++) { val = lup(nin->data, I); val = AIR_AFFINE(min, val, max, 0.0, 1.0); val = pow(val, Gamma); val = AIR_AFFINE(0.0, val, 1.0, min, max); ins(nout->data, I, val); } } if (nrrdContentSet_va(nout, func, nin, "%g,%g,%g", min, max, Gamma)) { biffAddf(NRRD, "%s:", me); airMopError(mop); return 1; } if (nout != nin) { nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_NONE); } /* basic info handled by nrrdCopy above */ airMopOkay(mop); return 0; }
int main(int argc, char *argv[]) { char *me, *outS; hestOpt *hopt; hestParm *hparm; airArray *mop; char *err, done[13]; Nrrd *nin, *nblur, *nout; NrrdKernelSpec *kb0, *kb1, *k00, *k11, *k22; NrrdResampleContext *rsmc; int E; unsigned int sx, sy, sz, xi, yi, zi, ai; gageContext *ctx; gagePerVolume *pvl; const double *gvec, *gmag, *evec0, *eval; double (*ins)(void *v, size_t I, double d); double (*lup)(const void *v, size_t I); double dotmax, dotpow, gmmax, evalshift, gmpow, _dotmax, _gmmax, scl, clamp; me = argv[0]; mop = airMopNew(); hparm = hestParmNew(); hopt = NULL; airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways); hestOptAdd(&hopt, "i", "nin", airTypeOther, 1, 1, &nin, NULL, "input volume", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "kb0", "kernel", airTypeOther, 1, 1, &kb0, "guass:3,5", "kernel to use for pre-process blurring", NULL, NULL, nrrdHestKernelSpec); hestOptAdd(&hopt, "kb1", "kernel", airTypeOther, 1, 1, &kb1, "cubic:1.5,1,0", "kernel to use for pos-process blurring", NULL, NULL, nrrdHestKernelSpec); hestOptAdd(&hopt, "k00", "kernel", airTypeOther, 1, 1, &k00, "cubic:1,0", "k00", NULL, NULL, nrrdHestKernelSpec); hestOptAdd(&hopt, "k11", "kernel", airTypeOther, 1, 1, &k11, "cubicd:1,0", "k00", NULL, NULL, nrrdHestKernelSpec); hestOptAdd(&hopt, "k22", "kernel", airTypeOther, 1, 1, &k22, "cubicdd:1,0", "k00", NULL, NULL, nrrdHestKernelSpec); hestOptAdd(&hopt, "dotmax", "dot", airTypeDouble, 1, 1, &dotmax, "5", "max effective value of dot(gvec, evec0)"); hestOptAdd(&hopt, "evs", "shift", airTypeDouble, 1, 1, &evalshift, "0", "negative shift to avoid changing mostly flat regions"); hestOptAdd(&hopt, "clamp", "clamp", airTypeDouble, 1, 1, &clamp, "nan", "if it exists, data value can't be forced below this"); hestOptAdd(&hopt, "dotpow", "pow", airTypeDouble, 1, 1, &dotpow, "1", "exponent for dot"); hestOptAdd(&hopt, "gmmax", "dot", airTypeDouble, 1, 1, &gmmax, "2", "max effective value of gmag"); hestOptAdd(&hopt, "gmpow", "pow", airTypeDouble, 1, 1, &gmpow, "1", "exponent for gmag"); hestOptAdd(&hopt, "scl", "scale", airTypeDouble, 1, 1, &scl, "0.1", "how much to scale hack to decrease input value"); hestOptAdd(&hopt, "o", "filename", airTypeString, 1, 1, &outS, "-", "fixed volume output"); hestParseOrDie(hopt, argc-1, argv+1, hparm, me, vhInfo, AIR_TRUE, AIR_TRUE, AIR_TRUE); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); if (!( 3 == nin->dim && nrrdTypeBlock != nin->type )) { fprintf(stderr, "%s: need a 3-D scalar nrrd (not %u-D %s)", me, nin->dim, airEnumStr(nrrdType, nin->type)); airMopError(mop); return 1; } nblur = nrrdNew(); airMopAdd(mop, nblur, (airMopper)nrrdNuke, airMopAlways); if (nrrdCopy(nblur, nin)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: couldn't allocate output:\n%s", me, err); airMopError(mop); return 1; } fprintf(stderr, "%s: pre-blurring ... ", me); fflush(stderr); rsmc = nrrdResampleContextNew(); airMopAdd(mop, rsmc, (airMopper)nrrdResampleContextNix, airMopAlways); E = AIR_FALSE; if (!E) E |= nrrdResampleDefaultCenterSet(rsmc, nrrdCenterCell); if (!E) E |= nrrdResampleNrrdSet(rsmc, nin); for (ai=0; ai<3; ai++) { if (!E) E |= nrrdResampleKernelSet(rsmc, ai, kb0->kernel, kb0->parm); if (!E) E |= nrrdResampleSamplesSet(rsmc, ai, nin->axis[ai].size); if (!E) E |= nrrdResampleRangeFullSet(rsmc, ai); } if (!E) E |= nrrdResampleBoundarySet(rsmc, nrrdBoundaryBleed); if (!E) E |= nrrdResampleTypeOutSet(rsmc, nrrdTypeDefault); if (!E) E |= nrrdResampleRenormalizeSet(rsmc, AIR_TRUE); if (!E) E |= nrrdResampleExecute(rsmc, nblur); if (E) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error resampling nrrd:\n%s", me, err); airMopError(mop); return 1; } fprintf(stderr, "done.\n"); ctx = gageContextNew(); airMopAdd(mop, ctx, (airMopper)gageContextNix, airMopAlways); gageParmSet(ctx, gageParmRenormalize, AIR_TRUE); gageParmSet(ctx, gageParmCheckIntegrals, AIR_TRUE); E = 0; if (!E) E |= !(pvl = gagePerVolumeNew(ctx, nblur, gageKindScl)); if (!E) E |= gagePerVolumeAttach(ctx, pvl); if (!E) E |= gageKernelSet(ctx, gageKernel00, k00->kernel, k00->parm); if (!E) E |= gageKernelSet(ctx, gageKernel11, k11->kernel, k11->parm); if (!E) E |= gageKernelSet(ctx, gageKernel22, k22->kernel, k22->parm); if (!E) E |= gageQueryItemOn(ctx, pvl, gageSclGradVec); if (!E) E |= gageQueryItemOn(ctx, pvl, gageSclGradMag); if (!E) E |= gageQueryItemOn(ctx, pvl, gageSclHessEvec0); if (!E) E |= gageQueryItemOn(ctx, pvl, gageSclHessEval); if (!E) E |= gageUpdate(ctx); if (E) { airMopAdd(mop, err = biffGetDone(GAGE), airFree, airMopAlways); fprintf(stderr, "%s: trouble:\n%s\n", me, err); airMopError(mop); return 1; } gvec = gageAnswerPointer(ctx, pvl, gageSclGradVec); gmag = gageAnswerPointer(ctx, pvl, gageSclGradMag); evec0 = gageAnswerPointer(ctx, pvl, gageSclHessEvec0); eval = gageAnswerPointer(ctx, pvl, gageSclHessEval); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); if (nrrdCopy(nout, nin)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: couldn't allocate output:\n%s", me, err); airMopError(mop); return 1; } if (!(nout->type == nin->type && nblur->type == nin->type)) { fprintf(stderr, "%s: whoa, types (%s %s %s) not all equal\n", me, airEnumStr(nrrdType, nin->type), airEnumStr(nrrdType, nblur->type), airEnumStr(nrrdType, nout->type)); } ins = nrrdDInsert[nout->type]; lup = nrrdDLookup[nout->type]; sx = nin->axis[0].size; sy = nin->axis[1].size; sz = nin->axis[2].size; gageProbe(ctx, 0, 0, 0); _dotmax = ELL_3V_DOT(gvec, evec0); _gmmax = *gmag; fprintf(stderr, "%s: hacking ", me); fflush(stderr); for (zi=0; zi<sz; zi++) { fprintf(stderr, "%s", airDoneStr(0, zi, sz-1, done)); fflush(stderr); for (yi=0; yi<sy; yi++) { for (xi=0; xi<sx; xi++) { size_t si; double dot, evl, gm, shift, in, out, mode; gageProbe(ctx, xi, yi, zi); si = xi + sx*(yi + sy*zi); dot = ELL_3V_DOT(gvec, evec0); _dotmax = AIR_MAX(_dotmax, dot); dot = AIR_ABS(dot); dot = 1 - AIR_MIN(dot, dotmax)/dotmax; dot = pow(dot, dotpow); evl = AIR_MAX(0, eval[0] - evalshift); mode = airMode3_d(eval); evl *= AIR_AFFINE(-1, mode, 1, 0, 1); _gmmax = AIR_MAX(_gmmax, *gmag); gm = 1 - AIR_MIN(*gmag, gmmax)/gmmax; gm = pow(gm, gmpow); shift = scl*gm*evl*dot; if (AIR_EXISTS(clamp)) { in = lup(nin->data, si); out = in - shift; out = AIR_MAX(out, clamp); shift = AIR_MAX(0, in - out); } ins(nout->data, si, shift); } } } fprintf(stderr, "\n"); fprintf(stderr, "%s: max dot seen: %g\n", me, _dotmax); fprintf(stderr, "%s: max gm seen: %g\n", me, _gmmax); fprintf(stderr, "%s: post-blurring ... ", me); fflush(stderr); E = AIR_FALSE; if (!E) E |= nrrdResampleNrrdSet(rsmc, nout); for (ai=0; ai<3; ai++) { if (!E) E |= nrrdResampleKernelSet(rsmc, ai, kb1->kernel, kb1->parm); if (!E) E |= nrrdResampleSamplesSet(rsmc, ai, nout->axis[ai].size); if (!E) E |= nrrdResampleRangeFullSet(rsmc, ai); } if (!E) E |= nrrdResampleExecute(rsmc, nblur); if (E) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error resampling nrrd:\n%s", me, err); airMopError(mop); return 1; } fprintf(stderr, "done.\n"); for (zi=0; zi<sz; zi++) { for (yi=0; yi<sy; yi++) { for (xi=0; xi<sx; xi++) { size_t si; double in, shift; si = xi + sx*(yi + sy*zi); in = lup(nin->data, si); shift = lup(nblur->data, si); ins(nout->data, si, in - shift); } } } if (nrrdSave(outS, nout, NULL)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: couldn't save output:\n%s", me, err); airMopError(mop); return 1; } airMopOkay(mop); exit(0); }
int tenTripleCalc(Nrrd *nout, int ttype, const Nrrd *nten) { static const char me[]="tenTripleCalc"; size_t II, NN, size[NRRD_DIM_MAX]; double (*ins)(void *, size_t, double), (*lup)(const void *, size_t); if (!( nout && nten )) { biffAddf(TEN, "%s: got NULL pointer", me); return 1; } if (airEnumValCheck(tenTripleType, ttype)) { biffAddf(TEN, "%s: got invalid %s (%d)", me, tenTripleType->name, ttype); return 1; } if (tenTensorCheck(nten, nrrdTypeDefault, AIR_FALSE, AIR_TRUE)) { biffAddf(TEN, "%s: didn't get a valid DT array", me); return 1; } if (!( nrrdTypeFloat == nten->type || nrrdTypeDouble == nten->type )) { biffAddf(TEN, "%s: need input type %s or %s, not %s\n", me, airEnumStr(nrrdType, nrrdTypeFloat), airEnumStr(nrrdType, nrrdTypeFloat), airEnumStr(nrrdType, nten->type)); } nrrdAxisInfoGet_nva(nten, nrrdAxisInfoSize, size); size[0] = 3; if (nrrdMaybeAlloc_nva(nout, nten->type, nten->dim, size)) { biffMovef(TEN, NRRD, "%s: couldn't alloc output", me); return 1; } NN = nrrdElementNumber(nten)/7; lup = nrrdDLookup[nten->type]; ins = nrrdDInsert[nten->type]; for (II=0; II<NN; II++) { double ten[7], trip[3]; unsigned int vv; for (vv=0; vv<7; vv++) { ten[vv] = lup(nten->data, vv + 7*II); } tenTripleCalcSingle_d(trip, ttype, ten); for (vv=0; vv<3; vv++) { ins(nout->data, vv + 3*II, trip[vv]); } } if (nrrdAxisInfoCopy(nout, nten, NULL, (NRRD_AXIS_INFO_SIZE_BIT))) { biffMovef(TEN, NRRD, "%s: couldn't copy axis info", me); return 1; } nout->axis[0].kind = nrrdKindUnknown; if (nrrdBasicInfoCopy(nout, nten, NRRD_BASIC_INFO_ALL ^ NRRD_BASIC_INFO_SPACE)) { biffAddf(TEN, "%s:", me); return 1; } return 0; }
int coilStart(coilContext *cctx) { char me[]="coilStart", err[BIFF_STRLEN]; int valIdx, valLen; coil_t (*lup)(const void*, size_t), *val; unsigned tidx, elIdx; if (!cctx) { sprintf(err, "%s: got NULL pointer", me); biffAdd(COIL, err); return 1; } cctx->task = (coilTask **)calloc(cctx->numThreads, sizeof(coilTask *)); if (!(cctx->task)) { sprintf(err, "%s: couldn't allocate array of tasks", me); biffAdd(COIL, err); return 1; } /* we create tasks for ALL threads, including me, thread 0 */ cctx->task[0] = NULL; for (tidx=0; tidx<cctx->numThreads; tidx++) { cctx->task[tidx] = _coilTaskNew(cctx, tidx); if (!(cctx->task[tidx])) { sprintf(err, "%s: couldn't allocate task %d", me, tidx); biffAdd(COIL, err); return 1; } } cctx->finished = AIR_FALSE; if (cctx->numThreads > 1) { cctx->nextSliceMutex = airThreadMutexNew(); cctx->filterBarrier = airThreadBarrierNew(cctx->numThreads); cctx->updateBarrier = airThreadBarrierNew(cctx->numThreads); } /* initialize the values in cctx->nvol */ val = (coil_t*)(cctx->nvol->data); valLen = cctx->kind->valLen; #if COIL_TYPE_FLOAT lup = nrrdFLookup[cctx->nin->type]; #else lup = nrrdDLookup[cctx->nin->type]; #endif for (elIdx=0; elIdx<cctx->size[0]*cctx->size[1]*cctx->size[2]; elIdx++) { for (valIdx=0; valIdx<valLen; valIdx++) { val[valIdx + 0*valLen] = lup(cctx->nin->data, valIdx + valLen*elIdx); val[valIdx + 1*valLen] = 0; } val += 2*valLen; } /* start threads 1 and up running; they'll all hit filterBarrier */ if (cctx->numThreads > 1) { for (tidx=1; tidx<cctx->numThreads; tidx++) { if (cctx->verbose > 1) { fprintf(stderr, "%s: spawning thread %d\n", me, tidx); } airThreadStart(cctx->task[tidx]->thread, _coilWorker, (void *)(cctx->task[tidx])); } } /* set things as though we've just finished an update phase */ cctx->nextSlice = cctx->size[2]; cctx->todoFilter = AIR_TRUE; cctx->todoUpdate = AIR_FALSE; return 0; }
int main(int argc, char *argv[]) { char *me, *outS; hestOpt *hopt; hestParm *hparm; airArray *mop; char *err; Nrrd *nin, *nhist; double vmin, vmax, rmax, val, cent[2], rad; int bins[2], sx, sy, xi, yi, ridx, hidx, rbins, hbins; NrrdRange *range; double (*lup)(const void *v, size_t I), *hist; me = argv[0]; mop = airMopNew(); hparm = hestParmNew(); hopt = NULL; airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways); hestOptAdd(&hopt, "i", "nin", airTypeOther, 1, 1, &nin, NULL, "input image", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "b", "rbins hbins", airTypeInt, 2, 2, bins, NULL, "# of histogram bins: radial and value"); hestOptAdd(&hopt, "min", "value", airTypeDouble, 1, 1, &vmin, "nan", "Value at low end of histogram. Defaults to lowest value " "found in input nrrd."); hestOptAdd(&hopt, "max", "value", airTypeDouble, 1, 1, &vmax, "nan", "Value at high end of histogram. Defaults to highest value " "found in input nrrd."); hestOptAdd(&hopt, "rmax", "max radius", airTypeDouble, 1, 1, &rmax, "nan", "largest radius to include in histogram"); hestOptAdd(&hopt, "c", "center x, y", airTypeDouble, 2, 2, cent, NULL, "The center point around which to build radial histogram"); hestOptAdd(&hopt, "o", "filename", airTypeString, 1, 1, &outS, "-", "file to write histogram to"); hestParseOrDie(hopt, argc-1, argv+1, hparm, me, histradInfo, AIR_TRUE, AIR_TRUE, AIR_TRUE); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); if (2 != nin->dim) { fprintf(stderr, "%s: need 2-D input (not %d-D)\n", me, nin->dim); airMopError(mop); return 1; } rbins = bins[0]; hbins = bins[1]; nhist = nrrdNew(); airMopAdd(mop, nhist, (airMopper)nrrdNuke, airMopAlways); if (nrrdMaybeAlloc_va(nhist, nrrdTypeDouble, 2, AIR_CAST(size_t, rbins), AIR_CAST(size_t, hbins))) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: couldn't allocate histogram:\n%s", me, err); airMopError(mop); return 1; } if (!( AIR_EXISTS(vmin) && AIR_EXISTS(vmax) )) { range = nrrdRangeNewSet(nin, nrrdStateBlind8BitRange); airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); vmin = AIR_EXISTS(vmin) ? vmin : range->min; vmax = AIR_EXISTS(vmax) ? vmax : range->max; } #define DIST(x0, y0, x1, y1) (sqrt((x0-x1)*(x0-x1) + (y0-y1)*(y0-y1))) sx = nin->axis[0].size; sy = nin->axis[1].size; if (!AIR_EXISTS(rmax)) { rmax = 0; rmax = AIR_MAX(rmax, DIST(cent[0], cent[1], 0, 0)); rmax = AIR_MAX(rmax, DIST(cent[0], cent[1], sx-1, 0)); rmax = AIR_MAX(rmax, DIST(cent[0], cent[1], 0, sy-1)); rmax = AIR_MAX(rmax, DIST(cent[0], cent[1], sx-1, sy-1)); } lup = nrrdDLookup[nin->type]; hist = (double*)(nhist->data); for (xi=0; xi<sx; xi++) { for (yi=0; yi<sy; yi++) { rad = DIST(cent[0], cent[1], xi, yi); if (!AIR_IN_OP(0, rad, rmax)) { continue; } val = lup(nin->data, xi + sx*yi); if (!AIR_IN_OP(vmin, val, vmax)) { continue; } ridx = airIndex(0, rad, rmax, rbins); hidx = airIndex(vmin, val, vmax, hbins); hist[ridx + rbins*hidx] += 1; } } nhist->axis[0].min = 0; nhist->axis[0].max = rmax; nhist->axis[1].min = vmin; nhist->axis[1].max = vmax; if (nrrdSave(outS, nhist, NULL)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: couldn't save output:\n%s", me, err); airMopError(mop); return 1; } airMopOkay(mop); exit(0); }
/* ******** nrrdHisto() ** ** makes a 1D histogram of a given size and type ** ** pre-NrrdRange policy: ** this looks at nin->min and nin->max to see if they are both non-NaN. ** If so, it uses these as the range of the histogram, otherwise it ** finds the min and max present in the volume. If nin->min and nin->max ** are being used as the histogram range, then values which fall outside ** this are ignored (they don't contribute to the histogram). ** ** post-NrrdRange policy: */ int nrrdHisto(Nrrd *nout, const Nrrd *nin, const NrrdRange *_range, const Nrrd *nwght, size_t bins, int type) { static const char me[]="nrrdHisto", func[]="histo"; size_t I, num, idx; airArray *mop; NrrdRange *range; double min, max, eps, val, count, incr, (*lup)(const void *v, size_t I); if (!(nin && nout)) { /* _range and nwght can be NULL */ biffAddf(NRRD, "%s: got NULL pointer", me); return 1; } if (nout == nin) { biffAddf(NRRD, "%s: nout==nin disallowed", me); return 1; } if (!(bins > 0)) { biffAddf(NRRD, "%s: bins value (" _AIR_SIZE_T_CNV ") invalid", me, bins); return 1; } if (airEnumValCheck(nrrdType, type) || nrrdTypeBlock == type) { biffAddf(NRRD, "%s: invalid nrrd type %d", me, type); return 1; } if (nwght) { if (nout==nwght) { biffAddf(NRRD, "%s: nout==nwght disallowed", me); return 1; } if (nrrdTypeBlock == nwght->type) { biffAddf(NRRD, "%s: nwght type %s invalid", me, airEnumStr(nrrdType, nrrdTypeBlock)); return 1; } if (!nrrdSameSize(nin, nwght, AIR_TRUE)) { biffAddf(NRRD, "%s: nwght size mismatch with nin", me); return 1; } lup = nrrdDLookup[nwght->type]; } else { lup = NULL; } if (nrrdMaybeAlloc_va(nout, type, 1, bins)) { biffAddf(NRRD, "%s: failed to alloc histo array (len " _AIR_SIZE_T_CNV ")", me, bins); return 1; } mop = airMopNew(); /* nout->axis[0].size set */ nout->axis[0].spacing = AIR_NAN; nout->axis[0].thickness = AIR_NAN; if (nout && AIR_EXISTS(nout->axis[0].min) && AIR_EXISTS(nout->axis[0].max)) { /* HEY: total hack to externally nail down min and max of histogram: use the min and max already set on axis[0] */ /* HEY: shouldn't this blatent hack be further restricted by also checking the existence of range->min and range->max ? */ min = nout->axis[0].min; max = nout->axis[0].max; } else { if (_range) { range = nrrdRangeCopy(_range); nrrdRangeSafeSet(range, nin, nrrdBlind8BitRangeState); } else { range = nrrdRangeNewSet(nin, nrrdBlind8BitRangeState); } airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); min = range->min; max = range->max; nout->axis[0].min = min; nout->axis[0].max = max; } eps = (min == max ? 1.0 : 0.0); nout->axis[0].center = nrrdCenterCell; /* nout->axis[0].label set below */ /* make histogram */ num = nrrdElementNumber(nin); for (I=0; I<num; I++) { val = nrrdDLookup[nin->type](nin->data, I); if (AIR_EXISTS(val)) { if (val < min || val > max+eps) { /* value is outside range; ignore it */ continue; } if (AIR_IN_CL(min, val, max)) { idx = airIndex(min, val, max+eps, AIR_CAST(unsigned int, bins)); /* printf("!%s: %d: index(%g, %g, %g, %d) = %d\n", me, (int)I, min, val, max, bins, idx); */ /* count is a double in order to simplify clamping the hit values to the representable range for nout->type */ count = nrrdDLookup[nout->type](nout->data, idx); incr = nwght ? lup(nwght->data, I) : 1; count = nrrdDClamp[nout->type](count + incr); nrrdDInsert[nout->type](nout->data, idx, count); } } } if (nrrdContentSet_va(nout, func, nin, "%d", bins)) { biffAddf(NRRD, "%s:", me); airMopError(mop); return 1; } nout->axis[0].label = (char *)airFree(nout->axis[0].label); nout->axis[0].label = (char *)airStrdup(nout->content); if (!nrrdStateKindNoop) { nout->axis[0].kind = nrrdKindDomain; } airMopOkay(mop); return 0; }
void _nrrdMeasureSkew(void *ans, int ansType, const void *line, int lineType, size_t len, double axmin, double axmax) { double val, diff, mean, vari, third, (*lup)(const void*, size_t); size_t ii, count; AIR_UNUSED(axmin); AIR_UNUSED(axmax); /* we don't try to do any one-pass short-cuts */ /* find the mean */ mean = 0; lup = nrrdDLookup[lineType]; if (nrrdTypeIsIntegral[lineType]) { count = len; for (ii=0; ii<len; ii++) { val = lup(line, ii); mean += val; } } else { count = 0; for (ii=0; ii<len; ii++) { val = lup(line, ii); if (AIR_EXISTS(val)) { count++; mean += val; } } } if (0 == count) { nrrdDStore[ansType](ans, AIR_NAN); return; } mean /= count; /* find the variance and third moment */ vari = third = 0; if (nrrdTypeIsIntegral[lineType]) { for (ii=0; ii<len; ii++) { diff = lup(line, ii) - mean; vari += diff*diff; third += diff*diff*diff; } } else { for (ii=0; ii<len; ii++) { val = lup(line, ii); if (AIR_EXISTS(val)) { diff = val - mean; vari += diff*diff; third += diff*diff*diff; } } } if (0 == vari) { /* why not have an existant value ... */ nrrdDStore[ansType](ans, 0); return; } vari /= count; third /= count; nrrdDStore[ansType](ans, third/(vari*sqrt(vari))); }
int gageDeconvolveSeparable(Nrrd *nout, const Nrrd *nin, const gageKind *kind, const NrrdKernelSpec *ksp, int typeOut) { static const char me[]="gageDeconvolveSeparable"; double *line, (*lup)(const void *, size_t), (*ins)(void *, size_t, double); airArray *mop; size_t lineLen, sx, sy, sz, idx, ii, jj; unsigned int vi, valLen; if (!(nout && nin && kind && ksp)) { biffAddf(GAGE, "%s: got NULL pointer", me); return 1; } if (!(nrrdTypeDefault == typeOut || !airEnumValCheck(nrrdType, typeOut))) { biffAddf(GAGE, "%s: typeOut %d not valid", me, typeOut); return 1; } if (!gageDeconvolveSeparableKnown(ksp)) { biffAddf(GAGE, "%s: separable deconv not known for %s kernel", me, ksp->kernel->name); return 1; } if (gageKindVolumeCheck(kind, nin)) { biffAddf(GAGE, "%s: given volume doesn't fit %s kind", me, kind->name); return 1; } if (nrrdTypeDefault == typeOut ? nrrdCopy(nout, nin) : nrrdConvert(nout, nin, typeOut)) { biffMovef(GAGE, NRRD, "%s: problem allocating output", me); return 1; } if (deconvTrivial(ksp)) { /* if there's no real work for the deconvolution, then by copying the values we're already done; bye */ return 0; } valLen = kind->valLen; sx = nin->axis[kind->baseDim + 0].size; sy = nin->axis[kind->baseDim + 1].size; sz = nin->axis[kind->baseDim + 2].size; lineLen = sx; lineLen = AIR_MAX(lineLen, sy); lineLen = AIR_MAX(lineLen, sz); lup = nrrdDLookup[nin->type]; ins = nrrdDInsert[nout->type]; mop = airMopNew(); line = AIR_CALLOC(lineLen*valLen, double); airMopAdd(mop, line, airFree, airMopAlways); /* process along X scanlines */ for (jj=0; jj<sy*sz; jj++) { /* xi = 0, yi = jj%sy, zi = jj/sy ==> xi + sx*(yi + sy*zi) == 0 + sx*(jj%sy + sy*(jj/sy)) == 0 + sx*jj */ idx = 0 + valLen*(0 + sx*jj); for (ii=0; ii<sx; ii++) { for (vi=0; vi<valLen; vi++) { line[ii + sx*vi] = lup(nin->data, idx + vi + valLen*ii); } } for (vi=0; vi<valLen; vi++) { deconvLine(line + sx*vi, sx, ksp); } for (ii=0; ii<sx; ii++) { for (vi=0; vi<valLen; vi++) { ins(nout->data, idx + vi + valLen*ii, line[ii + sx*vi]); } } } /* process along Y scanlines */ for (jj=0; jj<sx*sz; jj++) { /* xi = jj%sx, yi = 0, zi = jj/sx ==> xi + sx*(yi + sy*zi) == jj%sx + sx*(0 + sy*jj/sx) */ idx = 0 + valLen*((jj%sx) + sx*(0 + sy*(jj/sx))); for (ii=0; ii<sy; ii++) { for (vi=0; vi<valLen; vi++) { line[ii + sy*vi] = lup(nin->data, idx + vi + valLen*sx*ii); } } for (vi=0; vi<valLen; vi++) { deconvLine(line + sy*vi, sy, ksp); } for (ii=0; ii<sx; ii++) { for (vi=0; vi<valLen; vi++) { ins(nout->data, idx + vi + valLen*sx*ii, line[ii + sy*vi]); } } } /* process along Z scanlines */ for (jj=0; jj<sx*sy; jj++) { /* xi = jj%sx, yi = jj/sx, zi = 0 ==> xi + sx*(yi + sy*zi) == jj%sx + sx*(jj/sx + sy*0) == jj%sx + sx*(jj/sx) == jj */ idx = 0 + valLen*jj; for (ii=0; ii<sz; ii++) { for (vi=0; vi<valLen; vi++) { line[ii + sz*vi] = lup(nin->data, idx + vi + valLen*sx*sy*ii); } } for (vi=0; vi<valLen; vi++) { deconvLine(line + sz*vi, sz, ksp); } for (ii=0; ii<sx; ii++) { for (vi=0; vi<valLen; vi++) { ins(nout->data, idx + vi + valLen*sx*sy*ii, line[ii + sz*vi]); } } } airMopOkay(mop); return 0; }
int gageDeconvolve(Nrrd *_nout, double *lastDiffP, const Nrrd *nin, const gageKind *kind, const NrrdKernelSpec *ksp, int typeOut, unsigned int maxIter, int saveAnyway, double step, double epsilon, int verbose) { static const char me[]="gageDeconvolve"; gageContext *ctx[2]; gagePerVolume *pvl[2]; double *out[2], *val[2], alpha, (*lup)(const void *, size_t), meandiff=0; const double *ans[2]; Nrrd *nout[2]; airArray *mop; unsigned int sx, sy, sz, xi, yi, zi, anslen, thiz=0, last, inIdx, iter; int E, valItem; if (!(_nout && lastDiffP && nin && kind && ksp)) { biffAddf(GAGE, "%s: got NULL pointer", me); return 1; } if (!(nrrdTypeDefault == typeOut || !airEnumValCheck(nrrdType, typeOut))) { biffAddf(GAGE, "%s: typeOut %d not valid", me, typeOut); return 1; } if (!( maxIter >= 1 )) { biffAddf(GAGE, "%s: need maxIter >= 1 (not %u)", me, maxIter); return 1; } if (!( epsilon >= 0 )) { biffAddf(GAGE, "%s: need epsilon >= 0.0 (not %g)", me, epsilon); return 1; } /* this once changed from 0 to 1, but is unlikely to change again */ valItem = 1; mop = airMopNew(); for (iter=0; iter<2; iter++) { nout[iter] = nrrdNew(); airMopAdd(mop, nout[iter], (airMopper)nrrdNuke, airMopAlways); if (nrrdConvert(nout[iter], nin, nrrdTypeDouble)) { biffMovef(GAGE, NRRD, "%s: couldn't allocate working buffer %u", me, iter); airMopError(mop); return 1; } ctx[iter] = gageContextNew(); airMopAdd(mop, ctx[iter], (airMopper)gageContextNix, airMopAlways); E = 0; if (!E) E |= !(pvl[iter] = gagePerVolumeNew(ctx[iter], nout[iter], kind)); if (!E) E |= gagePerVolumeAttach(ctx[iter], pvl[iter]); if (!E) E |= gageKernelSet(ctx[iter], gageKernel00, ksp->kernel, ksp->parm); if (!E) E |= gageQueryItemOn(ctx[iter], pvl[iter], valItem); if (!E) E |= gageUpdate(ctx[iter]); if (E) { biffAddf(GAGE, "%s: trouble setting up context %u", me, iter); airMopError(mop); return 1; } out[iter] = AIR_CAST(double*, nout[iter]->data); ans[iter] = gageAnswerPointer(ctx[iter], pvl[iter], valItem); } anslen = kind->table[valItem].answerLength; lup = nrrdDLookup[nin->type]; alpha = ksp->kernel->eval1_d(0.0, ksp->parm); sx = ctx[0]->shape->size[0]; sy = ctx[0]->shape->size[1]; sz = ctx[0]->shape->size[2]; for (iter=0; iter<maxIter; iter++) { thiz = (iter+1) % 2; last = (iter+0) % 2; val[thiz] = out[thiz]; val[last] = out[last]; inIdx = 0; meandiff = 0; for (zi=0; zi<sz; zi++) { for (yi=0; yi<sy; yi++) { for (xi=0; xi<sx; xi++) { unsigned int ai; double in, aa; gageProbe(ctx[last], xi, yi, zi); for (ai=0; ai<anslen; ai++) { in = lup(nin->data, ai + anslen*inIdx); aa = ans[last][ai]; val[thiz][ai] = val[last][ai] + step*(in - aa)/alpha; meandiff += 2*(in - aa)*(in - aa)/(DBL_EPSILON + in*in + aa*aa); } val[thiz] += anslen; val[last] += anslen; ++inIdx; } } } meandiff /= sx*sy*sz; if (verbose) { fprintf(stderr, "%s: iter %u meandiff = %g\n", me, iter, meandiff); } if (meandiff < epsilon) { /* we have indeed converged while iter < maxIter */ break; } } if (iter == maxIter) { if (!saveAnyway) { biffAddf(GAGE, "%s: failed to converge in %u iterations, meandiff = %g", me, maxIter, meandiff); airMopError(mop); return 1; } else { if (verbose) { fprintf(stderr, "%s: at maxIter %u; err %g still > thresh %g\n", me, iter, meandiff, epsilon); } } } if (nrrdClampConvert(_nout, nout[thiz], (nrrdTypeDefault == typeOut ? nin->type : typeOut))) { biffAddf(GAGE, "%s: couldn't create output", me); airMopError(mop); return 1; } *lastDiffP = meandiff; airMopOkay(mop); return 0; }
int main(int argc, char *argv[]) { char *me, *err; hestOpt *hopt=NULL; airArray *mop; char *outTenS, *outCovarS, *outRmvS; int seed, E; unsigned int NN; Nrrd *_ninTen, *ninTen, *ngrad, *_ninB0, *ninB0, *nmask, *noutCovar, *noutTen, *noutRmv, *ntbuff; float sigma, bval; size_t sizeX, sizeY, sizeZ; tenEstimateContext *tec; int axmap[NRRD_DIM_MAX], randrot; mop = airMopNew(); me = argv[0]; hestOptAdd(&hopt, "i", "ten", airTypeOther, 1, 1, &_ninTen, NULL, "input tensor volume", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "n", "#sim", airTypeUInt, 1, 1, &NN, "100", "number of simulations to run"); hestOptAdd(&hopt, "seed", "seed", airTypeInt, 1, 1, &seed, "42", "seed value for RNG which creates noise"); hestOptAdd(&hopt, "r", "reference field", airTypeOther, 1, 1, &_ninB0, NULL, "reference anatomical scan, with no diffusion weighting", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "rr", NULL, airTypeOther, 0, 0, &randrot, NULL, "randomize gradient set orientation"); hestOptAdd(&hopt, "g", "grad list", airTypeOther, 1, 1, &ngrad, "", "gradient list, one row per diffusion-weighted image", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "b", "b", airTypeFloat, 1, 1, &bval, "1000", "b value for simulated scan"); hestOptAdd(&hopt, "sigma", "sigma", airTypeFloat, 1, 1, &sigma, "0.0", "Rician noise parameter"); hestOptAdd(&hopt, "ot", "filename", airTypeString, 1, 1, &outTenS, "tout.nrrd", "file to write output tensor nrrd to"); hestOptAdd(&hopt, "oc", "filename", airTypeString, 1, 1, &outCovarS, "cout.nrrd", "file to write output covariance nrrd to"); hestOptAdd(&hopt, "or", "filename", airTypeString, 1, 1, &outRmvS, "rout.nrrd", "file to write output R_i means, variances to"); hestParseOrDie(hopt, argc-1, argv+1, NULL, me, info, AIR_TRUE, AIR_TRUE, AIR_TRUE); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); if (tenGradientCheck(ngrad, nrrdTypeDefault, 7)) { airMopAdd(mop, err = biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: problem with gradient list:\n%s\n", me, err); airMopError(mop); return 1; } if (tenTensorCheck(_ninTen, nrrdTypeDefault, AIR_TRUE, AIR_TRUE)) { airMopAdd(mop, err = biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: didn't like input:\n%s\n", me, err); airMopError(mop); return 1; } sizeX = _ninTen->axis[1].size; sizeY = _ninTen->axis[2].size; sizeZ = _ninTen->axis[3].size; if (!(3 == _ninB0->dim && sizeX == _ninB0->axis[0].size && sizeY == _ninB0->axis[1].size && sizeZ == _ninB0->axis[2].size)) { fprintf(stderr, "%s: given B0 (%u-D) volume not 3-D " _AIR_SIZE_T_CNV "x" _AIR_SIZE_T_CNV "x" _AIR_SIZE_T_CNV, me, _ninB0->dim, sizeX, sizeY, sizeZ); airMopError(mop); return 1; } ninTen = nrrdNew(); airMopAdd(mop, ninTen, (airMopper)nrrdNuke, airMopOnError); nmask = nrrdNew(); airMopAdd(mop, nmask, (airMopper)nrrdNuke, airMopOnError); ninB0 = nrrdNew(); airMopAdd(mop, ninB0, (airMopper)nrrdNuke, airMopOnError); noutCovar = nrrdNew(); airMopAdd(mop, noutCovar, (airMopper)nrrdNuke, airMopOnError); noutTen = nrrdNew(); airMopAdd(mop, noutTen, (airMopper)nrrdNuke, airMopOnError); noutRmv = nrrdNew(); airMopAdd(mop, noutRmv, (airMopper)nrrdNuke, airMopOnError); ntbuff = nrrdNew(); airMopAdd(mop, ntbuff, (airMopper)nrrdNuke, airMopOnError); if (nrrdConvert(ninTen, _ninTen, nrrdTypeDouble) || nrrdSlice(nmask, ninTen, 0, 0) || nrrdConvert(ninB0, _ninB0, nrrdTypeDouble) || nrrdMaybeAlloc_va(noutTen, nrrdTypeDouble, 4, AIR_CAST(size_t, 7), sizeX, sizeY, sizeZ) || nrrdMaybeAlloc_va(noutCovar, nrrdTypeDouble, 4, AIR_CAST(size_t, 21), sizeX, sizeY, sizeZ) || nrrdMaybeAlloc_va(noutRmv, nrrdTypeDouble, 4, AIR_CAST(size_t, 6), sizeX, sizeY, sizeZ) || nrrdMaybeAlloc_va(ntbuff, nrrdTypeDouble, 2, AIR_CAST(size_t, 7), NN)) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble setting up tec:\n%s\n", me, err); airMopError(mop); return 1; } tec = tenEstimateContextNew(); airMopAdd(mop, tec, (airMopper)tenEstimateContextNix, airMopAlways); E = 0; if (!E) E |= tenEstimateMethodSet(tec, tenEstimate1MethodLLS); if (!E) E |= tenEstimateValueMinSet(tec, 0.000000001); if (!E) E |= tenEstimateGradientsSet(tec, ngrad, bval, AIR_TRUE); if (!E) E |= tenEstimateThresholdSet(tec, 0, 0); if (!E) E |= tenEstimateUpdate(tec); if (E) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble setting up tec:\n%s\n", me, err); airMopError(mop); return 1; } airSrandMT(seed); fprintf(stderr, "!%s: randrot = %d\n", me, randrot); if (1) { unsigned int II; unsigned int nsamp; double *inTen, *outTen, *outCovar, *outRmv, *dwibuff, (*lup)(const void *, size_t); char doneStr[AIR_STRLEN_SMALL]; dwibuff = AIR_CAST(double *, calloc(ngrad->axis[1].size, sizeof(double))); airMopAdd(mop, dwibuff, airFree, airMopAlways); nsamp = sizeX*sizeY*sizeZ; inTen = AIR_CAST(double *, ninTen->data); lup = nrrdDLookup[nrrdTypeDouble]; outTen = AIR_CAST(double *, noutTen->data); outCovar = AIR_CAST(double *, noutCovar->data); outRmv = AIR_CAST(double *, noutRmv->data); fprintf(stderr, "!%s: simulating ... ", me); fflush(stderr); for (II=0; II<nsamp; II++) { if (!(II % sizeX)) { fprintf(stderr, "%s", airDoneStr(0, II, nsamp, doneStr)); fflush(stderr); } if (csimDo(outTen, outCovar, outRmv + 0, outRmv + 3, ntbuff, tec, dwibuff, sigma, bval, lup(ninB0->data, II), NN, randrot, inTen)) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble:\n%s\n", me, err); airMopError(mop); return 1; } inTen += 7; outTen += 7; outCovar += 21; outRmv += 6; } fprintf(stderr, "%s\n", airDoneStr(0, II, nsamp, doneStr)); }