int nrrdApplyMulti1DRegMap(Nrrd *nout, const Nrrd *nin, const NrrdRange *_range, const Nrrd *nmmap, int typeOut, int rescale) { char me[]="nrrdApplyMulti1DRegMap", err[BIFF_STRLEN]; NrrdRange *range; airArray *mop; if (!(nout && nmmap && nin)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(NRRD, err); return 1; } mop = airMopNew(); if (_range) { range = nrrdRangeCopy(_range); nrrdRangeSafeSet(range, nin, nrrdBlind8BitRangeState); } else { range = nrrdRangeNewSet(nin, nrrdBlind8BitRangeState); } airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); if (_nrrdApply1DSetUp(nout, nin, range, nmmap, kindRmap, typeOut, rescale, AIR_TRUE) || _nrrdApply1DLutOrRegMap(nout, nin, range, nmmap, AIR_TRUE, rescale, AIR_TRUE)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
int unrrdu_histaxMain(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *err; Nrrd *nin, *nout; int type, bins, pret, blind8BitRange; unsigned int axis; double min, max; airArray *mop; NrrdRange *range; OPT_ADD_AXIS(axis, "axis to histogram along"); hestOptAdd(&opt, "b,bin", "bins", airTypeInt, 1, 1, &bins, NULL, "# of bins in histogram"); OPT_ADD_TYPE(type, "output type", "uchar"); hestOptAdd(&opt, "min,minimum", "value", airTypeDouble, 1, 1, &min, "nan", "Value at low end of histogram. Defaults to lowest value " "found in input nrrd."); hestOptAdd(&opt, "max,maximum", "value", airTypeDouble, 1, 1, &max, "nan", "Value at high end of histogram. Defaults to highest value " "found in input nrrd."); hestOptAdd(&opt, "blind8", "bool", airTypeBool, 1, 1, &blind8BitRange, nrrdStateBlind8BitRange ? "true" : "false", "Whether to know the range of 8-bit data blindly " "(uchar is always [0,255], signed char is [-128,127])."); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_histaxInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); range = nrrdRangeNew(min, max); airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); nrrdRangeSafeSet(range, nin, blind8BitRange); if (nrrdHistoAxis(nout, nin, range, axis, bins, type)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error doing axis histogramming:\n%s", me, err); airMopError(mop); return 1; } SAVE(out, nout, NULL); airMopOkay(mop); return 0; }
int unrrdu_gammaMain(int argc, const char **argv, const char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *err; Nrrd *nin, *nout; double min, max, gamma; airArray *mop; int pret, blind8BitRange; NrrdRange *range; hestOptAdd(&opt, "g,gamma", "gamma", airTypeDouble, 1, 1, &gamma, NULL, "gamma > 1.0 brightens; gamma < 1.0 darkens. " "Negative gammas invert values (like in xv). "); hestOptAdd(&opt, "min,minimum", "value", airTypeDouble, 1, 1, &min, "nan", "Value to implicitly map to 0.0 prior to calling pow(). " "Defaults to lowest value found in input nrrd."); hestOptAdd(&opt, "max,maximum", "value", airTypeDouble, 1, 1, &max, "nan", "Value to implicitly map to 1.0 prior to calling pow(). " "Defaults to highest value found in input nrrd."); hestOptAdd(&opt, "blind8", "bool", airTypeBool, 1, 1, &blind8BitRange, nrrdStateBlind8BitRange ? "true" : "false", "Whether to know the range of 8-bit data blindly " "(uchar is always [0,255], signed char is [-128,127])."); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_gammaInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); range = nrrdRangeNew(min, max); airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); nrrdRangeSafeSet(range, nin, blind8BitRange); if (nrrdArithGamma(nout, nin, range, gamma)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error doing gamma:\n%s", me, err); airMopError(mop); return 1; } SAVE(out, nout, NULL); airMopOkay(mop); return 0; }
int unrrdu_imapMain(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *err; Nrrd *nin, *nmap, *nacl, *nout; airArray *mop; NrrdRange *range=NULL; unsigned int aclLen; int typeOut, rescale, pret, blind8BitRange; double min, max; hestOptAdd(&opt, "m,map", "map", airTypeOther, 1, 1, &nmap, NULL, "irregular map to map input nrrd through", NULL, NULL, nrrdHestNrrd); hestOptAdd(&opt, "l,length", "aclLen", airTypeUInt, 1, 1, &aclLen, "0", "length of accelerator array, used to try to speed-up " "task of finding between which pair of control points " "a given value lies. Not terribly useful for small maps " "(about 10 points or less). Use 0 to turn accelorator off. "); hestOptAdd(&opt, "r,rescale", NULL, airTypeInt, 0, 0, &rescale, NULL, "rescale the input values from the input range to the " "map domain"); hestOptAdd(&opt, "min,minimum", "value", airTypeDouble, 1, 1, &min, "nan", "Low end of input range. Defaults to lowest value " "found in input nrrd. Explicitly setting this is useful " "only with rescaling (\"-r\")"); hestOptAdd(&opt, "max,maximum", "value", airTypeDouble, 1, 1, &max, "nan", "High end of input range. Defaults to highest value " "found in input nrrd. Explicitly setting this is useful " "only with rescaling (\"-r\")"); hestOptAdd(&opt, "blind8", "bool", airTypeBool, 1, 1, &blind8BitRange, nrrdStateBlind8BitRange ? "true" : "false", "Whether to know the range of 8-bit data blindly " "(uchar is always [0,255], signed char is [-128,127]). " "Explicitly setting this is useful only with rescaling (\"-r\")"); hestOptAdd(&opt, "t,type", "type", airTypeOther, 1, 1, &typeOut, "default", "specify the type (\"int\", \"float\", etc.) of the " "output nrrd. " "By default (not using this option), the output type " "is the map's type.", NULL, NULL, &unrrduHestMaybeTypeCB); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_imapInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); if (aclLen) { nacl = nrrdNew(); airMopAdd(mop, nacl, (airMopper)nrrdNuke, airMopAlways); if (nrrd1DIrregAclGenerate(nacl, nmap, aclLen)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble generating accelerator:\n%s", me, err); airMopError(mop); return 1; } } else { nacl = NULL; } if (rescale) { range = nrrdRangeNew(min, max); airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); nrrdRangeSafeSet(range, nin, blind8BitRange); } if (nrrdTypeDefault == typeOut) { typeOut = nmap->type; } /* some very non-exhaustive tests seemed to indicate that the accelerator does not in fact reliably speed anything up. This of course depends on the size of the imap (# points), but chances are most imaps will have only a handful of points, in which case the binary search in _nrrd1DIrregFindInterval() will finish quickly ... */ if (nrrdApply1DIrregMap(nout, nin, range, nmap, nacl, typeOut, rescale)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble applying map:\n%s", me, err); airMopError(mop); return 1; } SAVE(out, nout, NULL); airMopOkay(mop); return 0; }
int unrrdu_lutMain(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *err; Nrrd *nin, *nlut, *nout; airArray *mop; int typeOut, rescale, pret, blind8BitRange; double min, max; NrrdRange *range=NULL; hestOptAdd(&opt, "m,map", "lut", airTypeOther, 1, 1, &nlut, NULL, "lookup table to map input nrrd through", NULL, NULL, nrrdHestNrrd); hestOptAdd(&opt, "r,rescale", NULL, airTypeInt, 0, 0, &rescale, NULL, "rescale the input values from the input range to the " "lut domain. The lut domain is either explicitly " "defined by the axis min,max along axis 0 or 1, or, it " "is implicitly defined as zero to the length of that axis " "minus one."); hestOptAdd(&opt, "min,minimum", "value", airTypeDouble, 1, 1, &min, "nan", "Low end of input range. Defaults to lowest value " "found in input nrrd. Explicitly setting this is useful " "only with rescaling (\"-r\")"); hestOptAdd(&opt, "max,maximum", "value", airTypeDouble, 1, 1, &max, "nan", "High end of input range. Defaults to highest value " "found in input nrrd. Explicitly setting this is useful " "only with rescaling (\"-r\")"); hestOptAdd(&opt, "blind8", "bool", airTypeBool, 1, 1, &blind8BitRange, nrrdStateBlind8BitRange ? "true" : "false", "Whether to know the range of 8-bit data blindly " "(uchar is always [0,255], signed char is [-128,127]). " "Explicitly setting this is useful only with rescaling (\"-r\")"); hestOptAdd(&opt, "t,type", "type", airTypeOther, 1, 1, &typeOut, "default", "specify the type (\"int\", \"float\", etc.) of the " "output nrrd. " "By default (not using this option), the output type " "is the lut's type.", NULL, NULL, &unrrduHestMaybeTypeCB); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_lutInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); /* see comment rmap.c */ if (!( AIR_EXISTS(nlut->axis[nlut->dim - 1].min) && AIR_EXISTS(nlut->axis[nlut->dim - 1].max) )) { rescale = AIR_TRUE; } if (rescale) { range = nrrdRangeNew(min, max); airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); nrrdRangeSafeSet(range, nin, blind8BitRange); } if (nrrdTypeDefault == typeOut) { typeOut = nlut->type; } if (nrrdApply1DLut(nout, nin, range, nlut, typeOut, rescale)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble applying LUT:\n%s", me, err); airMopError(mop); return 1; } SAVE(out, nout, NULL); airMopOkay(mop); return 0; }
int unrrdu_rmapMain(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *err; Nrrd *nin, *nmap, *nout; airArray *mop; NrrdRange *range=NULL; int typeOut, rescale, pret, blind8BitRange; double min, max; hestOptAdd(&opt, "m,map", "map", airTypeOther, 1, 1, &nmap, NULL, "regular map to map input nrrd through", NULL, NULL, nrrdHestNrrd); hestOptAdd(&opt, "r,rescale", NULL, airTypeInt, 0, 0, &rescale, NULL, "rescale the input values from the input range to the " "map domain. The map domain is either explicitly " "defined by the axis min,max along axis 0 or 1, or, it " "is implicitly defined as zero to the length of " "that axis minus one."); hestOptAdd(&opt, "min,minimum", "value", airTypeDouble, 1, 1, &min, "nan", "Low end of input range. Defaults to lowest value " "found in input nrrd. Explicitly setting this is useful " "only with rescaling (\"-r\") or if the map domain is only " "implicitly defined"); hestOptAdd(&opt, "max,maximum", "value", airTypeDouble, 1, 1, &max, "nan", "High end of input range. Defaults to highest value " "found in input nrrd. Explicitly setting this is useful " "only with rescaling (\"-r\") or if the map domain is only " "implicitly defined"); hestOptAdd(&opt, "blind8", "bool", airTypeBool, 1, 1, &blind8BitRange, nrrdStateBlind8BitRange ? "true" : "false", "Whether to know the range of 8-bit data blindly " "(uchar is always [0,255], signed char is [-128,127]). " "Explicitly setting this is useful " "only with rescaling (\"-r\") or if the map domain is only " "implicitly defined"); hestOptAdd(&opt, "t,type", "type", airTypeOther, 1, 1, &typeOut, "default", "specify the type (\"int\", \"float\", etc.) of the " "output nrrd. " "By default (not using this option), the output type " "is the map's type.", NULL, NULL, &unrrduHestMaybeTypeCB); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_rmapInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); /* here is a big difference between unu and nrrd: we enforce rescaling any time that the map domain is implicit. This is how the pre-1.6 functionality is recreated. Also, whenever there is rescaling we pass a NrrdRange to reflect the (optional) user range specification, instead of letting nrrdApply1DRegMap find the input range itself (by passing a NULL NrrdRange). */ if (!( AIR_EXISTS(nmap->axis[nmap->dim - 1].min) && AIR_EXISTS(nmap->axis[nmap->dim - 1].max) )) { rescale = AIR_TRUE; } if (rescale) { range = nrrdRangeNew(min, max); airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); nrrdRangeSafeSet(range, nin, blind8BitRange); } if (nrrdTypeDefault == typeOut) { typeOut = nmap->type; } if (nrrdApply1DRegMap(nout, nin, range, nmap, typeOut, rescale)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble applying map:\n%s", me, err); airMopError(mop); return 1; } SAVE(out, nout, NULL); airMopOkay(mop); return 0; }
/* ******** nrrdApply1DIrregMap() ** ** Linear interpolation between irregularly spaced control points. ** Obviously, the location of the control point has to be given ** explicitly. The map nrrd must have dimension 2, and each ** control point is represented by a scanline along axis 0. The ** first value is the position of the control point, and the remaining ** value(s) are linearly weighted according to the position of the ** input value among the control point locations. ** ** To allow "coloring" of non-existant values -inf, NaN, and +inf, if ** the very first value of the map (the location of the first control ** point) is non-existant, then the first three control point locations ** must be -inf, NaN, and +inf, in that order, and the information ** about these points will be used for corresponding input values. ** Doing this makes everything slower, however, because airFPClass_f() ** is called on every single value. ** ** This assumes that nrrd1DIrregMapCheck has been called on "nmap", ** and that nrrd1DIrregAclCheck has been called on "nacl" (if it is ** non-NULL). */ int nrrdApply1DIrregMap(Nrrd *nout, const Nrrd *nin, const NrrdRange *_range, const Nrrd *nmap, const Nrrd *nacl, int typeOut, int rescale) { char me[]="nrrdApply1DIrregMap", err[BIFF_STRLEN]; size_t N, I; int i, *acl, entLen, posLen, aclLen, mapIdx, aclIdx, entSize, colSize, inSize, lo, hi, baseI; double val, *pos, domMin, domMax, mapIdxFrac, (*mapLup)(const void *v, size_t I), (*inLoad)(const void *v), (*outInsert)(void *v, size_t I, double d); char *inData, *outData, *entData0, *entData1; NrrdRange *range; airArray *mop; if (!(nout && nmap && nin)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(NRRD, err); return 1; } mop = airMopNew(); if (_range) { range = nrrdRangeCopy(_range); nrrdRangeSafeSet(range, nin, nrrdBlind8BitRangeState); } else { range = nrrdRangeNewSet(nin, nrrdBlind8BitRangeState); } airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); if (_nrrdApply1DSetUp(nout, nin, range, nmap, kindImap, typeOut, rescale, AIR_FALSE)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); airMopError(mop); return 1; } if (nacl && nrrd1DIrregAclCheck(nacl)) { sprintf(err, "%s: given acl isn't valid", me); biffAdd(NRRD, err); airMopError(mop); return 1; } if (nacl) { acl = (int *)nacl->data; aclLen = nacl->axis[1].size; } else { acl = NULL; aclLen = 0; } pos = _nrrd1DIrregMapDomain(&posLen, &baseI, nmap); if (!pos) { sprintf(err, "%s: couldn't determine domain", me); biffAdd(NRRD, err); airMopError(mop); return 1; } airMopAdd(mop, pos, airFree, airMopAlways); mapLup = nrrdDLookup[nmap->type]; inData = (char *)nin->data; inLoad = nrrdDLoad[nin->type]; inSize = nrrdElementSize(nin); mapLup = nrrdDLookup[nmap->type]; entLen = nmap->axis[0].size; /* entLen is really 1 + entry length */ entSize = entLen*nrrdElementSize(nmap); colSize = (entLen-1)*nrrdTypeSize[typeOut]; outData = (char *)nout->data; outInsert = nrrdDInsert[nout->type]; domMin = pos[0]; domMax = pos[posLen-1]; N = nrrdElementNumber(nin); for (I=0; I<N; I++, inData += inSize, outData += colSize) { val = inLoad(inData); /* _VV = ( (AIR_EXISTS(val) && (21 == (int)(-val))) || 22400 < I ); */ /* if (_VV) fprintf(stderr, "##%s: (%d) val = % 31.15f\n", me, (int)I, val); */ if (!AIR_EXISTS(val)) { /* got a non-existant value */ if (baseI) { /* and we know how to deal with them */ switch (airFPClass_d(val)) { case airFP_NEG_INF: mapIdx = 0; break; case airFP_SNAN: case airFP_QNAN: mapIdx = 1; break; case airFP_POS_INF: mapIdx = 2; break; default: mapIdx = 0; fprintf(stderr, "%s: PANIC: non-existant value/class %g/%d " "not handled\n", me, val, airFPClass_d(val)); exit(1); } entData0 = (char*)(nmap->data) + mapIdx*entSize; for (i=1; i<entLen; i++) { outInsert(outData, i-1, mapLup(entData0, i)); } continue; /* we're done! (with this value) */ } else { /* we don't know how to properly deal with this non-existant value: we use the first entry, and then fall through to code below */ mapIdx = 0; mapIdxFrac = 0.0; } } else { /* we have an existant value */ if (rescale) { val = AIR_AFFINE(range->min, val, range->max, domMin, domMax); /* if (_VV) fprintf(stderr, " rescaled --> % 31.15f\n", val); */ } val = AIR_CLAMP(domMin, val, domMax); if (acl) { aclIdx = airIndex(domMin, val, domMax, aclLen); lo = acl[0 + 2*aclIdx]; hi = acl[1 + 2*aclIdx]; } else { lo = 0; hi = posLen-2; } if (lo < hi) { mapIdx = _nrrd1DIrregFindInterval(pos, val, lo, hi); } else { /* acl did its job ==> lo == hi */ mapIdx = lo; } } mapIdxFrac = AIR_AFFINE(pos[mapIdx], val, pos[mapIdx+1], 0.0, 1.0); /* if (_VV) fprintf(stderr, "##%s: val=\n% 31.15f --> " "mapIdx,frac = %d,\n% 31.15f\n", me, val, mapIdx, mapIdxFrac); */ entData0 = (char*)(nmap->data) + (baseI+mapIdx)*entSize; entData1 = (char*)(nmap->data) + (baseI+mapIdx+1)*entSize; /* if (_VV) fprintf(stderr, "##%s: 2; %d/\n% 31.15f --> entLen=%d " "baseI=%d -->\n", me, mapIdx, mapIdxFrac, entLen, baseI); */ for (i=1; i<entLen; i++) { val = ((1-mapIdxFrac)*mapLup(entData0, i) + mapIdxFrac*mapLup(entData1, i)); /* if (_VV) fprintf(stderr, "% 31.15f\n", val); */ outInsert(outData, i-1, val); } /* if (_VV) fprintf(stderr, "##%s: 3\n", me); */ } airMopOkay(mop); return 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; }
/* ******** nrrdHistoAxis ** ** replace scanlines along one scanline with a histogram of the scanline ** ** 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 ** ** By its very nature, and by the simplicity of this implemention, ** this can be a slow process due to terrible memory locality. User ** may want to permute axes before and after this, but that can be ** slow too... */ int nrrdHistoAxis(Nrrd *nout, const Nrrd *nin, const NrrdRange *_range, unsigned int hax, size_t bins, int type) { static const char me[]="nrrdHistoAxis", func[]="histax"; int map[NRRD_DIM_MAX]; unsigned int ai, hidx; size_t szIn[NRRD_DIM_MAX], szOut[NRRD_DIM_MAX], size[NRRD_DIM_MAX], coordIn[NRRD_DIM_MAX], coordOut[NRRD_DIM_MAX]; size_t I, hI, num; double val, count; airArray *mop; NrrdRange *range; if (!(nin && nout)) { 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 (!( hax <= nin->dim-1 )) { biffAddf(NRRD, "%s: axis %d is not in range [0,%d]", me, hax, nin->dim-1); return 1; } mop = airMopNew(); if (_range) { range = nrrdRangeCopy(_range); nrrdRangeSafeSet(range, nin, nrrdBlind8BitRangeState); } else { range = nrrdRangeNewSet(nin, nrrdBlind8BitRangeState); } airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size); size[hax] = bins; if (nrrdMaybeAlloc_nva(nout, type, nin->dim, size)) { biffAddf(NRRD, "%s: failed to alloc output nrrd", me); airMopError(mop); return 1; } /* copy axis information */ for (ai=0; ai<nin->dim; ai++) { map[ai] = ai != hax ? (int)ai : -1; } nrrdAxisInfoCopy(nout, nin, map, NRRD_AXIS_INFO_NONE); /* axis hax now has to be set manually */ nout->axis[hax].size = bins; nout->axis[hax].spacing = AIR_NAN; /* min and max convey the information */ nout->axis[hax].thickness = AIR_NAN; nout->axis[hax].min = range->min; nout->axis[hax].max = range->max; nout->axis[hax].center = nrrdCenterCell; if (nin->axis[hax].label) { nout->axis[hax].label = (char *)calloc(strlen("histax()") + strlen(nin->axis[hax].label) + 1, sizeof(char)); if (nout->axis[hax].label) { sprintf(nout->axis[hax].label, "histax(%s)", nin->axis[hax].label); } else { biffAddf(NRRD, "%s: couldn't allocate output label", me); airMopError(mop); return 1; } } else { nout->axis[hax].label = NULL; } if (!nrrdStateKindNoop) { nout->axis[hax].kind = nrrdKindDomain; } /* the skinny: we traverse the input samples in linear order, and increment the bin in the histogram for the scanline we're in. This is not terribly clever, and the memory locality is a disaster */ nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, szIn); nrrdAxisInfoGet_nva(nout, nrrdAxisInfoSize, szOut); memset(coordIn, 0, NRRD_DIM_MAX*sizeof(size_t)); num = nrrdElementNumber(nin); for (I=0; I<num; I++) { /* get input nrrd value and compute its histogram index */ val = nrrdDLookup[nin->type](nin->data, I); if (AIR_EXISTS(val) && AIR_IN_CL(range->min, val, range->max)) { hidx = airIndex(range->min, val, range->max, AIR_CAST(unsigned int, bins)); memcpy(coordOut, coordIn, nin->dim*sizeof(size_t)); coordOut[hax] = (unsigned int)hidx; NRRD_INDEX_GEN(hI, coordOut, szOut, nout->dim); count = nrrdDLookup[nout->type](nout->data, hI); count = nrrdDClamp[nout->type](count + 1); nrrdDInsert[nout->type](nout->data, hI, count); } NRRD_COORD_INCR(coordIn, szIn, nin->dim, 0); }
int unrrdu_mlutMain(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *err; Nrrd *nin, **_nmlut, *nmlut, *nout; airArray *mop; int typeOut, rescale, pret, blind8BitRange; unsigned int _nmlutLen, mapAxis; double min, max; NrrdRange *range=NULL; hestOptAdd(&opt, "m,map", "mlut", airTypeOther, 1, -1, &_nmlut, NULL, "one nrrd of lookup tables to map input nrrd through, or, " "list of nrrds which contain the individual entries of " "the lookup table at each voxel, which will be joined together.", &_nmlutLen, NULL, nrrdHestNrrd); hestOptAdd(&opt, "r,rescale", NULL, airTypeInt, 0, 0, &rescale, NULL, "rescale the input values from the input range to the " "lut domain. The lut domain is either explicitly " "defined by the axis min,max along axis 0 or 1, or, it " "is implicitly defined as zero to the length of that axis " "minus one."); hestOptAdd(&opt, "min,minimum", "value", airTypeDouble, 1, 1, &min, "nan", "Low end of input range. Defaults to lowest value " "found in input nrrd. Explicitly setting this is useful " "only with rescaling (\"-r\")"); hestOptAdd(&opt, "max,maximum", "value", airTypeDouble, 1, 1, &max, "nan", "High end of input range. Defaults to highest value " "found in input nrrd. Explicitly setting this is useful " "only with rescaling (\"-r\")"); hestOptAdd(&opt, "blind8", "bool", airTypeBool, 1, 1, &blind8BitRange, nrrdStateBlind8BitRange ? "true" : "false", "Whether to know the range of 8-bit data blindly " "(uchar is always [0,255], signed char is [-128,127]). " "Explicitly setting this is useful only with rescaling (\"-r\")"); hestOptAdd(&opt, "t,type", "type", airTypeOther, 1, 1, &typeOut, "default", "specify the type (\"int\", \"float\", etc.) of the " "output nrrd. " "By default (not using this option), the output type " "is the lut's type.", NULL, NULL, &unrrduHestMaybeTypeCB); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_mlutInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); /* by the end of this block we need to have nmlut and mapAxis */ if (1 == _nmlutLen) { /* we got the mlut as a single nrrd */ nmlut = _nmlut[0]; mapAxis = nmlut->dim - nin->dim - 1; /* its not our job to do real error checking ... */ mapAxis = AIR_MIN(mapAxis, nmlut->dim - 1); } else { /* we have to join together multiple nrrds to get the mlut */ nmlut = nrrdNew(); airMopAdd(mop, nmlut, (airMopper)nrrdNuke, airMopAlways); /* assume that mlut component nrrds are all compatible sizes, nrrdJoin will fail if they aren't */ mapAxis = _nmlut[0]->dim - nin->dim; if (nrrdJoin(nmlut, (const Nrrd**)_nmlut, _nmlutLen, mapAxis, AIR_TRUE)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble joining mlut:\n%s", me, err); airMopError(mop); return 1; } /* set these if they were given, they'll be NaN otherwise */ nmlut->axis[mapAxis].min = min; nmlut->axis[mapAxis].max = max; } if (!( AIR_EXISTS(nmlut->axis[mapAxis].min) && AIR_EXISTS(nmlut->axis[mapAxis].max) )) { rescale = AIR_TRUE; } if (rescale) { range = nrrdRangeNew(min, max); airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); nrrdRangeSafeSet(range, nin, blind8BitRange); } if (nrrdTypeDefault == typeOut) { typeOut = nmlut->type; } if (nrrdApplyMulti1DLut(nout, nin, range, nmlut, typeOut, rescale)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble applying multi-LUT:\n%s", me, err); airMopError(mop); return 1; } SAVE(out, nout, NULL); airMopOkay(mop); return 0; }
int unrrdu_histoMain(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *err; Nrrd *nin, *nout, *nwght; int type, pret, blind8BitRange; unsigned int bins; double min, max; NrrdRange *range; airArray *mop; hestOptAdd(&opt, "b,bins", "num", airTypeUInt, 1, 1, &bins, NULL, "# of bins in histogram"); hestOptAdd(&opt, "w,weight", "nweight", airTypeOther, 1, 1, &nwght, "", "how to weigh contributions to histogram. By default " "(not using this option), the increment is one bin count per " "sample, but by giving a nrrd, the value in the nrrd at the " "corresponding location will be the bin count increment ", NULL, NULL, nrrdHestNrrd); hestOptAdd(&opt, "min,minimum", "value", airTypeDouble, 1, 1, &min, "nan", "Value at low end of histogram. Defaults to lowest value " "found in input nrrd."); hestOptAdd(&opt, "max,maximum", "value", airTypeDouble, 1, 1, &max, "nan", "Value at high end of histogram. Defaults to highest value " "found in input nrrd."); hestOptAdd(&opt, "blind8", "bool", airTypeBool, 1, 1, &blind8BitRange, nrrdStateBlind8BitRange ? "true" : "false", "Whether to know the range of 8-bit data blindly " "(uchar is always [0,255], signed char is [-128,127])."); OPT_ADD_TYPE(type, "type to use for bins in output histogram", "uint"); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_histoInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); /* If the input nrrd never specified min and max, then they'll be AIR_NAN, and nrrdRangeSafeSet will find them, and will do so according to blind8BitRange */ range = nrrdRangeNew(min, max); airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); nrrdRangeSafeSet(range, nin, blind8BitRange); if (nrrdHisto(nout, nin, range, nwght, bins, type)) { err = biffGet(NRRD); fprintf(stderr, "%s: error calculating histogram:\n%s", me, err); free(err); return 1; } SAVE(out, nout, NULL); 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 unrrdu_lut2Main(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *err; Nrrd *nin, *nlut, *nout, *ntmp[2]; airArray *mop; int typeOut, rescale[2], pret, blind8BitRange; double min[2], max[2]; NrrdRange *range[2]={NULL,NULL}; unsigned int mapAxis, rai; hestOptAdd(&opt, "m,map", "lut", airTypeOther, 1, 1, &nlut, NULL, "lookup table to map input nrrd through", NULL, NULL, nrrdHestNrrd); hestOptAdd(&opt, "r,rescale", "bool bool", airTypeBool, 2, 2, rescale, "false false", "rescale one or both of the input values from the " "input range to the lut domain. The lut domain is either " "explicitly defined by the axis min,max along axis 0 or 1, " "or, it is implicitly defined as zero to the length of that axis " "minus one."); hestOptAdd(&opt, "min,minimum", "min0 min1", airTypeDouble, 2, 2, min, "nan nan", "Low ends of input range. Defaults to lowest values " "found in input nrrd. Explicitly setting this is useful " "only with rescaling (\"-r\")"); hestOptAdd(&opt, "max,maximum", "max0 max1", airTypeDouble, 2, 2, max, "nan nan", "High end of input range. Defaults to highest values " "found in input nrrd. Explicitly setting this is useful " "only with rescaling (\"-r\")"); hestOptAdd(&opt, "blind8", "bool", airTypeBool, 1, 1, &blind8BitRange, nrrdStateBlind8BitRange ? "true" : "false", "Whether to know the range of 8-bit data blindly " "(uchar is always [0,255], signed char is [-128,127]). " "Explicitly setting this is useful only with rescaling (\"-r\")"); hestOptAdd(&opt, "t,type", "type", airTypeOther, 1, 1, &typeOut, "default", "specify the type (\"int\", \"float\", etc.) of the " "output nrrd. " "By default (not using this option), the output type " "is the lut's type.", NULL, NULL, &unrrduHestMaybeTypeCB); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_lut2InfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); if (!( nin->dim > 1 && 2 == nin->axis[0].size )) { fprintf(stderr, "%s: input nrrd dim must be > 1, and axis[0].size " "must be 2 (not " _AIR_SIZE_T_CNV ")", me, nin->axis[0].size); airMopError(mop); return 1; } mapAxis = nlut->dim - 2; if (!(0 == mapAxis || 1 == mapAxis)) { fprintf(stderr, "%s: dimension of lut should be 2 or 3, not %d", me, nlut->dim); airMopError(mop); return 1; } /* see comment in rmap.c */ for (rai=0; rai<=1; rai++) { if (!( AIR_EXISTS(nlut->axis[mapAxis + rai].min) && AIR_EXISTS(nlut->axis[mapAxis + rai].max) )) { rescale[rai] = AIR_TRUE; } if (rescale[rai]) { ntmp[rai] = nrrdNew(); airMopAdd(mop, ntmp[rai], AIR_CAST(airMopper, nrrdNuke), airMopAlways); if (nrrdSlice(ntmp[rai], nin, 0, rai)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble slicing input value %u:\n%s", me, rai, err); airMopError(mop); return 1; } range[rai] = nrrdRangeNew(min[rai], max[rai]); airMopAdd(mop, range[rai], (airMopper)nrrdRangeNix, airMopAlways); nrrdRangeSafeSet(range[rai], ntmp[rai], blind8BitRange); } } if (nrrdTypeDefault == typeOut) { typeOut = nlut->type; } if (nrrdApply2DLut(nout, nin, 0, range[0], range[1], nlut, typeOut, rescale[0], rescale[1])) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble applying 2-D LUT:\n%s", me, err); airMopError(mop); return 1; } SAVE(out, nout, NULL); airMopOkay(mop); return 0; }