Пример #1
0
/*
******** coilOutputGet
**
** slice the present intermediate volume to get an output.
**
** No, this does not do quantization or rounding to match the input
** type (of cctx->nin).  The reason is that after filtering, it is often
** the case that subtle differences in values emerge, and it may be
** reckless to dump them back into the limited type or value range
** that they started with.  That sort of operation should be under
** explicit user control.
*/
int
coilOutputGet(Nrrd *nout, coilContext *cctx) {
  static const char me[]="coilOutputGet";
  int baseDim;

  if (!(nout && cctx)) {
    biffAddf(COIL, "%s: got NULL pointer", me);
    return 1;
  }
  baseDim = (1 == cctx->kind->valLen ? 0 : 1);
  if (nrrdSlice(nout, cctx->nvol, baseDim, 0)
      || nrrdAxisInfoCopy(nout, cctx->nin, NULL, NRRD_AXIS_INFO_NONE)
      || nrrdBasicInfoCopy(nout, cctx->nin,
                           NRRD_BASIC_INFO_DATA_BIT
                           | NRRD_BASIC_INFO_TYPE_BIT
                           | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                           | NRRD_BASIC_INFO_DIMENSION_BIT
                           | NRRD_BASIC_INFO_CONTENT_BIT
                           | NRRD_BASIC_INFO_COMMENTS_BIT
                           | (nrrdStateKeyValuePairsPropagate
                              ? 0
                              : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
    biffMovef(COIL, NRRD, "%s: trouble getting output", me);
    return 1;
  }
  return 0;
}
Пример #2
0
int
_nrrdCopy(Nrrd *nout, const Nrrd *nin, int bitflag) {
  char me[]="_nrrdCopy", err[BIFF_STRLEN];
  size_t size[NRRD_DIM_MAX];

  if (!(nin && nout)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err); return 1;
  }
  if (nout == nin) {
    /* its not the case that we have nothing to do- the semantics of
       copying cannot be achieved if the input and output nrrd are
       the same; this is an error */
    sprintf(err, "%s: nout==nin disallowed", me);
    biffAdd(NRRD, err); return 1;
  }
  if (!nrrdElementSize(nin)) {
    sprintf(err, "%s: input nrrd reports zero element size!", me);
    biffAdd(NRRD, err); return 1;
  }
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size);
  if (nin->data) {
    if (nrrdMaybeAlloc_nva(nout, nin->type, nin->dim, size)) {
      sprintf(err, "%s: couldn't allocate data", me);
      biffAdd(NRRD, err); return 1;
    }
    memcpy(nout->data, nin->data,
           nrrdElementNumber(nin)*nrrdElementSize(nin));
  } else {
    /* someone is trying to copy structs without data, fine fine fine */
    if (nrrdWrap_nva(nout, NULL, nin->type, nin->dim, size)) {
      sprintf(err, "%s: couldn't allocate data", me);
      biffAdd(NRRD, err); return 1;
    }
  }
  nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_SIZE_BIT);
  /* if nin->data non-NULL (second branch above), this will 
     harmlessly unset and set type and dim */
  nrrdBasicInfoInit(nout, NRRD_BASIC_INFO_DATA_BIT | bitflag);
  if (nrrdBasicInfoCopy(nout, nin, NRRD_BASIC_INFO_DATA_BIT | bitflag)) {
    sprintf(err, "%s: trouble copying basic info", me);
    biffAdd(NRRD, err); return 1;
  }

  return 0;
}
Пример #3
0
/*
******** nrrdSlice()
**
** slices a nrrd along a given axis, at a given position.
**
** This is a newer version of the procedure, which is simpler, faster,
** and requires less memory overhead than the first one.  It is based
** on the observation that any slice is a periodic square-wave pattern
** in the original data (viewed as a one- dimensional array).  The
** characteristics of that periodic pattern are how far from the
** beginning it starts (offset), the length of the "on" part (length),
** the period (period), and the number of periods (numper).
*/
int
nrrdSlice(Nrrd *nout, const Nrrd *cnin, unsigned int saxi, size_t pos) {
  static const char me[]="nrrdSlice", func[]="slice";
  size_t
    I,
    rowLen,                  /* length of segment */
    colStep,                 /* distance between start of each segment */
    colLen,                  /* number of periods */
    szOut[NRRD_DIM_MAX];
  unsigned int ai, outdim;
  int map[NRRD_DIM_MAX];
  const char *src;
  char *dest, stmp[2][AIR_STRLEN_SMALL];
  airArray *mop;
  Nrrd *nin;

  if (!(cnin && nout)) {
    biffAddf(NRRD, "%s: got NULL pointer", me);
    return 1;
  }
  if (nout == cnin) {
    biffAddf(NRRD, "%s: nout==nin disallowed", me);
    return 1;
  }
  if (1 == cnin->dim) {
    if (0 != saxi) {
      biffAddf(NRRD, "%s: slice axis must be 0, not %u, for 1-D array",
               me, saxi);
      return 1;
    }
  } else {
    if (!( saxi < cnin->dim )) {
      biffAddf(NRRD, "%s: slice axis %d out of bounds (0 to %d)",
               me, saxi, cnin->dim-1);
      return 1;
    }
  }
  if (!( pos < cnin->axis[saxi].size )) {
    biffAddf(NRRD, "%s: position %s out of bounds (0 to %s)", me,
             airSprintSize_t(stmp[0], pos),
             airSprintSize_t(stmp[1], cnin->axis[saxi].size-1));
    return 1;
  }
  /* this shouldn't actually be necessary .. */
  if (!nrrdElementSize(cnin)) {
    biffAddf(NRRD, "%s: nrrd reports zero element size!", me);
    return 1;
  }

  /* HEY: copy and paste from measure.c/nrrdProject */
  mop = airMopNew();
  if (1 == cnin->dim) {
    /* There are more efficient ways of dealing with this case; this way is
       easy to implement because it leaves most of the established code below
       only superficially changed; uniformly replacing nin with (nin ? nin :
       cnin), even if pointlessly so; this expression that can't be assigned
       to a new variable because of the difference in const. */
    nin = nrrdNew();
    airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways);
    if (nrrdAxesInsert(nin, cnin, 1)) {
      biffAddf(NRRD, "%s: trouble inserting axis on 1-D array", me);
      airMopError(mop); return 1;
    }
  } else {
    nin = NULL;
  }

  /* set up control variables */
  rowLen = colLen = 1;
  for (ai=0; ai<(nin ? nin : cnin)->dim; ai++) {
    if (ai < saxi) {
      rowLen *= (nin ? nin : cnin)->axis[ai].size;
    } else if (ai > saxi) {
      colLen *= (nin ? nin : cnin)->axis[ai].size;
    }
  }
  rowLen *= nrrdElementSize(nin ? nin : cnin);
  colStep = rowLen*(nin ? nin : cnin)->axis[saxi].size;

  outdim = (nin ? nin : cnin)->dim-1;
  for (ai=0; ai<outdim; ai++) {
    map[ai] = AIR_INT(ai) + (ai >= saxi);
    szOut[ai] = (nin ? nin : cnin)->axis[map[ai]].size;
  }
  nout->blockSize = (nin ? nin : cnin)->blockSize;
  if (nrrdMaybeAlloc_nva(nout, (nin ? nin : cnin)->type, outdim, szOut)) {
    biffAddf(NRRD, "%s: failed to create slice", me);
    airMopError(mop); return 1;
  }

  /* the skinny */
  src = AIR_CAST(const char *, (nin ? nin : cnin)->data);
  dest = AIR_CAST(char *, nout->data);
  src += rowLen*pos;
  for (I=0; I<colLen; I++) {
    /* HEY: replace with AIR_MEMCPY() or similar, when applicable */
    memcpy(dest, src, rowLen);
    src += colStep;
    dest += rowLen;
  }

  /* copy the peripheral information */
  if (nrrdAxisInfoCopy(nout, (nin ? nin : cnin), map, NRRD_AXIS_INFO_NONE)) {
    biffAddf(NRRD, "%s:", me);
    airMopError(mop); return 1;
  }
  if (nrrdContentSet_va(nout, func, cnin /* hide possible axinsert*/,
                        "%d,%d", saxi, pos)) {
    biffAddf(NRRD, "%s:", me);
    airMopError(mop); return 1;
  }
  if (nrrdBasicInfoCopy(nout, (nin ? nin : cnin),
                        NRRD_BASIC_INFO_DATA_BIT
                        | NRRD_BASIC_INFO_TYPE_BIT
                        | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                        | NRRD_BASIC_INFO_DIMENSION_BIT
                        | NRRD_BASIC_INFO_SPACEORIGIN_BIT
                        | NRRD_BASIC_INFO_CONTENT_BIT
                        | NRRD_BASIC_INFO_COMMENTS_BIT
                        | (nrrdStateKeyValuePairsPropagate
                           ? 0
                           : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
    biffAddf(NRRD, "%s:", me);
    airMopError(mop); return 1;
  }
  /* translate origin if this was a spatial axis, otherwise copy */
  /* note that if there is no spatial info at all, this is all harmless */
  if (AIR_EXISTS((nin ? nin : cnin)->axis[saxi].spaceDirection[0])) {
    nrrdSpaceVecScaleAdd2(nout->spaceOrigin,
                          1.0, (nin ? nin : cnin)->spaceOrigin,
                          AIR_CAST(double, pos),
                          (nin ? nin : cnin)->axis[saxi].spaceDirection);
  } else {
Пример #4
0
/*
******** tenBVecNonLinearFit
**
** Assuming that axis 0 represents a sequence of DWI measurements at a 
** range of b values (as described by bb[i]), do non-linear least-squares
** fitting of those measurements, governed by weights ww[i] (with at
** most iterMax interations, or terminated when L2 norm change < eps).
**
** Based on model fit amp*exp(-b*dec), output nrrd's axis 0 has three values:
** 0: amp
** 1: dec
** 2: error of fit
** and all other axes are unchanged from input.  Output type is always double.
*/
int
tenBVecNonLinearFit(Nrrd *nout, const Nrrd *nin, 
                    double *bb, double *ww, int iterMax, double eps) {
  char me[]="tenBVecNonLinearFit", err[BIFF_STRLEN];
  int map[NRRD_DIM_MAX], vecSize, iter;
  size_t ii, size[NRRD_DIM_MAX], vecI, vecNum;
  char *vec;
  double *out, ss[AIR_STRLEN_SMALL], amp, dec, d_amp, d_dec, error, diff,
    (*vecLup)(const void *v, size_t I);

  if (!( nout && nin && bb && ww )) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(TEN, err); return 1;
  }
  
  if (!( nin->dim >= 2 )) {
    sprintf(err, "%s: nin->dim (%d) not >= 2", me, nin->dim);
    biffAdd(TEN, err); return 1;
  }
  if (!( nin->axis[0].size < AIR_STRLEN_SMALL )) {
    sprintf(err, "%s: sorry need nin->axis[0].size (" 
            _AIR_SIZE_T_CNV ") < %d", 
            me, nin->axis[0].size, AIR_STRLEN_SMALL);
    biffAdd(TEN, err); return 1;
  }

  /* allocate/set-up output */
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size);
  size[0] = 3;
  if (nrrdMaybeAlloc_nva(nout, nrrdTypeDouble, nin->dim, size)) {
    sprintf(err, "%s: couldn't allocate output", me);
    biffMove(TEN, err, NRRD); return 1;
  }
  for (ii=1; ii<nin->dim; ii++) {
    map[ii] = ii;
  }
  map[0] = -1;
  if (nrrdAxisInfoCopy(nout, nin, map, NRRD_AXIS_INFO_NONE)) {
    sprintf(err, "%s: couldn't copy axis info", me);
    biffMove(TEN, err, NRRD); return 1;
  }

  /* process all b vectors */
  vecSize = nin->axis[0].size*nrrdTypeSize[nin->type];
  vecNum = nrrdElementNumber(nin)/nin->axis[0].size;
  vecLup = nrrdDLookup[nin->type];
  vec = (char*)nin->data;
  out = (double*)nout->data;
  for (vecI=0; vecI<vecNum; vecI++) {
    /* copy DWI signal values */
    for (ii=0; ii<nin->axis[0].size; ii++) {
      ss[ii] = vecLup(vec, ii);
    }
    /* start with linear fit */
    tenBVecNonLinearFit_linear(&amp, &dec, bb, ss, ww, nin->axis[0].size);
    error = tenBVecNonLinearFit_error(bb, ss, ww, nin->axis[0].size, amp, dec);
    /* possibly refine with gauss-newton */
    if (iterMax > 0) {
      iter = 0;
      do {
        iter++;
        tenBVecNonLinearFit_GNstep(&d_amp, &d_dec,
                                   bb, ss, ww, nin->axis[0].size, amp, dec);
        amp += 0.3*d_amp;
        dec += 0.3*d_dec;
        diff = d_amp*d_amp + d_dec*d_dec;
      } while (iter < iterMax && diff > eps);
    }
    error = tenBVecNonLinearFit_error(bb, ss, ww, nin->axis[0].size, amp, dec);
    out[0] = amp;
    out[1] = dec;
    out[2] = error;
    vec += vecSize;
    out += 3;
  }
  
  return 0;
}
Пример #5
0
/*
** _nrrdApply1DSetUp()
**
** some error checking and initializing needed for 1D LUTS, regular,
** and irregular maps.  The intent is that if this succeeds, then
** there is no need for any further error checking.
**
** The only thing this function DOES is allocate the output nrrd, and
** set meta information.  The rest is just error checking.
**
** The given NrrdRange has to be fleshed out by the caller: it can't
** be NULL, and both range->min and range->max must exist.
*/
int
_nrrdApply1DSetUp(Nrrd *nout, const Nrrd *nin, const NrrdRange *range, 
                  const Nrrd *nmap, int kind, int typeOut,
                  int rescale, int multi) {
  char me[]="_nrrdApply1DSetUp", err[BIFF_STRLEN], *mapcnt;
  char nounStr[][AIR_STRLEN_SMALL]={"lut",
                                    "regular map",
                                    "irregular map"};
  char mnounStr[][AIR_STRLEN_SMALL]={"multi lut",
                                     "multi regular map",
                                     "multi irregular map"}; 
                                      /* wishful thinking */
  char verbStr[][AIR_STRLEN_SMALL]={"lut",
                                    "rmap",
                                    "imap"};
  char mverbStr[][AIR_STRLEN_SMALL]={"mlut",
                                     "mrmap",
                                     "mimap"}; /* wishful thinking */
  int mapAxis, copyMapAxis0=AIR_FALSE, axisMap[NRRD_DIM_MAX];
  unsigned int ax, dim, entLen;
  size_t size[NRRD_DIM_MAX];
  double domMin, domMax;

  if (nout == nin) {
    sprintf(err, "%s: due to laziness, nout==nin always disallowed", me);
    biffAdd(NRRD, err); return 1;
  }
  if (airEnumValCheck(nrrdType, typeOut)) {
    sprintf(err, "%s: invalid requested output type %d", me, typeOut);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdTypeBlock == nin->type || nrrdTypeBlock == typeOut) {
    sprintf(err, "%s: input or requested output type is %s, need scalar",
            me, airEnumStr(nrrdType, nrrdTypeBlock));
    biffAdd(NRRD, err); return 1;
  }
  if (rescale && !(range
                   && AIR_EXISTS(range->min) 
                   && AIR_EXISTS(range->max))) {
    sprintf(err, "%s: want rescaling but didn't get a range, or "
            "not both range->{min,max} exist", me);
    biffAdd(NRRD, err); return 1;
  }
  if (kindLut == kind || kindRmap == kind) {
    if (!multi) {
      mapAxis = nmap->dim - 1;
      if (!(0 == mapAxis || 1 == mapAxis)) {
        sprintf(err, "%s: dimension of %s should be 1 or 2, not %d", 
                me, nounStr[kind], nmap->dim);
        biffAdd(NRRD, err); return 1;
      }
      copyMapAxis0 = (1 == mapAxis);
    } else {
      mapAxis = nmap->dim - nin->dim - 1;
      if (!(0 == mapAxis || 1 == mapAxis)) {
        sprintf(err, "%s: dimension of %s should be %d or %d, not %d", 
                me, mnounStr[kind],
                nin->dim + 1, nin->dim + 2, nmap->dim);
        biffAdd(NRRD, err); return 1;
      }
      copyMapAxis0 = (1 == mapAxis);
      /* need to make sure the relevant sizes match */
      for (ax=0; ax<nin->dim; ax++) {
        if (nin->axis[ax].size != nmap->axis[mapAxis + 1 + ax].size) {
          sprintf(err, "%s: input and mmap don't have compatible sizes: "
                  "nin->axis[%d].size (" _AIR_SIZE_T_CNV ") "
                  "!= nmap->axis[%d].size (" _AIR_SIZE_T_CNV "): ",
                  me, ax, nin->axis[ax].size, 
                  mapAxis + 1 + ax, nmap->axis[mapAxis + 1 + ax].size);
          biffAdd(NRRD, err); return 1;
        }
      }
    }
    domMin = _nrrdApplyDomainMin(nmap, AIR_FALSE, mapAxis);
    domMax = _nrrdApplyDomainMax(nmap, AIR_FALSE, mapAxis);
    if (!( domMin < domMax )) {
      sprintf(err, "%s: (axis %d) domain min (%g) not less than max (%g)", me,
              mapAxis, domMin, domMax);
      biffAdd(NRRD, err); return 1;
    }
    if (nrrdHasNonExist(nmap)) {
      sprintf(err, "%s: %s nrrd has non-existent values",
              me, multi ? mnounStr[kind] : nounStr[kind]);
      biffAdd(NRRD, err); return 1;
    }
    entLen = mapAxis ? nmap->axis[0].size : 1;
  } else {
    if (multi) {
      sprintf(err, "%s: sorry, multi irregular maps not implemented", me);
      biffAdd(NRRD, err); return 1;
    }
    /* its an irregular map */
    if (nrrd1DIrregMapCheck(nmap)) {
      sprintf(err, "%s: problem with irregular map", me);
      biffAdd(NRRD, err); return 1;
    }
    /* mapAxis has no meaning for irregular maps, but we'll pretend ... */
    mapAxis = nmap->axis[0].size == 2 ? 0 : 1;
    copyMapAxis0 = AIR_TRUE;
    entLen = nmap->axis[0].size-1;
  }
  if (mapAxis + nin->dim > NRRD_DIM_MAX) {
    sprintf(err, "%s: input nrrd dim %d through non-scalar %s exceeds "
            "NRRD_DIM_MAX %d",
            me, nin->dim,
            multi ? mnounStr[kind] : nounStr[kind], NRRD_DIM_MAX);
    biffAdd(NRRD, err); return 1;
  }
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size+mapAxis);
  if (mapAxis) {
    size[0] = entLen;
    axisMap[0] = -1;
  }
  for (dim=0; dim<nin->dim; dim++) {
    axisMap[dim+mapAxis] = dim;
  }
  /*
  fprintf(stderr, "##%s: pre maybe alloc: nout->data = %p\n", me, nout->data);
  for (dim=0; dim<mapAxis + nin->dim; dim++) {
    fprintf(stderr, "    size[%d] = %d\n", d, (int)size[d]);
  }
  fprintf(stderr, "   nout->dim = %d; nout->type = %d = %s; sizes = %d,%d\n", 
          nout->dim, nout->type,
          airEnumStr(nrrdType, nout->type));
  fprintf(stderr, "   typeOut = %d = %s\n", typeOut,
          airEnumStr(nrrdType, typeOut));
  */
  if (nrrdMaybeAlloc_nva(nout, typeOut, mapAxis + nin->dim, size)) {
    sprintf(err, "%s: couldn't allocate output nrrd", me);
    biffAdd(NRRD, err); return 1;
  }
  /*
  fprintf(stderr, "   nout->dim = %d; nout->type = %d = %s\n",
          nout->dim, nout->type,
          airEnumStr(nrrdType, nout->type),
          nout->axis[0].size, nout->axis[1].size);
  for (d=0; d<nout->dim; d++) {
    fprintf(stderr, "    size[%d] = %d\n", d, (int)nout->axis[d].size);
  }
  fprintf(stderr, "##%s: post maybe alloc: nout->data = %p\n", me, nout->data);
  */
  if (nrrdAxisInfoCopy(nout, nin, axisMap, NRRD_AXIS_INFO_NONE)) {
    sprintf(err, "%s: trouble copying axis info", me);
    biffAdd(NRRD, err); return 1;
  }
  if (copyMapAxis0) {
    _nrrdAxisInfoCopy(nout->axis + 0, nmap->axis + 0,
                      NRRD_AXIS_INFO_SIZE_BIT);
  }

  mapcnt = _nrrdContentGet(nmap);
  if (nrrdContentSet_va(nout, multi ? mverbStr[kind] : verbStr[kind],
                        nin, "%s", mapcnt)) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); free(mapcnt); return 1;
  }
  free(mapcnt); 
  if (nrrdBasicInfoCopy(nout, nin,
                        NRRD_BASIC_INFO_DATA_BIT
                        | NRRD_BASIC_INFO_TYPE_BIT
                        | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                        | NRRD_BASIC_INFO_DIMENSION_BIT
                        | NRRD_BASIC_INFO_CONTENT_BIT
                        | (nrrdStateKeyValuePairsPropagate
                           ? 0
                           : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); return 1;
  }
  return 0;
}
Пример #6
0
int
main(int argc, char *argv[]) {
  char *me, *err;
  hestOpt *hopt=NULL;
  airArray *mop;

  char *outS;
  double _tA[6], tA[7], _tB[6], tB[7], time0, time1, conv, confThresh,
    pA[3], pB[3], qA[4], qB[4], rA[9], rB[9], mat1[9], mat2[9], tmp,
    stepSize, minNorm, sclA, sclB;
  unsigned int NN, maxiter, refIdx[3];
  int recurse, ptype, verb;
  Nrrd *_nin, *nin, *nout;
  tenInterpParm *tip;

  mop = airMopNew();
  me = argv[0];
  hestOptAdd(&hopt, "a", "tensor", airTypeDouble, 6, 6, _tA, "1 0 0 1 0 1",
             "first tensor");
  hestOptAdd(&hopt, "pa", "qq", airTypeDouble, 3, 3, pA, "0 0 0",
             "rotation of first tensor");
  hestOptAdd(&hopt, "sa", "scl", airTypeDouble, 1, 1, &sclA, "1.0",
             "scaling of first tensor");
  hestOptAdd(&hopt, "b", "tensor", airTypeDouble, 6, 6, _tB, "1 0 0 1 0 1",
             "second tensor");
  hestOptAdd(&hopt, "pb", "qq", airTypeDouble, 3, 3, pB, "0 0 0",
             "rotation of second tensor");
  hestOptAdd(&hopt, "sb", "scl", airTypeDouble, 1, 1, &sclB, "1.0",
             "scaling of second tensor");
  hestOptAdd(&hopt, "i", "nten", airTypeOther, 1, 1, &_nin, "",
             "input tensor volume (makes previous options moot)",
             NULL, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "ri", "x y z", airTypeUInt, 3, 3, refIdx, "0 0 0",
             "index of reference tensor in input tensor volume");
  hestOptAdd(&hopt, "th", "thresh", airTypeDouble, 1, 1, &confThresh, "0.5",
             "conf mask threshold on \"-i\"");
  hestOptAdd(&hopt, "n", "# steps", airTypeUInt, 1, 1, &NN, "100",
             "number of steps in between two tensors");
  hestOptAdd(&hopt, "s", "stepsize", airTypeDouble, 1, 1, &stepSize, "1",
             "step size in update");
  hestOptAdd(&hopt, "mn", "minnorm", airTypeDouble, 1, 1, &minNorm, "0.000001",
             "minnorm of something");
  hestOptAdd(&hopt, "c", "conv", airTypeDouble, 1, 1, &conv, "0.0001",
             "convergence threshold of length fraction");
  hestOptAdd(&hopt, "mi", "maxiter", airTypeUInt, 1, 1, &maxiter, "0",
             "if non-zero, max # iterations for computation");
  hestOptAdd(&hopt, "r", "recurse", airTypeInt, 0, 0, &recurse, NULL,
             "enable recursive solution, when useful");
  hestOptAdd(&hopt, "t", "path type", airTypeEnum, 1, 1, &ptype, "lerp",
             "what type of path to compute", NULL, tenInterpType);
  hestOptAdd(&hopt, "o", "filename", airTypeString, 1, 1, &outS, "-",
             "file to write output nrrd to");
  hestOptAdd(&hopt, "v", "verbosity", airTypeInt, 1, 1, &verb, "0",
             "verbosity");
  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);

  tip = tenInterpParmNew();
  airMopAdd(mop, tip, (airMopper)tenInterpParmNix, airMopAlways);
  nout = nrrdNew();
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);

  tip->verbose = verb;
  tip->convStep = stepSize;
  tip->enableRecurse = recurse;
  tip->minNorm = minNorm;
  tip->maxIter = maxiter;
  tip->convEps = conv;
  if (_nin) {
    double refTen[7], inTen[7], *in, *out;
    unsigned int xi, yi, zi, sx, sy, sz, dimOut;
    int axmap[NRRD_DIM_MAX], numerical;
    size_t size[NRRD_DIM_MAX];

    if (tenTensorCheck(_nin, nrrdTypeDefault, AIR_TRUE, AIR_TRUE)) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: input volume not valid:\n%s\n",
              me, err);
      airMopError(mop); 
      return 1;
    }
    sx = AIR_CAST(unsigned int, _nin->axis[1].size);
    sy = AIR_CAST(unsigned int, _nin->axis[2].size);
    sz = AIR_CAST(unsigned int, _nin->axis[3].size);
    if (!( refIdx[0] < sx 
           && refIdx[1] < sy
           && refIdx[2] < sz )) {
      fprintf(stderr, "%s: index (%u,%u,%u) out of bounds (%u,%u,%u)\n", me,
              refIdx[0], refIdx[1], refIdx[2], sx, sy, sz);
      airMopError(mop);
      return 1;
    }
    nin = nrrdNew();
    airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways);
    numerical = (ptype == tenInterpTypeGeoLoxK
                 || ptype == tenInterpTypeGeoLoxR
                 || ptype == tenInterpTypeLoxK
                 || ptype == tenInterpTypeLoxR
                 || ptype == tenInterpTypeQuatGeoLoxK
                 || ptype == tenInterpTypeQuatGeoLoxR);
    if (numerical) {
      tip->lengthFancy = AIR_TRUE;
      dimOut = 4;
      size[0] = 3;
      size[1] = _nin->axis[1].size;
      size[2] = _nin->axis[2].size;
      size[3] = _nin->axis[3].size;
      axmap[0] = -1;
      axmap[1] = 1;
      axmap[2] = 2;
      axmap[3] = 3;
    } else {
      dimOut = 3;
      size[0] = _nin->axis[1].size;
      size[1] = _nin->axis[2].size;
      size[2] = _nin->axis[3].size;
      axmap[0] = 1;
      axmap[1] = 2;
      axmap[2] = 3;
    }      
    if (nrrdConvert(nin, _nin, nrrdTypeDouble)
        || nrrdMaybeAlloc_nva(nout, nrrdTypeDouble, dimOut, size)
        || nrrdAxisInfoCopy(nout, nin, axmap, 
                            NRRD_AXIS_INFO_SIZE_BIT)
        || nrrdBasicInfoCopy(nout, nin, 
                             (NRRD_BASIC_INFO_DATA_BIT
                              | NRRD_BASIC_INFO_TYPE_BIT
                              | NRRD_BASIC_INFO_DIMENSION_BIT
                              | NRRD_BASIC_INFO_CONTENT_BIT
                              | NRRD_BASIC_INFO_SAMPLEUNITS_BIT))) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: trouble:\n%s\n", me, err);
      airMopError(mop); 
      return 1;
    }
    in = AIR_CAST(double *, nin->data);
    out = AIR_CAST(double *, nout->data);
    TEN_T_COPY(refTen, in + 7*(refIdx[0] + sx*(refIdx[1] + sy*refIdx[2])));
    fprintf(stderr, "!%s: reference tensor = (%g) %g %g %g   %g %g    %g\n",
            me, refTen[0], refTen[1], refTen[2], refTen[3],
            refTen[4], refTen[5], refTen[6]);
    for (zi=0; zi<sz; zi++) {
      for (yi=0; yi<sy; yi++) {
        for (xi=0; xi<sx; xi++) {
          TEN_T_COPY(inTen, in + 7*(xi + sx*(yi + sy*zi)));
          if (numerical) {
            fprintf(stderr, "!%s: %u %u %u \n", me, xi, yi, zi);
            if (inTen[0] < confThresh) {
              out[0] = AIR_NAN;
              out[1] = AIR_NAN;
              out[2] = AIR_NAN;
            } else {
              tip->verbose = 10*(xi == refIdx[0]
                                 && yi == refIdx[1]
                                 && zi == refIdx[2]);
              out[0] =  tenInterpDistanceTwo_d(inTen, refTen, ptype, tip);
              out[1] =  tip->lengthShape;
              out[2] =  tip->lengthOrient;
            }
            out += 3;
          } else {
            if (inTen[0] < confThresh) {
              *out = AIR_NAN;
            } else {
              *out =  tenInterpDistanceTwo_d(inTen, refTen, ptype, tip);
            }
            out += 1;
          }
        }
        if (numerical) {
          if (nrrdSave(outS, nout, NULL)) {
            airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
            fprintf(stderr, "%s: trouble saving output:\n%s\n", me, err);
            airMopError(mop); 
            return 1;
          }
        }
      }
    }
  } else {
Пример #7
0
int
nrrdProject(Nrrd *nout, const Nrrd *nin, unsigned int axis,
            int measr, int type) {
  char me[]="nrrdProject", func[]="project", err[BIFF_STRLEN];
  int iType, oType, axmap[NRRD_DIM_MAX];
  unsigned int ai, ei;
  size_t iElSz, oElSz, iSize[NRRD_DIM_MAX], oSize[NRRD_DIM_MAX], linLen,
    rowIdx, rowNum, colIdx, colNum, colStep;
  const char *ptr, *iData;
  char *oData, *line;
  double axmin, axmax;
  airArray *mop;
  
  if (!(nin && nout)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err); return 1;
  }
  if (nout == nin) {
    sprintf(err, "%s: nout==nin disallowed", me);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdTypeBlock == nin->type) {
    sprintf(err, "%s: can't project nrrd type %s", me,
            airEnumStr(nrrdType, nrrdTypeBlock));
    biffAdd(NRRD, err); return 1;
  }
  if (!AIR_IN_OP(nrrdMeasureUnknown, measr, nrrdMeasureLast)) {
    sprintf(err, "%s: measure %d not recognized", me, measr);
    biffAdd(NRRD, err); return 1;
  }
  /* without this check, the loops below cause segfaults, because
     nin->dim is now unsigned */
  if (!( 2 <= nin->dim )) {
    sprintf(err, "%s: sorry, currently need at least 2-D array to project", me);
    biffAdd(NRRD, err); return 1;
  }
  /* HEY: at some point, as a convenience, it would be nice to handle
     projecting a single 1-D scanline down into a 1-D single-sample,
     even though this would clearly be a special case */
  if (!( axis <= nin->dim-1 )) {
    sprintf(err, "%s: axis %d not in range [0,%d]", me, axis, nin->dim-1);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdTypeDefault != type) {
    if (!( AIR_IN_OP(nrrdTypeUnknown, type, nrrdTypeLast) )) {
      sprintf(err, "%s: got invalid target type %d", me, type);
      biffAdd(NRRD, err); return 1;
    }
  }
  
  mop = airMopNew();
  iType = nin->type;
  oType = (nrrdTypeDefault != type 
           ? type 
           : _nrrdMeasureType(nin, measr));
  iElSz = nrrdTypeSize[iType];
  oElSz = nrrdTypeSize[oType];
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, iSize);
  colNum = rowNum = 1;
  for (ai=0; ai<nin->dim; ai++) {
    if (ai < axis) {
      colNum *= iSize[ai];
    } else if (ai > axis) {
      rowNum *= iSize[ai];
    }
  }
  linLen = iSize[axis];
  colStep = linLen*colNum;
  for (ai=0; ai<=nin->dim-2; ai++) {
    axmap[ai] = ai + (ai >= axis);
  }
  for (ai=0; ai<=nin->dim-2; ai++) {
    oSize[ai] = iSize[axmap[ai]];
  }
  if (nrrdMaybeAlloc_nva(nout, oType, nin->dim-1, oSize)) {
    sprintf(err, "%s: failed to create output", me);
    biffAdd(NRRD, err); airMopError(mop); return 1;
  }

  /* allocate a scanline buffer */
  if (!(line = (char*)calloc(linLen, iElSz))) {
    sprintf(err, "%s: couldn't calloc(" _AIR_SIZE_T_CNV "," 
            _AIR_SIZE_T_CNV ") scanline buffer",
            me, linLen, iElSz);
    biffAdd(NRRD, err); airMopError(mop); return 1;
  }
  airMopAdd(mop, line, airFree, airMopAlways);

  /* the skinny */
  axmin = nin->axis[axis].min;
  axmax = nin->axis[axis].max;
  iData = (char *)nin->data;
  oData = (char *)nout->data;
  for (rowIdx=0; rowIdx<rowNum; rowIdx++) {
    for (colIdx=0; colIdx<colNum; colIdx++) {
      ptr = iData + iElSz*(colIdx + rowIdx*colStep);
      for (ei=0; ei<linLen; ei++) {
        memcpy(line + ei*iElSz, ptr + ei*iElSz*colNum, iElSz);
      }
      nrrdMeasureLine[measr](oData, oType, line, iType, linLen,
                             axmin, axmax);
      oData += oElSz;
    }
  }
  
  /* copy the peripheral information */
  if (nrrdAxisInfoCopy(nout, nin, axmap, NRRD_AXIS_INFO_NONE)) {
    sprintf(err, "%s:", me); 
    biffAdd(NRRD, err); airMopError(mop); return 1;
  }
  if (nrrdContentSet_va(nout, func, nin,
                        "%d,%s", axis, airEnumStr(nrrdMeasure, measr))) {
    sprintf(err, "%s:", me); 
    biffAdd(NRRD, err); airMopError(mop); return 1;
  }
  /* this will copy the space origin over directly, which is reasonable */
  if (nrrdBasicInfoCopy(nout, nin,
                        NRRD_BASIC_INFO_DATA_BIT
                        | NRRD_BASIC_INFO_TYPE_BIT
                        | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                        | NRRD_BASIC_INFO_DIMENSION_BIT
                        | NRRD_BASIC_INFO_CONTENT_BIT
                        | NRRD_BASIC_INFO_COMMENTS_BIT
                        | (nrrdStateKeyValuePairsPropagate
                           ? 0
                           : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); airMopError(mop); return 1;
  }

  airMopOkay(mop);
  return 0;
}
Пример #8
0
/*
******** nrrdSlice()
**
** slices a nrrd along a given axis, at a given position.
**
** This is a newer version of the procedure, which is simpler, faster,
** and requires less memory overhead than the first one.  It is based
** on the observation that any slice is a periodic square-wave pattern
** in the original data (viewed as a one- dimensional array).  The
** characteristics of that periodic pattern are how far from the
** beginning it starts (offset), the length of the "on" part (length),
** the period (period), and the number of periods (numper).
*/
int
nrrdSlice(Nrrd *nout, const Nrrd *nin, unsigned int saxi, size_t pos)
{
  char me[]="nrrdSlice", func[]="slice", err[BIFF_STRLEN];
  size_t
  I,
  rowLen,                  /* length of segment */
  colStep,                 /* distance between start of each segment */
  colLen,                  /* number of periods */
  szOut[NRRD_DIM_MAX];
  unsigned int ai, outdim;
  int map[NRRD_DIM_MAX];
  char *src, *dest;

  if (!(nin && nout))
  {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err);
    return 1;
  }
  if (nout == nin)
  {
    sprintf(err, "%s: nout==nin disallowed", me);
    biffAdd(NRRD, err);
    return 1;
  }
  if (1 == nin->dim)
  {
    sprintf(err, "%s: can't slice a 1-D nrrd; use nrrd{I,F,D}Lookup[]", me);
    biffAdd(NRRD, err);
    return 1;
  }
  if (!( saxi < nin->dim ))
  {
    sprintf(err, "%s: slice axis %d out of bounds (0 to %d)",
            me, saxi, nin->dim-1);
    biffAdd(NRRD, err);
    return 1;
  }
  if (!( pos < nin->axis[saxi].size ))
  {
    sprintf(err, "%s: position " _AIR_SIZE_T_CNV
            " out of bounds (0 to " _AIR_SIZE_T_CNV  ")",
            me, pos, nin->axis[saxi].size-1);
    biffAdd(NRRD, err);
    return 1;
  }
  /* this shouldn't actually be necessary .. */
  if (!nrrdElementSize(nin))
  {
    sprintf(err, "%s: nrrd reports zero element size!", me);
    biffAdd(NRRD, err);
    return 1;
  }

  /* set up control variables */
  rowLen = colLen = 1;
  for (ai=0; ai<nin->dim; ai++)
  {
    if (ai < saxi)
    {
      rowLen *= nin->axis[ai].size;
    }
    else if (ai > saxi)
    {
      colLen *= nin->axis[ai].size;
    }
  }
  rowLen *= nrrdElementSize(nin);
  colStep = rowLen*nin->axis[saxi].size;

  outdim = nin->dim-1;
  for (ai=0; ai<outdim; ai++)
  {
    map[ai] = ai + (ai >= saxi);
    szOut[ai] = nin->axis[map[ai]].size;
  }
  nout->blockSize = nin->blockSize;
  if (nrrdMaybeAlloc_nva(nout, nin->type, outdim, szOut))
  {
    sprintf(err, "%s: failed to create slice", me);
    biffAdd(NRRD, err);
    return 1;
  }

  /* the skinny */
  src = (char *)nin->data;
  dest = (char *)nout->data;
  src += rowLen*pos;
  for (I=0; I<colLen; I++)
  {
    /* HEY: replace with AIR_MEMMOVE() or similar, when applicable */
    memmove(dest, src, rowLen);
    src += colStep;
    dest += rowLen;
  }

  /* copy the peripheral information */
  if (nrrdAxisInfoCopy(nout, nin, map, NRRD_AXIS_INFO_NONE))
  {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err);
    return 1;
  }
  if (nrrdContentSet_va(nout, func, nin, "%d,%d", saxi, pos))
  {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err);
    return 1;
  }
  if (nrrdBasicInfoCopy(nout, nin,
                        NRRD_BASIC_INFO_DATA_BIT
                        | NRRD_BASIC_INFO_TYPE_BIT
                        | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                        | NRRD_BASIC_INFO_DIMENSION_BIT
                        | NRRD_BASIC_INFO_SPACEORIGIN_BIT
                        | NRRD_BASIC_INFO_CONTENT_BIT
                        | NRRD_BASIC_INFO_COMMENTS_BIT
                        | (nrrdStateKeyValuePairsPropagate
                           ? 0
                           : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT)))
  {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err);
    return 1;
  }
  /* translate origin if this was a spatial axis, otherwise copy */
  /* note that if there is no spatial info at all, this is all harmless */
  if (AIR_EXISTS(nin->axis[saxi].spaceDirection[0]))
  {
    _nrrdSpaceVecScaleAdd2(nout->spaceOrigin,
                           1.0, nin->spaceOrigin,
                           pos, nin->axis[saxi].spaceDirection);
  }
  else
  {
    _nrrdSpaceVecCopy(nout->spaceOrigin, nin->spaceOrigin);
  }
  return 0;
}
Пример #9
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);
  }
Пример #10
0
/*
******** nrrdShuffle
**
** rearranges hyperslices of a nrrd along a given axis according to
** given permutation.  This could be used to on a 4D array,
** representing a 3D volume of vectors, to re-order the vector
** components.
**
** the given permutation array must allocated for at least as long as
** the input nrrd along the chosen axis.  perm[j] = i means that the
** value at position j in the _new_ array should come from position i
** in the _old_array.  The standpoint is from the new, looking at
** where to find the values amid the old array (perm answers "what do
** I put here", not "where do I put this").  This allows multiple
** positions in the new array to copy from the same old position, and
** insures that there is an source for all positions along the new
** array.
*/
int
nrrdShuffle(Nrrd *nout, const Nrrd *nin, unsigned int axis,
            const size_t *perm) {
  static const char me[]="nrrdShuffle", func[]="shuffle";
  char buff2[AIR_STRLEN_SMALL];
  /* Sun Feb 8 13:13:58 CST 2009: There was a memory bug here caused
     by using the same buff1[NRRD_DIM_MAX*30] declaration that had
     worked fine for nrrdAxesPermute and nrrdReshape, but does NOT
     work here because now samples along an axes are re-ordered, not
     axes, so its often not allocated for long enough to hold the
     string that's printed to it. Ideally there'd be another argument
     that says whether to document the shuffle in the content string,
     which would mean an API change.  Or, we can use a secret
     heuristic (or maybe later a nrrdState variable) for determining
     when an axis is short enough to make documenting the shuffle
     interesting.  This is useful since functions like nrrdFlip()
     probably do *not* need the shuffle (the sample reversal) to be
     documented for long axes */
#define LONGEST_INTERESTING_AXIS 42
  char buff1[LONGEST_INTERESTING_AXIS*30];
  unsigned int ai, ldim, len;
  size_t idxInB=0, idxOut, lineSize, numLines, size[NRRD_DIM_MAX], *lsize,
    cIn[NRRD_DIM_MAX+1], cOut[NRRD_DIM_MAX+1];
  char *dataIn, *dataOut;

  if (!(nin && nout && perm)) {
    biffAddf(NRRD, "%s: got NULL pointer", me);
    return 1;
  }
  if (nout == nin) {
    biffAddf(NRRD, "%s: nout==nin disallowed", me);
    return 1;
  }
  if (!( axis < nin->dim )) {
    biffAddf(NRRD, "%s: axis %d outside valid range [0,%d]",
             me, axis, nin->dim-1);
    return 1;
  }
  len = AIR_CAST(unsigned int, nin->axis[axis].size);
  for (ai=0; ai<len; ai++) {
    if (!( perm[ai] < len )) {
      char stmp[AIR_STRLEN_SMALL];
      biffAddf(NRRD, "%s: perm[%d] (%s) outside valid range [0,%d]", me, ai,
               airSprintSize_t(stmp, perm[ai]), len-1);
      return 1;
    }
  }
  /* this shouldn't actually be necessary .. */
  if (!nrrdElementSize(nin)) {
    biffAddf(NRRD, "%s: nrrd reports zero element size!", me);
    return 1;
  }
  /* set information in new volume */
  nout->blockSize = nin->blockSize;
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size);
  if (nrrdMaybeAlloc_nva(nout, nin->type, nin->dim, size)) {
    biffAddf(NRRD, "%s: failed to allocate output", me);
    return 1;
  }
  if (nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_NONE)) {
    biffAddf(NRRD, "%s:", me);
    return 1;
  }
  /* the min and max along the shuffled axis are now meaningless */
  nout->axis[axis].min = nout->axis[axis].max = AIR_NAN;
  /* do the safe thing first */
  nout->axis[axis].kind = _nrrdKindAltered(nin->axis[axis].kind, AIR_FALSE);
  /* try cleverness */
  if (!nrrdStateKindNoop) {
    if (0 == nrrdKindSize(nin->axis[axis].kind)
        || nrrdKindStub == nin->axis[axis].kind
        || nrrdKindScalar == nin->axis[axis].kind
        || nrrdKind2Vector == nin->axis[axis].kind
        || nrrdKind3Color == nin->axis[axis].kind
        || nrrdKind4Color == nin->axis[axis].kind
        || nrrdKind3Vector == nin->axis[axis].kind
        || nrrdKind3Gradient == nin->axis[axis].kind
        || nrrdKind3Normal == nin->axis[axis].kind
        || nrrdKind4Vector == nin->axis[axis].kind) {
      /* these kinds have no intrinsic ordering */
      nout->axis[axis].kind = nin->axis[axis].kind;
    }
  }
  /* the skinny */
  lineSize = 1;
  for (ai=0; ai<axis; ai++) {
    lineSize *= nin->axis[ai].size;
  }
  numLines = nrrdElementNumber(nin)/lineSize;
  lineSize *= nrrdElementSize(nin);
  lsize = size + axis;
  ldim = nin->dim - axis;
  dataIn = AIR_CAST(char *, nin->data);
  dataOut = AIR_CAST(char *, nout->data);
  memset(cIn, 0, sizeof(cIn));
  memset(cOut, 0, sizeof(cOut));
  for (idxOut=0; idxOut<numLines; idxOut++) {
    memcpy(cIn, cOut, sizeof(cIn));
    cIn[0] = perm[cOut[0]];
    NRRD_INDEX_GEN(idxInB, cIn, lsize, ldim);
    NRRD_INDEX_GEN(idxOut, cOut, lsize, ldim);
    memcpy(dataOut + idxOut*lineSize, dataIn + idxInB*lineSize, lineSize);
    NRRD_COORD_INCR(cOut, lsize, ldim, 0);
  }
  /* Set content. The LONGEST_INTERESTING_AXIS hack avoids the
     previous array out-of-bounds bug */
  if (len <= LONGEST_INTERESTING_AXIS) {
    strcpy(buff1, "");
    for (ai=0; ai<len; ai++) {
      char stmp[AIR_STRLEN_SMALL];
      sprintf(buff2, "%s%s", (ai ? "," : ""), airSprintSize_t(stmp, perm[ai]));
      strcat(buff1, buff2);
    }
    if (nrrdContentSet_va(nout, func, nin, "%s", buff1)) {
      biffAddf(NRRD, "%s:", me);
      return 1;
    }
  } else {
    if (nrrdContentSet_va(nout, func, nin, "")) {
      biffAddf(NRRD, "%s:", me);
      return 1;
    }
  }
  if (nrrdBasicInfoCopy(nout, nin,
                        NRRD_BASIC_INFO_DATA_BIT
                        | NRRD_BASIC_INFO_TYPE_BIT
                        | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                        | NRRD_BASIC_INFO_DIMENSION_BIT
                        | NRRD_BASIC_INFO_CONTENT_BIT
                        | NRRD_BASIC_INFO_COMMENTS_BIT
                        | (nrrdStateKeyValuePairsPropagate
                           ? 0
                           : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
    biffAddf(NRRD, "%s:", me);
    return 1;
  }

  return 0;
#undef LONGEST_INTERESTING_AXIS
}
Пример #11
0
/*
******** nrrdAxesPermute
**
** changes the scanline ordering of the data in a nrrd
**
** The basic means by which data is moved around is with memcpy().
** The goal is to call memcpy() as few times as possible, on memory
** segments as large as possible.  Currently, this is done by
** detecting how many of the low-index axes are left untouched by
** the permutation- this constitutes a "scanline" which can be
** copied around as a unit.  For permuting the y and z axes of a
** matrix-x-y-z order matrix volume, this optimization produced a
** factor of 5 speed up (exhaustive multi-platform tests, of course).
**
** The axes[] array determines the permutation of the axes.
** axis[i] = j means: axis i in the output will be the input's axis j
** (axis[i] answers: "what do I put here", from the standpoint of the output,
** not "where do I put this", from the standpoint of the input)
*/
int
nrrdAxesPermute(Nrrd *nout, const Nrrd *nin, const unsigned int *axes) {
  static const char me[]="nrrdAxesPermute", func[]="permute";
  char buff1[NRRD_DIM_MAX*30], buff2[AIR_STRLEN_SMALL];
  size_t idxOut, idxInA=0,   /* indices for input and output scanlines */
    lineSize,                /* size of block of memory which can be
                                moved contiguously from input to output,
                                thought of as a "scanline" */
    numLines,                /* how many "scanlines" there are to permute */
    szIn[NRRD_DIM_MAX], *lszIn,
    szOut[NRRD_DIM_MAX], *lszOut,
    cIn[NRRD_DIM_MAX],
    cOut[NRRD_DIM_MAX];
  char *dataIn, *dataOut;
  int axmap[NRRD_DIM_MAX];
  unsigned int
    ai,                      /* running index along dimensions */
    lowPax,                  /* lowest axis which is "p"ermutated */
    ldim,                    /* nin->dim - lowPax */
    ip[NRRD_DIM_MAX+1],      /* inverse of permutation in "axes" */
    laxes[NRRD_DIM_MAX+1];   /* copy of axes[], but shifted down by lowPax
                                elements, to remove i such that i == axes[i] */
  airArray *mop;

  mop = airMopNew();
  if (!(nin && nout && axes)) {
    biffAddf(NRRD, "%s: got NULL pointer", me);
    airMopError(mop); return 1;
  }
  /* we don't actually need ip[], computing it is for error checking */
  if (nrrdInvertPerm(ip, axes, nin->dim)) {
    biffAddf(NRRD, "%s: couldn't compute axis permutation inverse", me);
    airMopError(mop); return 1;
  }
  /* this shouldn't actually be necessary .. */
  if (!nrrdElementSize(nin)) {
    biffAddf(NRRD, "%s: nrrd reports zero element size!", me);
    airMopError(mop); return 1;
  }

  for (ai=0; ai<nin->dim && axes[ai] == ai; ai++)
    ;
  lowPax = ai;

  /* allocate output by initial copy */
  if (nout != nin) {
    if (nrrdCopy(nout, nin)) {
      biffAddf(NRRD, "%s: trouble copying input", me);
      airMopError(mop); return 1;
    }
    dataIn = (char*)nin->data;
  } else {
    dataIn = (char*)calloc(nrrdElementNumber(nin), nrrdElementSize(nin));
    if (!dataIn) {
      biffAddf(NRRD, "%s: couldn't create local copy of data", me);
      airMopError(mop); return 1;
    }
    airMopAdd(mop, dataIn, airFree, airMopAlways);
    memcpy(dataIn, nin->data, nrrdElementNumber(nin)*nrrdElementSize(nin));
  }
  if (lowPax < nin->dim) {
    /* if lowPax == nin->dim, then we were given the identity permutation, so
       there's nothing to do other than the copy already done.  Otherwise,
       here we are (actually, lowPax < nin->dim-1) */
    for (ai=0; ai<nin->dim; ai++) {
      axmap[ai] = AIR_INT(axes[ai]);
    }
    nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, szIn);
    if (nrrdAxisInfoCopy(nout, nin, axmap, NRRD_AXIS_INFO_NONE)) {
      biffAddf(NRRD, "%s:", me);
      airMopError(mop); return 1;
    }
    nrrdAxisInfoGet_nva(nout, nrrdAxisInfoSize, szOut);
    /* the skinny */
    lineSize = 1;
    for (ai=0; ai<lowPax; ai++) {
      lineSize *= szIn[ai];
    }
    numLines = nrrdElementNumber(nin)/lineSize;
    lineSize *= nrrdElementSize(nin);
    lszIn = szIn + lowPax;
    lszOut = szOut + lowPax;
    ldim = nin->dim - lowPax;
    memset(laxes, 0, sizeof(laxes));
    for (ai=0; ai<ldim; ai++) {
      laxes[ai] = axes[ai+lowPax]-lowPax;
    }
    dataOut = AIR_CAST(char *, nout->data);
    memset(cIn, 0, sizeof(cIn));
    memset(cOut, 0, sizeof(cOut));
    for (idxOut=0; idxOut<numLines; idxOut++) {
      /* in our representation of the coordinates of the start of the
         scanlines that we're copying, we are not even storing all the
         zeros in the coordinates prior to lowPax, and when we go to
         a linear index for the memcpy(), we multiply by lineSize */
      for (ai=0; ai<ldim; ai++) {
        cIn[laxes[ai]] = cOut[ai];
      }
      NRRD_INDEX_GEN(idxInA, cIn, lszIn, ldim);
      memcpy(dataOut + idxOut*lineSize, dataIn + idxInA*lineSize, lineSize);
      NRRD_COORD_INCR(cOut, lszOut, ldim, 0);
    }
    /* set content */
    strcpy(buff1, "");
    for (ai=0; ai<nin->dim; ai++) {
      sprintf(buff2, "%s%d", (ai ? "," : ""), axes[ai]);
      strcat(buff1, buff2);
    }
    if (nrrdContentSet_va(nout, func, nin, "%s", buff1)) {
      biffAddf(NRRD, "%s:", me);
      airMopError(mop); return 1;
    }
    if (nout != nin) {
      if (nrrdBasicInfoCopy(nout, nin,
                            NRRD_BASIC_INFO_DATA_BIT
                            | NRRD_BASIC_INFO_TYPE_BIT
                            | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                            | NRRD_BASIC_INFO_DIMENSION_BIT
                            | NRRD_BASIC_INFO_CONTENT_BIT
                            | NRRD_BASIC_INFO_COMMENTS_BIT
                            | (nrrdStateKeyValuePairsPropagate
                               ? 0
                               : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
        biffAddf(NRRD, "%s:", me);
        airMopError(mop); return 1;
      }
    }
  }
  airMopOkay(mop);
  return 0;
}
Пример #12
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;
}
Пример #13
0
int
nrrdArithIterTernaryOpSelect(Nrrd *nout, int op,
                             NrrdIter *inA, NrrdIter *inB, NrrdIter *inC,
                             unsigned int which) {
  static const char me[]="nrrdArithIterTernaryOpSelect";
  char *contA, *contB, *contC;
  size_t N, I, size[NRRD_DIM_MAX];
  int type;
  double (*insert)(void *v, size_t I, double d),
    (*top)(double a, double b, double c), valA, valB, valC;
  const Nrrd *nin;

  if (!(nout && inA && inB && inC)) {
    biffAddf(NRRD, "%s: got NULL pointer", me);
    return 1;
  }
  if (airEnumValCheck(nrrdTernaryOp, op)) {
    biffAddf(NRRD, "%s: ternary op %d invalid", me, op);
    return 1;
  }
  if (!( 0 == which || 1 == which || 2 == which )) {
    biffAddf(NRRD, "%s: which %u not valid, want 0, 1, or 2", me, which);
    return 1;
  }
  nin = (0 == which
         ? _NRRD_ITER_NRRD(inA)
         : (1 == which
            ? _NRRD_ITER_NRRD(inB)
            : _NRRD_ITER_NRRD(inC)));
  if (!nin) {
    biffAddf(NRRD, "%s: selected input %u is a fixed value", me, which);
    return 1;
  }
  type = nin->type;
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size);
  if (_nrrdMaybeAllocMaybeZero_nva(nout, type, nin->dim, size,
                                   AIR_FALSE /* zero when no realloc */)) {
    biffAddf(NRRD, "%s: couldn't allocate output nrrd", me);
    return 1;
  }
  nrrdBasicInfoCopy(nout, nin, (NRRD_BASIC_INFO_DATA_BIT
                                | NRRD_BASIC_INFO_TYPE_BIT
                                | NRRD_BASIC_INFO_DIMENSION_BIT
                                | NRRD_BASIC_INFO_CONTENT_BIT
                                | NRRD_BASIC_INFO_COMMENTS_BIT
                                | (nrrdStateKeyValuePairsPropagate
                                   ? 0
                                   : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT)));
  nrrdBasicInfoInit(nout,
                    NRRD_BASIC_INFO_ALL ^ (NRRD_BASIC_INFO_OLDMIN_BIT
                                           | NRRD_BASIC_INFO_OLDMAX_BIT));
  top = _nrrdTernaryOp[op];

  /*
  fprintf(stderr, "%!s: inA->left = %d, inB->left = %d\n", me,
          (int)(inA->left), (int)(inB->left));
  */
  N = nrrdElementNumber(nin);
  insert = nrrdDInsert[type];
  for (I=0; I<N; I++) {
    /* HEY: there is a loss of precision issue here with 64-bit ints */
    valA = nrrdIterValue(inA);
    valB = nrrdIterValue(inB);
    valC = nrrdIterValue(inC);
    /*
    if (!(I % 1000)) {
      fprintf(stderr, "!%s: %d: top(%g,%g,%g) = %g\n", me, (int)I,
              valA, valB, valC,
              top(valA, valB, valC));
    }
    */
    insert(nout->data, I, top(valA, valB, valC));
  }
  contA = nrrdIterContent(inA);
  contB = nrrdIterContent(inB);
  contC = nrrdIterContent(inC);
  if (_nrrdContentSet_va(nout, airEnumStr(nrrdTernaryOp, op),
                         contA, "%s,%s", contB, contC)) {
    biffAddf(NRRD, "%s:", me);
    free(contA); free(contB); free(contC); return 1;
  }
  if (nout != nin) {
    nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_NONE);
  }
  free(contA);
  free(contB);
  free(contC);
  return 0;
}
Пример #14
0
/*
******** nrrdArithTerneryOp
**
** HEY: UNTESTED UNTESTED UNTESTED UNTESTED UNTESTED UNTESTED UNTESTED
**
** this is a simplified version of nrrdArithIterTernaryOp, written after
** that, in a hurry, to operate directly on three nrrds, instead with
** the NrrdIter nonsense
*/
int
nrrdArithTernaryOp(Nrrd *nout, int op, const Nrrd *ninA,
                   const Nrrd *ninB, const Nrrd *ninC) {
  static const char me[]="nrrdArithTernaryOp";
  char *contA, *contB, *contC;
  size_t N, I, size[NRRD_DIM_MAX];
  double (*ins)(void *v, size_t I, double d),
    (*lupA)(const void *v, size_t I), (*lupB)(const void *v, size_t I),
    (*lupC)(const void *v, size_t I),
    (*top)(double a, double b, double c), valA, valB, valC;

  if (!( nout && !nrrdCheck(ninA) && !nrrdCheck(ninB) && !nrrdCheck(ninC) )) {
    biffAddf(NRRD, "%s: NULL pointer or invalid args", me);
    return 1;
  }
  if (!( nrrdSameSize(ninA, ninB, AIR_TRUE) &&
         nrrdSameSize(ninA, ninC, AIR_TRUE) )) {
    biffAddf(NRRD, "%s: size mismatch between arguments", me);
    return 1;
  }
  if (airEnumValCheck(nrrdTernaryOp, op)) {
    biffAddf(NRRD, "%s: ternary op %d invalid", me, op);
    return 1;
  }

  nrrdAxisInfoGet_nva(ninA, nrrdAxisInfoSize, size);
  if (!( nout == ninA || nout == ninB || nout == ninC)) {
    if (_nrrdMaybeAllocMaybeZero_nva(nout, ninA->type, ninA->dim, size,
                                     AIR_FALSE /* zero when no realloc */)) {
      biffAddf(NRRD, "%s: couldn't allocate output nrrd", me);
      return 1;
    }
    if (nrrdAxisInfoCopy(nout, ninA, NULL, NRRD_AXIS_INFO_NONE)) {
      biffAddf(NRRD, "%s:", me);
      return 1;
    }
    nrrdBasicInfoCopy(nout, ninA, (NRRD_BASIC_INFO_DATA_BIT
                                   | NRRD_BASIC_INFO_TYPE_BIT
                                   | NRRD_BASIC_INFO_DIMENSION_BIT
                                   | NRRD_BASIC_INFO_CONTENT_BIT
                                   | NRRD_BASIC_INFO_COMMENTS_BIT
                                   | (nrrdStateKeyValuePairsPropagate
                                      ? 0
                                      : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT)));
  }
  nrrdBasicInfoInit(nout,
                    NRRD_BASIC_INFO_ALL ^ (NRRD_BASIC_INFO_OLDMIN_BIT
                                           | NRRD_BASIC_INFO_OLDMAX_BIT));
  top = _nrrdTernaryOp[op];

  N = nrrdElementNumber(ninA);
  lupA = nrrdDLookup[ninA->type];
  lupB = nrrdDLookup[ninB->type];
  lupC = nrrdDLookup[ninC->type];
  ins = nrrdDInsert[nout->type];
  for (I=0; I<N; I++) {
    /* HEY: there is a loss of precision issue here with 64-bit ints */
    valA = lupA(ninA->data, I);
    valB = lupB(ninB->data, I);
    valC = lupC(ninC->data, I);
    ins(nout->data, I, top(valA, valB, valC));
  }

  contA = _nrrdContentGet(ninA);
  contB = _nrrdContentGet(ninB);
  contC = _nrrdContentGet(ninC);
  if (_nrrdContentSet_va(nout, airEnumStr(nrrdTernaryOp, op),
                         contA, "%s,%s", contB, contC)) {
    biffAddf(NRRD, "%s:", me);
    free(contA); free(contB); free(contC); return 1;
  }
  free(contA);
  free(contB);
  free(contC);

  return 0;
}
Пример #15
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;
}
Пример #16
0
/*
** _nrrdApply2DSetUp()
**
** some error checking and initializing needed for 2D LUTS and regular
** maps.  The intent is that if this succeeds, then there is no need
** for any further error checking.
**
** The only thing this function DOES is allocate the output nrrd, and
** set meta information.  The rest is just error checking.
**
** The given NrrdRange has to be fleshed out by the caller: it can't
** be NULL, and both range->min and range->max must exist.
*/
int
_nrrdApply2DSetUp(Nrrd *nout, const Nrrd *nin,
                  const NrrdRange *range0, const NrrdRange *range1,
                  const Nrrd *nmap, int kind, int typeOut,
                  int rescale0, int rescale1) {
  char me[]="_nrrdApply2DSetUp", err[BIFF_STRLEN], *mapcnt;
  char nounStr[][AIR_STRLEN_SMALL]={"2D lut",
                                    "2D regular map"};
  char verbStr[][AIR_STRLEN_SMALL]={"lut2",
                                    "rmap2"};
  int mapAxis, copyMapAxis0=AIR_FALSE, axisMap[NRRD_DIM_MAX];
  unsigned int dim, entLen;
  size_t size[NRRD_DIM_MAX];
  double domMin, domMax;

  if (nout == nin) {
    sprintf(err, "%s: due to laziness, nout==nin always disallowed", me);
    biffAdd(NRRD, err); return 1;
  }
  if (airEnumValCheck(nrrdType, typeOut)) {
    sprintf(err, "%s: invalid requested output type %d", me, typeOut);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdTypeBlock == nin->type || nrrdTypeBlock == typeOut) {
    sprintf(err, "%s: input or requested output type is %s, need scalar",
            me, airEnumStr(nrrdType, nrrdTypeBlock));
    biffAdd(NRRD, err); return 1;
  }
  if (!(2 == nin->axis[0].size)) {
    sprintf(err, "%s: input axis[0] must have size 2 (not " 
            _AIR_SIZE_T_CNV ")", me, nin->axis[0].size);
    biffAdd(NRRD, err); return 1;
  }
  if (!(nin->dim > 1)) {
    sprintf(err, "%s: input dimension must be > 1 (not %u)", me, nin->dim);
    biffAdd(NRRD, err); return 1;
  }
  if (rescale0 && !(range0
                    && AIR_EXISTS(range0->min) 
                    && AIR_EXISTS(range0->max))) {
    sprintf(err, "%s: want axis 0 rescaling but didn't get range, or "
            "not both range->{min,max} exist", me);
    biffAdd(NRRD, err); return 1;
  }
  if (rescale1 && !(range1
                    && AIR_EXISTS(range1->min) 
                    && AIR_EXISTS(range1->max))) {
    sprintf(err, "%s: want axis 1 rescaling but didn't get range, or "
            "not both range->{min,max} exist", me);
    biffAdd(NRRD, err); return 1;
  }
  mapAxis = nmap->dim - 2;
  if (!(0 == mapAxis || 1 == mapAxis)) {
    sprintf(err, "%s: dimension of %s should be 2 or 3, not %d", 
            me, nounStr[kind], nmap->dim);
    biffAdd(NRRD, err); return 1;
  }
  copyMapAxis0 = (1 == mapAxis);
  domMin = _nrrdApplyDomainMin(nmap, AIR_FALSE, mapAxis);
  domMax = _nrrdApplyDomainMax(nmap, AIR_FALSE, mapAxis);
  if (!( domMin < domMax )) {
    sprintf(err, "%s: (axis %d) domain min (%g) not less than max (%g)", me,
            mapAxis, domMin, domMax);
    biffAdd(NRRD, err); return 1;
  }
  domMin = _nrrdApplyDomainMin(nmap, AIR_FALSE, mapAxis+1);
  domMax = _nrrdApplyDomainMax(nmap, AIR_FALSE, mapAxis+1);
  if (!( domMin < domMax )) {
    sprintf(err, "%s: (axis %d) domain min (%g) not less than max (%g)", me,
            mapAxis+1, domMin, domMax);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdHasNonExist(nmap)) {
    sprintf(err, "%s: %s nrrd has non-existent values",
            me, nounStr[kind]);
    biffAdd(NRRD, err); return 1;
  }
  entLen = mapAxis ? nmap->axis[0].size : 1;
  if (mapAxis + nin->dim - 1 > NRRD_DIM_MAX) {
    sprintf(err, "%s: input nrrd dim %d through non-scalar %s exceeds "
            "NRRD_DIM_MAX %d",
            me, nin->dim, nounStr[kind], NRRD_DIM_MAX);
    biffAdd(NRRD, err); return 1;
  }
  if (mapAxis) {
    size[0] = entLen;
    axisMap[0] = -1;
  }
  for (dim=1; dim<nin->dim; dim++) {
    size[dim-1+mapAxis] = nin->axis[dim].size;
    axisMap[dim-1+mapAxis] = dim;
  }
  /*
  fprintf(stderr, "##%s: pre maybe alloc: nout->data = %p\n", me, nout->data);
  for (dim=0; dim<mapAxis + nin->dim - 1; dim++) {
    fprintf(stderr, "    size[%d] = %d\n", dim, (int)size[dim]);
  }
  fprintf(stderr, "   nout->dim = %u; nout->type = %d = %s; sizes = %u,%u\n", 
          nout->dim, nout->type,
          airEnumStr(nrrdType, nout->type),
          AIR_CAST(unsigned int, nout->axis[0].size),
          AIR_CAST(unsigned int, nout->axis[1].size));
  fprintf(stderr, "   typeOut = %d = %s\n", typeOut,
          airEnumStr(nrrdType, typeOut));
  */
  if (nrrdMaybeAlloc_nva(nout, typeOut, nin->dim - 1 + mapAxis, size)) {
    sprintf(err, "%s: couldn't allocate output nrrd", me);
    biffAdd(NRRD, err); return 1;
  }
  /*
  fprintf(stderr, "   nout->dim = %d; nout->type = %d = %s\n",
          nout->dim, nout->type,
          airEnumStr(nrrdType, nout->type));
  for (dim=0; dim<nout->dim; dim++) {
    fprintf(stderr, "    size[%d] = %d\n", dim, (int)nout->axis[dim].size);
  }
  fprintf(stderr, "##%s: post maybe alloc: nout->data = %p\n", me, nout->data);
  */
  if (nrrdAxisInfoCopy(nout, nin, axisMap, NRRD_AXIS_INFO_NONE)) {
    sprintf(err, "%s: trouble copying axis info", me);
    biffAdd(NRRD, err); return 1;
  }
  if (copyMapAxis0) {
    _nrrdAxisInfoCopy(nout->axis + 0, nmap->axis + 0,
                      NRRD_AXIS_INFO_SIZE_BIT);
  }

  mapcnt = _nrrdContentGet(nmap);
  if (nrrdContentSet_va(nout, verbStr[kind], nin, "%s", mapcnt)) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); free(mapcnt); return 1;
  }
  free(mapcnt); 
  nrrdBasicInfoInit(nout, (NRRD_BASIC_INFO_DATA_BIT
                           | NRRD_BASIC_INFO_TYPE_BIT
                           | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                           | NRRD_BASIC_INFO_DIMENSION_BIT
                           | NRRD_BASIC_INFO_CONTENT_BIT));
  return 0;
}
Пример #17
0
/*
******** nrrdSpatialResample()
**
** general-purpose array-resampler: resamples a nrrd of any type
** (except block) and any dimension along any or all of its axes, with
** any combination of up- or down-sampling along the axes, with any
** kernel (specified by callback), with potentially a different kernel
** for each axis.  Whether or not to resample along axis d is
** controlled by the non-NULL-ity of info->kernel[ai].  Where to sample
** on the axis is controlled by info->min[ai] and info->max[ai]; these
** specify a range of "positions" aka "world space" positions, as 
** determined by the per-axis min and max of the input nrrd, which must
** be set for every resampled axis.
** 
** we cyclically permute those axes being resampled, and never touch
** the position (in axis ordering) of axes along which we are not
** resampling.  This strategy is certainly not the most intelligent
** one possible, but it does mean that the axis along which we're
** currently resampling-- the one along which we'll have to look at
** multiple adjecent samples-- is that resampling axis which is
** currently most contiguous in memory.  It may make sense to precede
** the resampling with an axis permutation which bubbles all the
** resampled axes to the front (most contiguous) end of the axis list,
** and then puts them back in place afterwards, depending on the cost
** of such axis permutation overhead.
*/
int
nrrdSpatialResample(Nrrd *nout, const Nrrd *nin,
                    const NrrdResampleInfo *info) {
  char me[]="nrrdSpatialResample", func[]="resample", err[BIFF_STRLEN];
  nrrdResample_t
    *array[NRRD_DIM_MAX],      /* intermediate copies of the input data
                                  undergoing resampling; we don't need a full-
                                  fledged nrrd for these.  Only about two of
                                  these arrays will be allocated at a time;
                                  intermediate results will be free()d when not
                                  needed */
    *_inVec,                   /* current input vector being resampled;
                                  not necessarily contiguous in memory
                                  (if strideIn != 1) */
    *inVec,                    /* buffer for input vector; contiguous */
    *_outVec;                  /* output vector in context of volume;
                                  never contiguous */
  double tmpF;
  double ratio,                /* factor by which or up or downsampled */
    ratios[NRRD_DIM_MAX];      /* record of "ratio" for all resampled axes,
                                  used to compute new spacing in output */

  Nrrd *floatNin;              /* if the input nrrd type is not nrrdResample_t,
                                  then we convert it and keep it here */
  unsigned int ai,
    pi,                        /* current pass */
    topLax,
    permute[NRRD_DIM_MAX],     /* how to permute axes of last pass to get
                                  axes for current pass */
    ax[NRRD_DIM_MAX+1][NRRD_DIM_MAX],  /* axis ordering on each pass */
    passes;                    /* # of passes needed to resample all axes */
  int i, s, e,
    topRax,                    /* the lowest index of an axis which is
                                  resampled.  If all axes are being resampled,
                                  then this is 0.  If for some reason the
                                  "x" axis (fastest stride) is not being
                                  resampled, but "y" is, then topRax is 1 */
    botRax,                    /* index of highest axis being resampled */
    typeIn, typeOut;           /* types of input and output of resampling */
  size_t sz[NRRD_DIM_MAX+1][NRRD_DIM_MAX];
                               /* how many samples along each
                                  axis, changing on each pass */

  /* all these variables have to do with the spacing of elements in
     memory for the current pass of resampling, and they (except
     strideIn) are re-set at the beginning of each pass */
  nrrdResample_t
    *weight;                  /* sample weights */
  unsigned int ci[NRRD_DIM_MAX+1],
    co[NRRD_DIM_MAX+1];
  int 
    sizeIn, sizeOut,          /* lengths of input and output vectors */
    dotLen,                   /* # input samples to dot with weights to get
                                 one output sample */
    doRound,                  /* actually do rounding on output: we DO NOT
                                 round when info->round but the output 
                                 type is not integral */
    *index;                   /* dotLen*sizeOut 2D array of input indices */
  size_t 
    I,                        /* swiss-army int */
    strideIn,                 /* the stride between samples in the input
                                 "scanline" being resampled */
    strideOut,                /* stride between samples in output 
                                 "scanline" from resampling */
    L, LI, LO, numLines,      /* top secret */
    numOut;                   /* # of _samples_, total, in output volume;
                                 this is for allocating the output */
  airArray *mop;              /* for cleaning up */
  
  if (!(nout && nin && info)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdBoundaryUnknown == info->boundary) {
    sprintf(err, "%s: need to specify a boundary behavior", me);
    biffAdd(NRRD, err); return 1;
  }

  typeIn = nin->type;
  typeOut = nrrdTypeDefault == info->type ? typeIn : info->type;

  if (_nrrdResampleCheckInfo(nin, info)) {
    sprintf(err, "%s: problem with arguments", me);
    biffAdd(NRRD, err); return 1;
  }
  
  _nrrdResampleComputePermute(permute, ax, sz,
                              &topRax, &botRax, &passes,
                              nin, info);
  topLax = topRax ? 0 : 1;

  /* not sure where else to put this:
     (want to put it before 0 == passes branch)
     We have to assume some centering when doing resampling, and it would
     be stupid to not record it in the outgoing nrrd, since the value of
     nrrdDefaultCenter could always change. */
  for (ai=0; ai<nin->dim; ai++) {
    if (info->kernel[ai]) {
      nout->axis[ai].center = _nrrdCenter(nin->axis[ai].center);
    }
  }

  if (0 == passes) {
    /* actually, no resampling was desired.  Copy input to output,
       but with the clamping that we normally do at the end of resampling */
    nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, sz[0]);
    if (nrrdMaybeAlloc_nva(nout, typeOut, nin->dim, sz[0])) {
      sprintf(err, "%s: couldn't allocate output", me);
      biffAdd(NRRD, err); return 1;
    }
    numOut = nrrdElementNumber(nout);
    for (I=0; I<numOut; I++) {
      tmpF = nrrdDLookup[nin->type](nin->data, I);
      tmpF = nrrdDClamp[typeOut](tmpF);
      nrrdDInsert[typeOut](nout->data, I, tmpF);
    }
    nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_NONE);
    /* HEY: need to create textual representation of resampling parameters */
    if (nrrdContentSet_va(nout, func, nin, "")) {
      sprintf(err, "%s:", me);
      biffAdd(NRRD, err); return 1;
    }
    if (nrrdBasicInfoCopy(nout, nin,
                          NRRD_BASIC_INFO_DATA_BIT
                          | NRRD_BASIC_INFO_TYPE_BIT
                          | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                          | NRRD_BASIC_INFO_DIMENSION_BIT
                          | NRRD_BASIC_INFO_CONTENT_BIT
                          | NRRD_BASIC_INFO_COMMENTS_BIT
                          | (nrrdStateKeyValuePairsPropagate
                             ? 0
                             : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
      sprintf(err, "%s:", me);
      biffAdd(NRRD, err); return 1;
    }
    return 0;
  }

  mop = airMopNew();
  /* convert input nrrd to nrrdResample_t if necessary */
  if (nrrdResample_nrrdType != typeIn) {
    if (nrrdConvert(floatNin = nrrdNew(), nin, nrrdResample_nrrdType)) {
      sprintf(err, "%s: couldn't create float copy of input", me);
      biffAdd(NRRD, err); airMopError(mop); return 1;
    }
    array[0] = (nrrdResample_t*)floatNin->data;
    airMopAdd(mop, floatNin, (airMopper)nrrdNuke, airMopAlways);
  } else {
    floatNin = NULL;
    array[0] = (nrrdResample_t*)nin->data;
  }
  
  /* compute strideIn; this is actually the same for every pass
     because (strictly speaking) in every pass we are resampling
     the same axis, and axes with lower indices are constant length */
  strideIn = 1;
  for (ai=0; ai<(unsigned int)topRax; ai++) { /* HEY scrutinize casts */
    strideIn *= nin->axis[ai].size;
  }
  /*
  printf("%s: strideIn = " _AIR_SIZE_T_CNV "\n", me, strideIn);
  */

  /* go! */
  for (pi=0; pi<passes; pi++) {
    /*
    printf("%s: --- pass %d --- \n", me, pi);
    */
    numLines = strideOut = 1;
    for (ai=0; ai<nin->dim; ai++) {
      if (ai < (unsigned int)botRax) {   /* HEY scrutinize cast */
        strideOut *= sz[pi+1][ai];
      }
      if (ai != (unsigned int)topRax) {  /* HEY scrutinize cast */
        numLines *= sz[pi][ai];
      }
    }
    sizeIn = sz[pi][topRax];
    sizeOut = sz[pi+1][botRax];
    numOut = numLines*sizeOut;
    /* for the rest of the loop body, d is the original "dimension"
       for the axis being resampled */
    ai = ax[pi][topRax];
    /*
    printf("%s(%d): numOut = " _AIR_SIZE_T_CNV "\n", me, pi, numOut);
    printf("%s(%d): numLines = " _AIR_SIZE_T_CNV "\n", me, pi, numLines);
    printf("%s(%d): stride: In=%d, Out=%d\n", me, pi, 
           (int)strideIn, (int)strideOut);
    printf("%s(%d): sizeIn = %d\n", me, pi, sizeIn);
    printf("%s(%d): sizeOut = %d\n", me, pi, sizeOut);
    */

    /* we can free the input to the previous pass 
       (if its not the given data) */
    if (pi > 0) {
      if (pi == 1) {
        if (array[0] != nin->data) {
          airMopSub(mop, floatNin, (airMopper)nrrdNuke);
          floatNin = nrrdNuke(floatNin);
          array[0] = NULL;
          /*
          printf("%s: pi %d: freeing array[0]\n", me, pi);
          */
        }
      } else {
        airMopSub(mop, array[pi-1], airFree);
        array[pi-1] = (nrrdResample_t*)airFree(array[pi-1]);
        /*
        printf("%s: pi %d: freeing array[%d]\n", me, pi, pi-1);
        */
      }
    }

    /* allocate output volume */
    array[pi+1] = (nrrdResample_t*)calloc(numOut, sizeof(nrrdResample_t));
    if (!array[pi+1]) {
      sprintf(err, "%s: couldn't create array of " _AIR_SIZE_T_CNV 
              " nrrdResample_t's for output of pass %d",
              me, numOut, pi);
      biffAdd(NRRD, err); airMopError(mop); return 1;
    }
    airMopAdd(mop, array[pi+1], airFree, airMopAlways);
    /*
    printf("%s: allocated array[%d]\n", me, pi+1);
    */

    /* allocate contiguous input scanline buffer, we alloc one more
       than needed to provide a place for the pad value.  That is, in
       fact, the over-riding reason to copy a scanline to a local
       array: so that there is a simple consistent (non-branchy) way
       to incorporate the pad values */
    inVec = (nrrdResample_t *)calloc(sizeIn+1, sizeof(nrrdResample_t));
    airMopAdd(mop, inVec, airFree, airMopAlways);
    inVec[sizeIn] = AIR_CAST(nrrdResample_t, info->padValue);

    dotLen = _nrrdResampleMakeWeightIndex(&weight, &index, &ratio,
                                          nin, info, ai);
    if (!dotLen) {
      sprintf(err, "%s: trouble creating weight and index vector arrays", me);
      biffAdd(NRRD, err); airMopError(mop); return 1;
    }
    ratios[ai] = ratio;
    airMopAdd(mop, weight, airFree, airMopAlways);
    airMopAdd(mop, index, airFree, airMopAlways);

    /* the skinny: resample all the scanlines */
    _inVec = array[pi];
    _outVec = array[pi+1];
    memset(ci, 0, (NRRD_DIM_MAX+1)*sizeof(int));
    memset(co, 0, (NRRD_DIM_MAX+1)*sizeof(int));
    for (L=0; L<numLines; L++) {
      /* calculate the index to get to input and output scanlines,
         according the coordinates of the start of the scanline */
      NRRD_INDEX_GEN(LI, ci, sz[pi], nin->dim);
      NRRD_INDEX_GEN(LO, co, sz[pi+1], nin->dim);
      _inVec = array[pi] + LI;
      _outVec = array[pi+1] + LO;
      
      /* read input scanline into contiguous array */
      for (i=0; i<sizeIn; i++) {
        inVec[i] = _inVec[i*strideIn];
      }

      /* do the weighting */
      for (i=0; i<sizeOut; i++) {
        tmpF = 0.0;
        /*
        fprintf(stderr, "%s: i = %d (tmpF=0)\n", me, (int)i);
        */
        for (s=0; s<dotLen; s++) {
          tmpF += inVec[index[s + dotLen*i]]*weight[s + dotLen*i];
          /*
          fprintf(stderr, "  tmpF += %g*%g == %g\n",
                  inVec[index[s + dotLen*i]], weight[s + dotLen*i], tmpF);
          */
        }
        _outVec[i*strideOut] = tmpF;
        /*
        fprintf(stderr, "--> out[%d] = %g\n",
                i*strideOut, _outVec[i*strideOut]);
        */
      }
 
      /* update the coordinates for the scanline starts.  We don't
         use the usual NRRD_COORD macros because we're subject to
         the unusual constraint that ci[topRax] and co[permute[topRax]]
         must stay exactly zero */
      e = topLax;
      ci[e]++; 
      co[permute[e]]++;
      while (L < numLines-1 && ci[e] == sz[pi][e]) {
        ci[e] = co[permute[e]] = 0;
        e++;
        e += e == topRax;
        ci[e]++; 
        co[permute[e]]++;
      }
    }

    /* pass-specific clean up */
    airMopSub(mop, weight, airFree);
    airMopSub(mop, index, airFree);
    airMopSub(mop, inVec, airFree);
    weight = (nrrdResample_t*)airFree(weight);
    index = (int*)airFree(index);
    inVec = (nrrdResample_t*)airFree(inVec);
  }

  /* clean up second-to-last array and scanline buffers */
  if (passes > 1) {
    airMopSub(mop, array[passes-1], airFree);
    array[passes-1] = (nrrdResample_t*)airFree(array[passes-1]);
    /*
    printf("%s: now freeing array[%d]\n", me, passes-1);
    */
  } else if (array[passes-1] != nin->data) {
    airMopSub(mop, floatNin, (airMopper)nrrdNuke);
    floatNin = nrrdNuke(floatNin);
  }
  array[passes-1] = NULL;
  
  /* create output nrrd and set axis info */
  if (nrrdMaybeAlloc_nva(nout, typeOut, nin->dim, sz[passes])) {
    sprintf(err, "%s: couldn't allocate final output nrrd", me);
    biffAdd(NRRD, err); airMopError(mop); return 1;
  }
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopOnError);
  nrrdAxisInfoCopy(nout, nin, NULL, 
                   (NRRD_AXIS_INFO_SIZE_BIT
                    | NRRD_AXIS_INFO_MIN_BIT
                    | NRRD_AXIS_INFO_MAX_BIT
                    | NRRD_AXIS_INFO_SPACING_BIT
                    | NRRD_AXIS_INFO_SPACEDIRECTION_BIT  /* see below */
                    | NRRD_AXIS_INFO_THICKNESS_BIT
                    | NRRD_AXIS_INFO_KIND_BIT));
  for (ai=0; ai<nin->dim; ai++) {
    if (info->kernel[ai]) {
      /* we do resample this axis */
      nout->axis[ai].spacing = nin->axis[ai].spacing/ratios[ai];
      /* no way to usefully update thickness: we could be doing blurring
         but maintaining the number of samples: thickness increases, or
         we could be downsampling, in which the relationship between the
         sampled and the skipped regions of space becomes complicated:
         no single scalar can represent it, or we could be upsampling,
         in which the notion of "skip" could be rendered meaningless */
      nout->axis[ai].thickness = AIR_NAN;
      nout->axis[ai].min = info->min[ai];
      nout->axis[ai].max = info->max[ai];
      /*
        HEY: this is currently a bug: all this code was written long
        before there were space directions, so min/max are always 
        set, regardless of whethere there are incoming space directions
        which then disallows output space directions on the same axes
      _nrrdSpaceVecScale(nout->axis[ai].spaceDirection,
                         1.0/ratios[ai], nin->axis[ai].spaceDirection);
      */
      nout->axis[ai].kind = _nrrdKindAltered(nin->axis[ai].kind, AIR_TRUE);
    } else {
      /* this axis remains untouched */
      nout->axis[ai].min = nin->axis[ai].min;
      nout->axis[ai].max = nin->axis[ai].max;
      nout->axis[ai].spacing = nin->axis[ai].spacing;
      nout->axis[ai].thickness = nin->axis[ai].thickness;
      nout->axis[ai].kind = nin->axis[ai].kind;
    }
  }
  /* HEY: need to create textual representation of resampling parameters */
  if (nrrdContentSet_va(nout, func, nin, "")) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); return 1;
  }

  /* copy the resampling final result into the output nrrd, maybe
     rounding as we go to make sure that 254.9999 is saved as 255
     in uchar output, and maybe clamping as we go to insure that
     integral results don't have unexpected wrap-around. */
  if (info->round) {
    if (nrrdTypeInt == typeOut ||
        nrrdTypeUInt == typeOut ||
        nrrdTypeLLong == typeOut ||
        nrrdTypeULLong == typeOut) {
      fprintf(stderr, "%s: WARNING: possible erroneous output with "
              "rounding of %s output type due to int-based implementation "
              "of rounding\n", me, airEnumStr(nrrdType, typeOut));
    }
    doRound = nrrdTypeIsIntegral[typeOut];
  } else {
    doRound = AIR_FALSE;
  }
  numOut = nrrdElementNumber(nout);
  for (I=0; I<numOut; I++) {
    tmpF = array[passes][I];
    if (doRound) {
      tmpF = AIR_CAST(nrrdResample_t, AIR_ROUNDUP(tmpF));
    }
    if (info->clamp) {
      tmpF = nrrdDClamp[typeOut](tmpF);
    }
    nrrdDInsert[typeOut](nout->data, I, tmpF);
  }

  if (nrrdBasicInfoCopy(nout, nin,
                        NRRD_BASIC_INFO_DATA_BIT
                        | NRRD_BASIC_INFO_TYPE_BIT
                        | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                        | NRRD_BASIC_INFO_DIMENSION_BIT
                        | NRRD_BASIC_INFO_CONTENT_BIT
                        | NRRD_BASIC_INFO_COMMENTS_BIT
                        | (nrrdStateKeyValuePairsPropagate
                           ? 0
                           : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT))) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); return 1;
  }

  /* enough already */
  airMopOkay(mop);
  return 0;
}
Пример #18
0
/*
******** nrrdCrop()
**
** select some sub-volume inside a given nrrd, producing an output
** nrrd with the same dimensions, but with equal or smaller sizes
** along each axis.
*/
int
nrrdCrop(Nrrd *nout, const Nrrd *nin, size_t *min, size_t *max)
{
  char me[]="nrrdCrop", func[] = "crop", err[BIFF_STRLEN],
    buff1[NRRD_DIM_MAX*30], buff2[AIR_STRLEN_SMALL];
  unsigned int ai;
  size_t I,
  lineSize,                /* #bytes in one scanline to be copied */
  typeSize,                /* size of data type */
  cIn[NRRD_DIM_MAX],       /* coords for line start, in input */
  cOut[NRRD_DIM_MAX],      /* coords for line start, in output */
  szIn[NRRD_DIM_MAX],
  szOut[NRRD_DIM_MAX],
  idxIn=0, idxOut=0,           /* linear indices for input and output */
  numLines;                /* number of scanlines in output nrrd */
  char *dataIn, *dataOut;

  /* errors */
  if (!(nout && nin && min && max))
  {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err);
    return 1;
  }
  if (nout == nin)
  {
    sprintf(err, "%s: nout==nin disallowed", me);
    biffAdd(NRRD, err);
    return 1;
  }
  for (ai=0; ai<nin->dim; ai++)
  {
    if (!(min[ai] <= max[ai]))
    {
      sprintf(err, "%s: axis %d min (" _AIR_SIZE_T_CNV
              ") not <= max (" _AIR_SIZE_T_CNV ")",
              me, ai, min[ai], max[ai]);
      biffAdd(NRRD, err);
      return 1;
    }
    if (!( min[ai] < nin->axis[ai].size && max[ai] < nin->axis[ai].size ))
    {
      sprintf(err, "%s: axis %d min (" _AIR_SIZE_T_CNV
              ") or max (" _AIR_SIZE_T_CNV  ") out of bounds [0,"
              _AIR_SIZE_T_CNV  "]",
              me, ai, min[ai], max[ai], nin->axis[ai].size-1);
      biffAdd(NRRD, err);
      return 1;
    }
  }
  /* this shouldn't actually be necessary .. */
  if (!nrrdElementSize(nin))
  {
    sprintf(err, "%s: nrrd reports zero element size!", me);
    biffAdd(NRRD, err);
    return 1;
  }

  /* allocate */
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, szIn);
  numLines = 1;
  for (ai=0; ai<nin->dim; ai++)
  {
    szOut[ai] = max[ai] - min[ai] + 1;
    if (ai)
    {
      numLines *= szOut[ai];
    }
  }
  nout->blockSize = nin->blockSize;
  if (nrrdMaybeAlloc_nva(nout, nin->type, nin->dim, szOut))
  {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err);
    return 1;
  }
  lineSize = szOut[0]*nrrdElementSize(nin);

  /* the skinny */
  typeSize = nrrdElementSize(nin);
  dataIn = (char *)nin->data;
  dataOut = (char *)nout->data;
  memset(cOut, 0, NRRD_DIM_MAX*sizeof(unsigned int));
  /*
  printf("!%s: nin->dim = %d\n", me, nin->dim);
  printf("!%s: min  = %d %d %d\n", me, min[0], min[1], min[2]);
  printf("!%s: szIn = %d %d %d\n", me, szIn[0], szIn[1], szIn[2]);
  printf("!%s: szOut = %d %d %d\n", me, szOut[0], szOut[1], szOut[2]);
  printf("!%s: lineSize = %d\n", me, lineSize);
  printf("!%s: typeSize = %d\n", me, typeSize);
  printf("!%s: numLines = %d\n", me, (int)numLines);
  */
  for (I=0; I<numLines; I++)
  {
    for (ai=0; ai<nin->dim; ai++)
    {
      cIn[ai] = cOut[ai] + min[ai];
    }
    NRRD_INDEX_GEN(idxOut, cOut, szOut, nin->dim);
    NRRD_INDEX_GEN(idxIn, cIn, szIn, nin->dim);
    /*
    printf("!%s: %5d: cOut=(%3d,%3d,%3d) --> idxOut = %5d\n",
           me, (int)I, cOut[0], cOut[1], cOut[2], (int)idxOut);
    printf("!%s: %5d:  cIn=(%3d,%3d,%3d) -->  idxIn = %5d\n",
           me, (int)I, cIn[0], cIn[1], cIn[2], (int)idxIn);
    */
    memmove(dataOut + idxOut*typeSize, dataIn + idxIn*typeSize, lineSize);
    /* the lowest coordinate in cOut[] will stay zero, since we are
       copying one (1-D) scanline at a time */
    NRRD_COORD_INCR(cOut, szOut, nin->dim, 1);
  }
  if (nrrdAxisInfoCopy(nout, nin, NULL, (NRRD_AXIS_INFO_SIZE_BIT |
                                         NRRD_AXIS_INFO_MIN_BIT |
                                         NRRD_AXIS_INFO_MAX_BIT )))
  {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err);
    return 1;
  }
  for (ai=0; ai<nin->dim; ai++)
  {
    nrrdAxisInfoPosRange(&(nout->axis[ai].min), &(nout->axis[ai].max),
                         nin, ai, min[ai], max[ai]);
    /* do the safe thing first */
    nout->axis[ai].kind = _nrrdKindAltered(nin->axis[ai].kind, AIR_FALSE);
    /* try cleverness */
    if (!nrrdStateKindNoop)
    {
      if (nout->axis[ai].size == nin->axis[ai].size)
      {
        /* we can safely copy kind; the samples didn't change */
        nout->axis[ai].kind = nin->axis[ai].kind;
      }
      else if (nrrdKind4Color == nin->axis[ai].kind
               && 3 == szOut[ai])
      {
        nout->axis[ai].kind = nrrdKind3Color;
      }
      else if (nrrdKind4Vector == nin->axis[ai].kind
               && 3 == szOut[ai])
      {
        nout->axis[ai].kind = nrrdKind3Vector;
      }
      else if ((nrrdKind4Vector == nin->axis[ai].kind
                || nrrdKind3Vector == nin->axis[ai].kind)
               && 2 == szOut[ai])
      {
        nout->axis[ai].kind = nrrdKind2Vector;
      }
      else if (nrrdKindRGBAColor == nin->axis[ai].kind
               && 0 == min[ai]
               && 2 == max[ai])
      {
        nout->axis[ai].kind = nrrdKindRGBColor;
      }
      else if (nrrdKind2DMaskedSymMatrix == nin->axis[ai].kind
               && 1 == min[ai]
               && max[ai] == szIn[ai]-1)
      {
        nout->axis[ai].kind = nrrdKind2DSymMatrix;
      }
      else if (nrrdKind2DMaskedMatrix == nin->axis[ai].kind
               && 1 == min[ai]
               && max[ai] == szIn[ai]-1)
      {
        nout->axis[ai].kind = nrrdKind2DMatrix;
      }
      else if (nrrdKind3DMaskedSymMatrix == nin->axis[ai].kind
               && 1 == min[ai]
               && max[ai] == szIn[ai]-1)
      {
        nout->axis[ai].kind = nrrdKind3DSymMatrix;
      }
      else if (nrrdKind3DMaskedMatrix == nin->axis[ai].kind
               && 1 == min[ai]
               && max[ai] == szIn[ai]-1)
      {
        nout->axis[ai].kind = nrrdKind3DMatrix;
      }
    }
  }
  strcpy(buff1, "");
  for (ai=0; ai<nin->dim; ai++)
  {
    sprintf(buff2, "%s[" _AIR_SIZE_T_CNV  "," _AIR_SIZE_T_CNV  "]",
            (ai ? "x" : ""), min[ai], max[ai]);
    strcat(buff1, buff2);
  }
  if (nrrdContentSet_va(nout, func, nin, "%s", buff1))
  {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err);
    return 1;
  }
  if (nrrdBasicInfoCopy(nout, nin,
                        NRRD_BASIC_INFO_DATA_BIT
                        | NRRD_BASIC_INFO_TYPE_BIT
                        | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                        | NRRD_BASIC_INFO_DIMENSION_BIT
                        | NRRD_BASIC_INFO_SPACEORIGIN_BIT
                        | NRRD_BASIC_INFO_CONTENT_BIT
                        | NRRD_BASIC_INFO_COMMENTS_BIT
                        | (nrrdStateKeyValuePairsPropagate
                           ? 0
                           : NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT)))
  {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err);
    return 1;
  }
  /* copy origin, then shift it along the spatial axes */
  _nrrdSpaceVecCopy(nout->spaceOrigin, nin->spaceOrigin);
  for (ai=0; ai<nin->dim; ai++)
  {
    if (AIR_EXISTS(nin->axis[ai].spaceDirection[0]))
    {
      _nrrdSpaceVecScaleAdd2(nout->spaceOrigin,
                             1.0, nout->spaceOrigin,
                             min[ai], nin->axis[ai].spaceDirection);
    }
  }


  return 0;
}