int nrrdSimpleResample(Nrrd *nout, Nrrd *nin, const NrrdKernel *kernel, const double *parm, const size_t *samples, const double *scalings) { char me[]="nrrdSimpleResample", err[BIFF_STRLEN]; NrrdResampleInfo *info; int p, np, center; unsigned ai; if (!(nout && nin && kernel && (samples || scalings))) { sprintf(err, "%s: not NULL pointer", me); biffAdd(NRRD, err); return 1; } if (!(info = nrrdResampleInfoNew())) { sprintf(err, "%s: can't allocate resample info struct", me); biffAdd(NRRD, err); return 1; } np = kernel->numParm; for (ai=0; ai<nin->dim; ai++) { info->kernel[ai] = kernel; if (samples) { info->samples[ai] = samples[ai]; } else { center = _nrrdCenter(nin->axis[ai].center); if (nrrdCenterCell == center) { info->samples[ai] = (size_t)(nin->axis[ai].size*scalings[ai]); } else { info->samples[ai] = (size_t)((nin->axis[ai].size - 1) *scalings[ai]) + 1; } } for (p=0; p<np; p++) info->parm[ai][p] = parm[p]; /* set the min/max for this axis if not already set to something */ if (!( AIR_EXISTS(nin->axis[ai].min) && AIR_EXISTS(nin->axis[ai].max) )) nrrdAxisInfoMinMaxSet(nin, ai, nrrdDefaultCenter); info->min[ai] = nin->axis[ai].min; info->max[ai] = nin->axis[ai].max; } /* we go with the defaults (enstated by _nrrdResampleInfoInit()) for all the remaining fields */ if (nrrdSpatialResample(nout, nin, info)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); return 1; } info = nrrdResampleInfoNix(info); return 0; }
int unrrdu_resampleMain(int argc, char **argv, char *me, hestParm *hparm) { hestOpt *opt = NULL; char *out, *err; Nrrd *nin, *nout; int type, bb, pret, norenorm, older, E, defaultCenter, verbose; unsigned int scaleLen, ai, samplesOut; airArray *mop; float *scale; double padVal; NrrdResampleInfo *info; NrrdResampleContext *rsmc; NrrdKernelSpec *unuk; mop = airMopNew(); info = nrrdResampleInfoNew(); airMopAdd(mop, info, (airMopper)nrrdResampleInfoNix, airMopAlways); hparm->elideSingleOtherDefault = AIR_FALSE; hestOptAdd(&opt, "old", NULL, airTypeInt, 0, 0, &older, NULL, "instead of using the new nrrdResampleContext implementation, " "use the old nrrdSpatialResample implementation"); hestOptAdd(&opt, "s,size", "sz0", airTypeOther, 1, -1, &scale, NULL, "For each axis, information about how many samples in output:\n " "\b\bo \"=\": leave this axis completely untouched: no " "resampling whatsoever\n " "\b\bo \"x<float>\": multiply the number of input samples by " "<float>, and round to the nearest integer, to get the number " "of output samples. Use \"x1\" to resample the axis but leave " "the number of samples unchanged\n " "\b\bo \"<int>\": exact number of output samples", &scaleLen, NULL, &unrrduHestScaleCB); hestOptAdd(&opt, "k,kernel", "kern", airTypeOther, 1, 1, &unuk, "cubic:0,0.5", "The kernel to use for resampling. " "Kernels logically live in the input index space for upsampling, " "and in the output index space for downsampling. " "Possibilities include:\n " "\b\bo \"box\": nearest neighbor interpolation\n " "\b\bo \"cheap\": nearest neighbor interpolation for upsampling, " "and non-blurring sub-sampling (pick subset of input samples) " "on downsampling\n " "\b\bo \"tent\": linear interpolation\n " "\b\bo \"cubic:B,C\": Mitchell/Netravali BC-family of " "cubics:\n " "\t\t\"cubic:1,0\": B-spline; maximal blurring\n " "\t\t\"cubic:0,0.5\": Catmull-Rom; good interpolating kernel\n " "\b\bo \"quartic:A\": 1-parameter family of " "interpolating quartics (\"quartic:0.0834\" is most accurate)\n " "\b\bo \"hann:R\": Hann (cosine bell) windowed sinc, radius R\n " "\b\bo \"black:R\": Blackman windowed sinc, radius R\n " "\b\bo \"gauss:S,C\": Gaussian blurring, with standard deviation " "S and cut-off at C standard deviations", NULL, NULL, nrrdHestKernelSpec); hestOptAdd(&opt, "nrn", NULL, airTypeInt, 0, 0, &norenorm, NULL, "don't do per-pass kernel weight renormalization. " "Doing the renormalization is not a big performance hit, and " "is sometimes needed to avoid \"grating\" on non-integral " "down-sampling. Disabling the renormalization is needed for " "correct results with artificially narrow kernels. "); hestOptAdd(&opt, "b,boundary", "behavior", airTypeEnum, 1, 1, &bb, "bleed", "How to handle samples beyond the input bounds:\n " "\b\bo \"pad\": use some specified value\n " "\b\bo \"bleed\": extend border values outward\n " "\b\bo \"wrap\": wrap-around to other side", NULL, nrrdBoundary); hestOptAdd(&opt, "v,value", "value", airTypeDouble, 1, 1, &padVal, "0.0", "for \"pad\" boundary behavior, pad with this value"); hestOptAdd(&opt, "t,type", "type", airTypeOther, 1, 1, &type, "default", "type to save OUTPUT as. By default (not using this option), " "the output type is the same as the input type", NULL, NULL, &unrrduHestMaybeTypeCB); hestOptAdd(&opt, "cheap", NULL, airTypeInt, 0, 0, &(info->cheap), NULL, "DEPRECATED: the \"-k cheap\" option is the new (and more " "reliable) way to access this functionality. \"-cheap\" is " "only here for legacy use in combination with \"-old\".\n " "When downsampling (reducing number of samples), don't " "try to do correct filtering by scaling kernel to match " "new (stretched) index space; keep it in old index space. " "When used in conjunction with \"-k box\", this can implement " "subsampling which chooses every Nth value. "); hestOptAdd(&opt, "c,center", "center", airTypeEnum, 1, 1, &defaultCenter, (nrrdCenterCell == nrrdDefaultCenter ? "cell" : "node"), "(not available with \"-old\") " "default centering of axes when input nrrd " "axes don't have a known centering: \"cell\" or \"node\" ", NULL, nrrdCenter); hestOptAdd(&opt, "verbose", NULL, airTypeInt, 0, 0, &verbose, NULL, "(not available with \"-old\") " "turn on verbosity "); OPT_ADD_NIN(nin, "input nrrd"); OPT_ADD_NOUT(out, "output nrrd"); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_resampleInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); if (scaleLen != nin->dim) { fprintf(stderr, "%s: # sampling sizes (%d) != input nrrd dimension (%d)\n", me, scaleLen, nin->dim); airMopError(mop); return 1; } if (!older) { rsmc = nrrdResampleContextNew(); rsmc->verbose = verbose; airMopAdd(mop, rsmc, (airMopper)nrrdResampleContextNix, airMopAlways); E = AIR_FALSE; if (!E) E |= nrrdResampleDefaultCenterSet(rsmc, defaultCenter); if (!E) E |= nrrdResampleNrrdSet(rsmc, nin); for (ai=0; ai<nin->dim; ai++) { switch((int)scale[0 + 2*ai]) { case 0: /* no resampling */ if (!E) E |= nrrdResampleKernelSet(rsmc, ai, NULL, NULL); break; case 1: /* scaling of input # samples */ if (!E) E |= nrrdResampleKernelSet(rsmc, ai, unuk->kernel, unuk->parm); samplesOut = AIR_ROUNDUP(scale[1 + 2*ai]*nin->axis[ai].size); if (!E) E |= nrrdResampleSamplesSet(rsmc, ai, samplesOut); break; case 2: /* explicit # of samples */ if (!E) E |= nrrdResampleKernelSet(rsmc, ai, unuk->kernel, unuk->parm); samplesOut = (size_t)scale[1 + 2*ai]; if (!E) E |= nrrdResampleSamplesSet(rsmc, ai, samplesOut); break; } if (!E) E |= nrrdResampleRangeFullSet(rsmc, ai); } if (!E) E |= nrrdResampleBoundarySet(rsmc, bb); if (!E) E |= nrrdResampleTypeOutSet(rsmc, type); if (!E) E |= nrrdResamplePadValueSet(rsmc, padVal); if (!E) E |= nrrdResampleRenormalizeSet(rsmc, !norenorm); if (!E) E |= nrrdResampleExecute(rsmc, nout); if (E) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error resampling nrrd:\n%s", me, err); airMopError(mop); return 1; } } else { for (ai=0; ai<nin->dim; ai++) { /* this may be over-written below */ info->kernel[ai] = unuk->kernel; switch((int)scale[0 + 2*ai]) { case 0: /* no resampling */ info->kernel[ai] = NULL; break; case 1: /* scaling of input # samples */ info->samples[ai] = AIR_ROUNDUP(scale[1 + 2*ai]*nin->axis[ai].size); break; case 2: /* explicit # of samples */ info->samples[ai] = (size_t)scale[1 + 2*ai]; break; } memcpy(info->parm[ai], unuk->parm, NRRD_KERNEL_PARMS_NUM*sizeof(double)); if (info->kernel[ai] && (!( AIR_EXISTS(nin->axis[ai].min) && AIR_EXISTS(nin->axis[ai].max))) ) { nrrdAxisInfoMinMaxSet(nin, ai, (nin->axis[ai].center ? nin->axis[ai].center : nrrdDefaultCenter)); } info->min[ai] = nin->axis[ai].min; info->max[ai] = nin->axis[ai].max; } info->boundary = bb; info->type = type; info->padValue = padVal; info->renormalize = !norenorm; if (nrrdSpatialResample(nout, nin, info)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error resampling nrrd:\n%s", me, err); airMopError(mop); return 1; } } SAVE(out, nout, NULL); airMopOkay(mop); return 0; }