int main(int argc, char *argv[]) { char *me; hestOpt *hopt = NULL; int center; double minPos, maxPos, pos, index, size; me = argv[0]; hestOptAdd(&hopt, NULL, "center", airTypeEnum, 1, 1, ¢er, NULL, "which centering applies to the quantized position.\n " "Possibilities are:\n " "\b\bo \"cell\": for histogram bins, quantized values, and " "pixels-as-squares\n " "\b\bo \"node\": for non-trivially interpolated " "sample points", NULL, nrrdCenter); hestOptAdd(&hopt, NULL, "minPos", airTypeDouble, 1, 1, &minPos, NULL, "smallest position associated with index 0"); hestOptAdd(&hopt, NULL, "maxPos", airTypeDouble, 1, 1, &maxPos, NULL, "highest position associated with highest index"); hestOptAdd(&hopt, NULL, "num", airTypeDouble, 1, 1, &size, NULL, "number of intervals into which position has been quantized"); hestOptAdd(&hopt, NULL, "index", airTypeDouble, 1, 1, &index, NULL, "the input index, to be converted to position"); hestParseOrDie(hopt, argc-1, argv+1, NULL, me, info, AIR_TRUE, AIR_TRUE, AIR_TRUE); pos = NRRD_POS(center, minPos, maxPos, size, index); printf("%g\n", pos); hestParseFree(hopt); hestOptFree(hopt); exit(0); }
/* ******** nrrdAxisInfoPos() ** ** given a nrrd, an axis, and a (floating point) index space position, ** return the position implied the axis's min, max, and center ** Does the opposite of nrrdAxisIdx(). ** ** does not use biff */ double nrrdAxisInfoPos(const Nrrd *nrrd, unsigned int ax, double idx) { int center; size_t size; double min, max; if (!( nrrd && ax <= nrrd->dim-1 )) { return AIR_NAN; } center = _nrrdCenter(nrrd->axis[ax].center); min = nrrd->axis[ax].min; max = nrrd->axis[ax].max; size = nrrd->axis[ax].size; return NRRD_POS(center, min, max, size, idx); }
int unrrdu_i2wMain(int argc, const char **argv, const char *me, hestParm *hparm) { hestOpt *opt = NULL; airArray *mop; int pret; char *err; int center; double minPos, maxPos, pos, indx, size; mop = airMopNew(); hestOptAdd(&opt, NULL, "center", airTypeEnum, 1, 1, ¢er, NULL, "which centering applies to the quantized position.\n " "Possibilities are:\n " "\b\bo \"cell\": for histogram bins, quantized values, and " "pixels-as-squares\n " "\b\bo \"node\": for non-trivially interpolated " "sample points", NULL, nrrdCenter); hestOptAdd(&opt, NULL, "minPos", airTypeDouble, 1, 1, &minPos, NULL, "smallest position associated with index 0"); hestOptAdd(&opt, NULL, "maxPos", airTypeDouble, 1, 1, &maxPos, NULL, "highest position associated with highest index"); hestOptAdd(&opt, NULL, "num", airTypeDouble, 1, 1, &size, NULL, "number of intervals into which position has been quantized"); hestOptAdd(&opt, NULL, "index", airTypeDouble, 1, 1, &indx, NULL, "the input index position, to be converted to world"); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_i2wInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); pos = NRRD_POS(center, minPos, maxPos, size, indx); printf("%g\n", pos); airMopOkay(mop); return 0; }
/* ** _nrrdResampleMakeWeightIndex() ** ** _allocate_ and fill the arrays of indices and weights that are ** needed to process all the scanlines along a given axis; also ** be so kind as to set the sampling ratio (<1: downsampling, ** new sample spacing larger, >1: upsampling, new sample spacing smaller) ** ** returns "dotLen", the number of input samples which are required ** for resampling this axis, or 0 if there was an error. Uses biff. */ int _nrrdResampleMakeWeightIndex(nrrdResample_t **weightP, int **indexP, double *ratioP, const Nrrd *nin, const NrrdResampleInfo *info, unsigned int ai) { char me[]="_nrrdResampleMakeWeightIndex", err[BIFF_STRLEN]; int sizeIn, sizeOut, center, dotLen, halfLen, *index, base, idx; nrrdResample_t minIn, maxIn, minOut, maxOut, spcIn, spcOut, ratio, support, integral, pos, idxD, wght; nrrdResample_t *weight; double parm[NRRD_KERNEL_PARMS_NUM]; int e, i; if (!(info->kernel[ai])) { sprintf(err, "%s: don't see a kernel for dimension %d", me, ai); biffAdd(NRRD, err); *weightP = NULL; *indexP = NULL; return 0; } center = _nrrdCenter(nin->axis[ai].center); sizeIn = nin->axis[ai].size; sizeOut = info->samples[ai]; minIn = AIR_CAST(nrrdResample_t, nin->axis[ai].min); maxIn = AIR_CAST(nrrdResample_t, nin->axis[ai].max); minOut = AIR_CAST(nrrdResample_t, info->min[ai]); maxOut = AIR_CAST(nrrdResample_t, info->max[ai]); spcIn = NRRD_SPACING(center, minIn, maxIn, sizeIn); spcOut = NRRD_SPACING(center, minOut, maxOut, sizeOut); *ratioP = ratio = spcIn/spcOut; support = AIR_CAST(nrrdResample_t, info->kernel[ai]->support(info->parm[ai])); integral = AIR_CAST(nrrdResample_t, info->kernel[ai]->integral(info->parm[ai])); /* fprintf(stderr, "!%s(%d): size{In,Out} = %d, %d, support = %f; ratio = %f\n", me, d, sizeIn, sizeOut, support, ratio); */ if (ratio > 1) { /* if upsampling, we need only as many samples as needed for interpolation with the given kernel */ dotLen = (int)(2*ceil(support)); } else { /* if downsampling, we need to use all the samples covered by the stretched out version of the kernel */ if (info->cheap) { dotLen = (int)(2*ceil(support)); } else { dotLen = (int)(2*ceil(support/ratio)); } } /* fprintf(stderr, "!%s(%d): dotLen = %d\n", me, d, dotLen); */ weight = (nrrdResample_t*)calloc(sizeOut*dotLen, sizeof(nrrdResample_t)); index = (int*)calloc(sizeOut*dotLen, sizeof(int)); if (!(weight && index)) { sprintf(err, "%s: can't allocate weight and index arrays", me); biffAdd(NRRD, err); *weightP = NULL; *indexP = NULL; return 0; } /* calculate sample locations and do first pass on indices */ halfLen = dotLen/2; for (i=0; i<sizeOut; i++) { pos = AIR_CAST(nrrdResample_t, NRRD_POS(center, minOut, maxOut, sizeOut, i)); idxD = AIR_CAST(nrrdResample_t, NRRD_IDX(center, minIn, maxIn, sizeIn, pos)); base = (int)floor(idxD) - halfLen + 1; for (e=0; e<dotLen; e++) { index[e + dotLen*i] = base + e; weight[e + dotLen*i] = idxD - index[e + dotLen*i]; } /* ******** if (!i) { fprintf(stderr, "%s: sample locations:\n", me); } fprintf(stderr, "%s: %d (sample locations)\n ", me, i); for (e=0; e<dotLen; e++) { fprintf(stderr, "%d/%g ", index[e + dotLen*i], weight[e + dotLen*i]); } fprintf(stderr, "\n"); ******** */ } /* nrrdBoundaryPad, 1: fill with some user-specified value nrrdBoundaryBleed, 2: copy the last/first value out as needed nrrdBoundaryWrap, 3: wrap-around nrrdBoundaryWeight, 4: normalize the weighting on the existing samples; ONLY sensible for a strictly positive kernel which integrates to unity (as in blurring) */ /* figure out what to do with the out-of-range indices */ for (i=0; i<dotLen*sizeOut; i++) { idx = index[i]; if (!AIR_IN_CL(0, idx, sizeIn-1)) { switch(info->boundary) { case nrrdBoundaryPad: case nrrdBoundaryWeight: /* this will be further handled later */ idx = sizeIn; break; case nrrdBoundaryBleed: idx = AIR_CLAMP(0, idx, sizeIn-1); break; case nrrdBoundaryWrap: idx = AIR_MOD(idx, sizeIn); break; default: sprintf(err, "%s: boundary behavior %d unknown/unimplemented", me, info->boundary); biffAdd(NRRD, err); *weightP = NULL; *indexP = NULL; return 0; } index[i] = idx; } } /* run the sample locations through the chosen kernel. We play a sneaky trick on the kernel parameter 0 in case of downsampling to create the blurring of the old index space, but only if !cheap */ memcpy(parm, info->parm[ai], NRRD_KERNEL_PARMS_NUM*sizeof(double)); if (ratio < 1 && !(info->cheap)) { parm[0] /= ratio; } info->kernel[ai]->EVALN(weight, weight, dotLen*sizeOut, parm); /* ******** for (i=0; i<sizeOut; i++) { fprintf(stderr, "%s: %d (sample weights)\n ", me, i); for (e=0; e<dotLen; e++) { fprintf(stderr, "%d/%g ", index[e + dotLen*i], weight[e + dotLen*i]); } fprintf(stderr, "\n"); } ******** */ if (nrrdBoundaryWeight == info->boundary) { if (integral) { /* above, we set to sizeIn all the indices that were out of range. We now use that to determine the sum of the weights for the indices that were in-range */ for (i=0; i<sizeOut; i++) { wght = 0; for (e=0; e<dotLen; e++) { if (sizeIn != index[e + dotLen*i]) { wght += weight[e + dotLen*i]; } } for (e=0; e<dotLen; e++) { idx = index[e + dotLen*i]; if (sizeIn != idx) { weight[e + dotLen*i] *= integral/wght; } else { weight[e + dotLen*i] = 0; } } } } } else { /* try to remove ripple/grating on downsampling */ /* if (ratio < 1 && info->renormalize && integral) { */ if (info->renormalize && integral) { for (i=0; i<sizeOut; i++) { wght = 0; for (e=0; e<dotLen; e++) { wght += weight[e + dotLen*i]; } if (wght) { for (e=0; e<dotLen; e++) { /* this used to normalize the weights so that they summed to integral ("*= integral/wght"), which meant that if you use a very truncated Gaussian, then your over-all image brightness goes down. This seems very contrary to the whole point of renormalization. */ weight[e + dotLen*i] *= AIR_CAST(nrrdResample_t, 1.0/wght); } } } } } /* ******** fprintf(stderr, "%s: sample weights:\n", me); for (i=0; i<sizeOut; i++) { fprintf(stderr, "%s: %d\n ", me, i); wght = 0; for (e=0; e<dotLen; e++) { fprintf(stderr, "%d/%g ", index[e + dotLen*i], weight[e + dotLen*i]); wght += weight[e + dotLen*i]; } fprintf(stderr, " (sum = %g)\n", wght); } ******** */ *weightP = weight; *indexP = index; /* fprintf(stderr, "!%s: dotLen = %d\n", me, dotLen); */ return dotLen; }
int mossLinearTransform (Nrrd *nout, Nrrd *nin, float *bg, double *mat, mossSampler *msp, double xMin, double xMax, double yMin, double yMax, int xSize, int ySize) { char me[]="mossLinearTransform", err[BIFF_STRLEN]; int ncol, xi, yi, ci, ax0, xCent, yCent; float *val, (*ins)(void *v, size_t I, float f), (*clamp)(float val); double inv[6], xInPos, xOutPos, yInPos, yOutPos; if (!(nout && nin && mat && msp && !mossImageCheck(nin))) { sprintf(err, "%s: got NULL pointer or bad image", me); biffAdd(MOSS, err); return 1; } if (mossSamplerImageSet(msp, nin, bg) || mossSamplerUpdate(msp)) { sprintf(err, "%s: trouble with sampler", me); biffAdd(MOSS, err); return 1; } if (!( xMin != xMax && yMin != yMax && xSize > 1 && ySize > 1 )) { sprintf(err, "%s: bad args: {x,y}Min == {x,y}Max or {x,y}Size <= 1", me); biffAdd(MOSS, err); return 1; } ax0 = MOSS_AXIS0(nin); if (!( AIR_EXISTS(nin->axis[ax0+0].min) && AIR_EXISTS(nin->axis[ax0+0].max) && AIR_EXISTS(nin->axis[ax0+1].min) && AIR_EXISTS(nin->axis[ax0+1].max) )) { sprintf(err, "%s: input axis min,max not set on axes %d and %d", me, ax0+0, ax0+1); biffAdd(MOSS, err); return 1; } ncol = MOSS_NCOL(nin); if (mossImageAlloc(nout, nin->type, xSize, ySize, ncol)) { sprintf(err, "%s: ", me); biffAdd(MOSS, err); return 1; } val = (float*)calloc(ncol, sizeof(float)); if (nrrdCenterUnknown == nout->axis[ax0+0].center) nout->axis[ax0+0].center = _mossCenter(nin->axis[ax0+0].center); xCent = nout->axis[ax0+0].center; if (nrrdCenterUnknown == nout->axis[ax0+1].center) nout->axis[ax0+1].center = _mossCenter(nin->axis[ax0+1].center); yCent = nout->axis[ax0+1].center; nout->axis[ax0+0].min = xMin; nout->axis[ax0+0].max = xMax; nout->axis[ax0+1].min = yMin; nout->axis[ax0+1].max = yMax; ins = nrrdFInsert[nin->type]; clamp = nrrdFClamp[nin->type]; if (mossSamplerSample(val, msp, 0, 0)) { sprintf(err, "%s: trouble in sampler", me); free(val); biffAdd(MOSS, err); return 1; } mossMatInvert(inv, mat); for (yi=0; yi<ySize; yi++) { yOutPos = NRRD_POS(yCent, yMin, yMax, ySize, yi); for (xi=0; xi<xSize; xi++) { /* mossVerbose = ( (36 == xi && 72 == yi) || (37 == xi && 73 == yi) || (105 == xi && 175 == yi) ); */ xOutPos = NRRD_POS(xCent, xMin, xMax, xSize, xi); mossMatApply(&xInPos, &yInPos, inv, xOutPos, yOutPos); xInPos = NRRD_IDX(xCent, nin->axis[ax0+0].min, nin->axis[ax0+0].max, nin->axis[ax0+0].size, xInPos); yInPos = NRRD_IDX(yCent, nin->axis[ax0+1].min, nin->axis[ax0+1].max, nin->axis[ax0+1].size, yInPos); mossSamplerSample(val, msp, xInPos, yInPos); for (ci=0; ci<ncol; ci++) { ins(nout->data, ci + ncol*(xi + xSize*yi), clamp(val[ci])); } } } free(val); return 0; }