int unrrdu_minmaxDoit(char *me, char *inS, int blind8BitRange, FILE *fout) { char err[BIFF_STRLEN]; Nrrd *nrrd; NrrdRange *range; airArray *mop; mop = airMopNew(); airMopAdd(mop, nrrd=nrrdNew(), (airMopper)nrrdNuke, airMopAlways); if (nrrdLoad(nrrd, inS, NULL)) { sprintf(err, "%s: trouble loading \"%s\"", me, inS); biffMove(me, err, NRRD); airMopError(mop); return 1; } range = nrrdRangeNewSet(nrrd, blind8BitRange); airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); airSinglePrintf(fout, NULL, "min: %g\n", range->min); airSinglePrintf(fout, NULL, "max: %g\n", range->max); if (0 == range->min && 0 == range->max) { fprintf(fout, "# min == max == 0.0 exactly\n"); } if (range->hasNonExist) { fprintf(fout, "# has non-existent values\n"); } airMopOkay(mop); return 0; }
int main(int argc, char **argv) { char *me, *err; Nrrd *nrrd; NrrdRange *range; me = argv[0]; if (2 != argc) usage(me); nrrdStateVerboseIO = 10; if (nrrdLoad(nrrd=nrrdNew(), argv[1], NULL)) { fprintf(stderr, "%s: trouble loading \"%s\":\n%s", me, argv[1], err = biffGet(NRRD)); free(err); exit(1); } range = nrrdRangeNewSet(nrrd, nrrdBlind8BitRangeState); printf("%s: min = %g; max = %g, hasNonExist = %d\n", me, range->min, range->max, range->hasNonExist); nrrdNuke(nrrd); exit(0); }
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 main(int argc, char * argv[]) { Nrrd *nin = nrrdNew(); Nrrd *nquantized = nrrdNew(); char *biffErr; if(argc < 4) { fprintf(stderr,"Usage: %s centerx centery nrrd\n",argv[0]); return 1; } cx = atoi(argv[1]); cy = atoi(argv[2]); if(nrrdLoad(nin, argv[3], NULL)) { biffErr = biffGetDone(NRRD); fprintf(stderr, "Error reading file: %s\n", biffErr); free(biffErr); return 1; } printf("Read %d-dimensional nrrd of type %d (%s)\n", nin->dim, nin->type, airEnumStr(nrrdType, nin->type)); printf("Axis dimensions: %d x %d x %d\n", nin->axis[0].size, nin->axis[1].size, nin->axis[2].size); NrrdRange *range = nrrdRangeNewSet(nin, 0); printf("min: %g\tmax: %g\n", range->min, range->max); if(nrrdQuantize(nquantized, nin, range, 8)) { biffErr = biffGetDone(NRRD); fprintf(stderr, "Error quantizing: %s\n", biffErr); return 1; } process_slices(nquantized); nrrdRangeNix(range); nrrdNuke(nin); nrrdNuke(nquantized); return 0; }
int baneGkms_scatMain(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out[2], *perr, err[BIFF_STRLEN]; Nrrd *hvol, *nvgRaw, *nvhRaw, *nvgQuant, *nvhQuant; NrrdRange *vgRange, *vhRange; airArray *mop; int pret, E; double gamma; hestOptAdd(&opt, "g", "gamma", airTypeDouble, 1, 1, &gamma, "1.0", "gamma used to brighten/darken scatterplots. " "gamma > 1.0 brightens; gamma < 1.0 darkens. " "Negative gammas invert values (like in xv). "); hestOptAdd(&opt, "i", "hvolIn", airTypeOther, 1, 1, &hvol, NULL, "input histogram volume (from \"gkms hvol\")", NULL, NULL, nrrdHestNrrd); hestOptAdd(&opt, "o", "vgOut vhOut", airTypeString, 2, 2, out, NULL, "Filenames to use for two output scatterplots, (gradient " "magnitude versus value, and 2nd derivative versus value); " "can use PGM or PNG format"); mop = airMopNew(); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_baneGkms_scatInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nvgRaw = nrrdNew(); nvhRaw = nrrdNew(); nvgQuant = nrrdNew(); nvhQuant = nrrdNew(); airMopAdd(mop, nvgRaw, (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nvhRaw, (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nvgQuant, (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nvhQuant, (airMopper)nrrdNuke, airMopAlways); if (baneRawScatterplots(nvgRaw, nvhRaw, hvol, AIR_TRUE)) { sprintf(err, "%s: trouble creating raw scatterplots", me); biffAdd(BANE, err); airMopError(mop); return 1; } vgRange = nrrdRangeNewSet(nvgRaw, nrrdBlind8BitRangeFalse); vhRange = nrrdRangeNewSet(nvhRaw, nrrdBlind8BitRangeFalse); airMopAdd(mop, vgRange, (airMopper)nrrdRangeNix, airMopAlways); airMopAdd(mop, vhRange, (airMopper)nrrdRangeNix, airMopAlways); E = 0; if (!E) E |= nrrdArithGamma(nvgRaw, nvgRaw, vgRange, gamma); if (!E) E |= nrrdArithGamma(nvhRaw, nvhRaw, vhRange, gamma); if (!E) E |= nrrdQuantize(nvgQuant, nvgRaw, vgRange, 8); if (!E) E |= nrrdQuantize(nvhQuant, nvhRaw, vhRange, 8); if (E) { sprintf(err, "%s: trouble doing gamma or quantization", me); biffMove(BANE, err, NRRD); airMopError(mop); return 1; } if (!E) E |= nrrdSave(out[0], nvgQuant, NULL); if (!E) E |= nrrdSave(out[1], nvhQuant, NULL); if (E) { sprintf(err, "%s: trouble saving scatterplot images", me); biffMove(BANE, err, NRRD); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
int main(int argc, const char **argv) { const char *me; char *err; hestOpt *hopt=NULL; hestParm *hparm; airArray *mop; /* variables learned via hest */ Nrrd *nin; float camfr[3], camat[3], camup[3], camnc, camfc, camFOV; int camortho, hitandquit; unsigned int camsize[2]; double isovalue, sliso, isomin, isomax; /* boilerplate hest code */ me = argv[0]; mop = airMopNew(); hparm = hestParmNew(); hparm->respFileEnable = AIR_TRUE; airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways); /* setting up the command-line options */ hparm->respFileEnable = AIR_TRUE; hestOptAdd(&hopt, "i", "volume", airTypeOther, 1, 1, &nin, NULL, "input volume to isosurface", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "v", "isovalue", airTypeDouble, 1, 1, &isovalue, "nan", "isovalue at which to run Marching Cubes"); hestOptAdd(&hopt, "fr", "x y z", airTypeFloat, 3, 3, camfr, "3 4 5", "look-from point"); hestOptAdd(&hopt, "at", "x y z", airTypeFloat, 3, 3, camat, "0 0 0", "look-at point"); hestOptAdd(&hopt, "up", "x y z", airTypeFloat, 3, 3, camup, "0 0 1", "up direction"); hestOptAdd(&hopt, "nc", "dist", airTypeFloat, 1, 1, &(camnc), "-2", "at-relative near clipping distance"); hestOptAdd(&hopt, "fc", "dist", airTypeFloat, 1, 1, &(camfc), "2", "at-relative far clipping distance"); hestOptAdd(&hopt, "fov", "angle", airTypeFloat, 1, 1, &(camFOV), "20", "vertical field-of-view, in degrees. Full vertical " "extent of image plane subtends this angle."); hestOptAdd(&hopt, "sz", "s0 s1", airTypeUInt, 2, 2, &(camsize), "640 480", "# samples (horz vert) of image plane. "); hestOptAdd(&hopt, "ortho", NULL, airTypeInt, 0, 0, &(camortho), NULL, "use orthographic instead of (the default) " "perspective projection "); hestOptAdd(&hopt, "haq", NULL, airTypeBool, 0, 0, &(hitandquit), NULL, "save a screenshot rather than display the viewer"); hestParseOrDie(hopt, argc-1, argv+1, hparm, me, "demo program", AIR_TRUE, AIR_TRUE, AIR_TRUE); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); /* learn value range, and set initial isovalue if needed */ NrrdRange *range = nrrdRangeNewSet(nin, AIR_FALSE); airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways); isomin = range->min; isomax = range->max; if (!AIR_EXISTS(isovalue)) { isovalue = (isomin + isomax)/2; } /* first, make sure we can isosurface ok */ limnPolyData *lpld = limnPolyDataNew(); seekContext *sctx = seekContextNew(); airMopAdd(mop, sctx, (airMopper)seekContextNix, airMopAlways); sctx->pldArrIncr = nrrdElementNumber(nin); seekVerboseSet(sctx, 0); seekNormalsFindSet(sctx, AIR_TRUE); if (seekDataSet(sctx, nin, NULL, 0) || seekTypeSet(sctx, seekTypeIsocontour) || seekIsovalueSet(sctx, isovalue) || seekUpdate(sctx) || seekExtract(sctx, lpld)) { airMopAdd(mop, err=biffGetDone(SEEK), airFree, airMopAlways); fprintf(stderr, "trouble with isosurfacing:\n%s", err); airMopError(mop); return 1; } if (!lpld->xyzwNum) { fprintf(stderr, "%s: warning: No isocontour generated at isovalue %g\n", me, isovalue); } /* then create empty scene */ Hale::init(); Hale::Scene scene; /* then create viewer (in order to create the OpenGL context) */ Hale::Viewer viewer(camsize[0], camsize[1], "Iso", &scene); viewer.lightDir(glm::vec3(-1.0f, 1.0f, 3.0f)); viewer.camera.init(glm::vec3(camfr[0], camfr[1], camfr[2]), glm::vec3(camat[0], camat[1], camat[2]), glm::vec3(camup[0], camup[1], camup[2]), camFOV, (float)camsize[0]/camsize[1], camnc, camfc, camortho); viewer.refreshCB((Hale::ViewerRefresher)render); viewer.refreshData(&viewer); sliso = isovalue; viewer.slider(&sliso, isomin, isomax); viewer.current(); /* then create geometry, and add it to scene */ Hale::Polydata hply(lpld, true, // hply now owns lpld Hale::ProgramLib(Hale::preprogramAmbDiff2SideSolid)); scene.add(&hply); scene.drawInit(); render(&viewer); if (hitandquit) { seekIsovalueSet(sctx, isovalue); seekUpdate(sctx); seekExtract(sctx, lpld); hply.rebuffer(); render(&viewer); glfwWaitEvents(); render(&viewer); viewer.snap(); Hale::done(); airMopOkay(mop); return 0; } while(!Hale::finishing){ glfwWaitEvents(); if (viewer.sliding() && sliso != isovalue) { isovalue = sliso; printf("%s: isosurfacing at %g\n", me, isovalue); seekIsovalueSet(sctx, isovalue); seekUpdate(sctx); seekExtract(sctx, lpld); hply.rebuffer(); } render(&viewer); } /* clean exit; all okay */ Hale::done(); 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 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); }
/* ******** 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; }