Beispiel #1
0
void
_nrrdMeasureHistoMedian(void *ans, int ansType,
                        const void *line, int lineType, size_t len, 
                        double axmin, double axmax) {
  double sum, tmp, half, ansD, (*lup)(const void*, size_t);
  size_t ii;
  
  lup = nrrdDLookup[lineType];
  sum = 0;
  for (ii=0; ii<len; ii++) {
    tmp = lup(line, ii);
    sum += (tmp > 0 ? tmp : 0);
  }
  if (!sum) {
    nrrdDStore[ansType](ans, AIR_NAN);
    return;
  }
  /* else there was something in the histogram */
  half = sum/2;
  sum = 0;
  for (ii=0; ii<len; ii++) {
    tmp = lup(line, ii);
    sum += (tmp > 0 ? tmp : 0);
    if (sum >= half) {
      break;
    }
  }
  ansD = ii;
  if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) {
    ansD = NRRD_CELL_POS(axmin, axmax, len, ansD);
  }
  nrrdDStore[ansType](ans, ansD);
}
Beispiel #2
0
void
_nrrdMeasureProduct(void *ans, int ansType,
                    const void *line, int lineType, size_t len, 
                    double axmin, double axmax) {
  double val, P, (*lup)(const void*, size_t);
  size_t ii;

  AIR_UNUSED(axmin);
  AIR_UNUSED(axmax);
  lup = nrrdDLookup[lineType];
  if (nrrdTypeIsIntegral[lineType]) {
    P = 1.0;
    for (ii=0; ii<len; ii++) {
      P *= lup(line, ii);
    }
  } else {
    P = AIR_NAN;
    /* the point of this is to ensure that that if there are NO
       existant values, then the return is NaN */
    for (ii=0; !AIR_EXISTS(P) && ii<len; ii++) {
      P = lup(line, ii);
    }
    for (; ii<len; ii++) {
      val = lup(line, ii);
      if (AIR_EXISTS(val)) {
        P *= val;
      }
    }
  }
  nrrdDStore[ansType](ans, P);
}
Beispiel #3
0
void
_nrrdMeasureMax(void *ans, int ansType,
                const void *line, int lineType, size_t len, 
                double axmin, double axmax) {
  double val, M, (*lup)(const void*, size_t);
  size_t ii;

  AIR_UNUSED(axmin);
  AIR_UNUSED(axmax);
  lup = nrrdDLookup[lineType];
  if (nrrdTypeIsIntegral[lineType]) {
    M = lup(line, 0);
    for (ii=1; ii<len; ii++) {
      val = lup(line, ii);
      M = AIR_MAX(M, val);
    }
  } else {
    M = AIR_NAN;
    for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) {
      M = lup(line, ii);
    }
    for (; ii<len; ii++) {
      val = lup(line, ii);
      if (AIR_EXISTS(val)) {
        M = AIR_MAX(M, val);
      }
    }
  }
  nrrdDStore[ansType](ans, M);
}
Beispiel #4
0
void
_nrrdMeasureL2(void *ans, int ansType,
               const void *line, int lineType, size_t len, 
               double axmin, double axmax) {
  double val, S, (*lup)(const void*, size_t);
  size_t ii;

  AIR_UNUSED(axmin);
  AIR_UNUSED(axmax);
  lup = nrrdDLookup[lineType];
  if (nrrdTypeIsIntegral[lineType]) {
    S = 0.0;
    for (ii=0; ii<len; ii++) {
      val = lup(line, ii);
      S += val*val;
    }
  } else {
    S = AIR_NAN;
    for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) {
      S = lup(line, ii);
    }
    S *= S;
    for (; ii<len; ii++) {
      val = lup(line, ii);
      if (AIR_EXISTS(val)) {
        S += val*val;
      }
    }
  }
  nrrdDStore[ansType](ans, sqrt(S));
}
Beispiel #5
0
void
_nrrdMeasureLineFit(double *intc, double *slope,
                    const void *line, int lineType, size_t len, 
                    double axmin, double axmax) {
  double x, y, xi=0, yi=0, xiyi=0, xisq=0, det, (*lup)(const void*, size_t);
  size_t ii;

  lup = nrrdDLookup[lineType];
  if (!( AIR_EXISTS(axmin) && AIR_EXISTS(axmax) )) {
    axmin = 0;
    axmax = len-1;
  }
  if (1 == len) {
    *slope = 0;
    *intc = lup(line, 0);
  } else {
    for (ii=0; ii<len; ii++) {
      x = NRRD_NODE_POS(axmin, axmax, len, ii);
      y = lup(line, ii);
      xi += x;
      yi += y;
      xiyi += x*y;
      xisq += x*x;
    }
    det = len*xisq - xi*xi;
    *slope = (len*xiyi - xi*yi)/det;
    *intc = (-xi*xiyi + xisq*yi)/det;
  }
}
Beispiel #6
0
int
tenTripleConvert(Nrrd *nout, int dstType,
                 const Nrrd *nin, int srcType) {
  static const char me[]="tenTripleConvert";
  size_t II, NN;
  double (*ins)(void *, size_t, double), (*lup)(const void *, size_t);

  if (!( nout && nin )) {
    biffAddf(TEN, "%s: got NULL pointer", me);
    return 1;
  }
  if ( airEnumValCheck(tenTripleType, dstType) ||
       airEnumValCheck(tenTripleType, srcType) ) {
    biffAddf(TEN, "%s: got invalid %s dst (%d) or src (%d)", me,
             tenTripleType->name, dstType, srcType);
    return 1;
  }
  if (3 != nin->axis[0].size) {
    char stmp[AIR_STRLEN_SMALL];
    biffAddf(TEN, "%s: need axis[0].size 3, not %s", me,
             airSprintSize_t(stmp, nin->axis[0].size));
    return 1;
  }
  if (nrrdTypeBlock == nin->type) {
    biffAddf(TEN, "%s: input has non-scalar %s type",
             me, airEnumStr(nrrdType, nrrdTypeBlock));
    return 1;
  }

  if (nrrdCopy(nout, nin)) {
    biffMovef(TEN, NRRD, "%s: couldn't initialize output", me);
    return 1;
  }
  lup = nrrdDLookup[nin->type];
  ins = nrrdDInsert[nout->type];
  NN = nrrdElementNumber(nin)/3;
  for (II=0; II<NN; II++) {
    double src[3], dst[3];
    src[0] = lup(nin->data, 0 + 3*II);
    src[1] = lup(nin->data, 1 + 3*II);
    src[2] = lup(nin->data, 2 + 3*II);
    tenTripleConvertSingle_d(dst, dstType, src, srcType);
    ins(nout->data, 0 + 3*II, dst[0]);
    ins(nout->data, 1 + 3*II, dst[1]);
    ins(nout->data, 2 + 3*II, dst[2]);
  }

  return 0;
}
Beispiel #7
0
void
_nrrdMeasureHistoMean(void *ans, int ansType,
                      const void *line, int lineType, size_t len, 
                      double axmin, double axmax) {
  double count, hits, ansD, (*lup)(const void*, size_t);
  size_t ii;
  
  lup = nrrdDLookup[lineType];
  ansD = count = 0;
  for (ii=0; ii<len; ii++) {
    hits = lup(line, ii);
    hits = AIR_MAX(hits, 0);
    count += hits;
    ansD += hits*ii;
  }
  if (!count) {
    nrrdDStore[ansType](ans, AIR_NAN);
    return;
  }
  ansD /= count;
  if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) {
    ansD = NRRD_CELL_POS(axmin, axmax, len, ansD);
  }
  nrrdDStore[ansType](ans, ansD);
}
Beispiel #8
0
void
_nrrdMeasureHistoVariance(void *ans, int ansType,
                          const void *line, int lineType, size_t len, 
                          double axmin, double axmax) {
  double S, SS, count, hits, val, (*lup)(const void*, size_t);
  size_t ii;
  
  lup = nrrdDLookup[lineType];
  count = 0;
  SS = S = 0.0;
  /* we fix axmin, axmax now because GK is better safe than sorry */
  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
    axmin = -0.5;
    axmax = len-0.5;
  }
  for (ii=0; ii<len; ii++) {
    val = NRRD_CELL_POS(axmin, axmax, len, ii);
    hits = lup(line, ii);
    hits = AIR_MAX(hits, 0);
    count += hits;
    S += hits*val;
    SS += hits*val*val;
  }
  if (!count) {
    nrrdDStore[ansType](ans, AIR_NAN);
    return;
  }
  S /= count;
  SS /= count;
  nrrdDStore[ansType](ans, SS - S*S);
}
Beispiel #9
0
void
_nrrdMeasureHistoL2(void *ans, int ansType,
                    const void *line, int lineType, size_t len, 
                    double axmin, double axmax) {
  double l2, count, hits, val, (*lup)(const void*, size_t);
  size_t ii;
  
  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
    axmin = -0.5;
    axmax = len-0.5;
  }
  lup = nrrdDLookup[lineType];
  l2 = count = 0;
  for (ii=0; ii<len; ii++) {
    val = NRRD_CELL_POS(axmin, axmax, len, ii);
    hits = lup(line, ii);
    hits = AIR_MAX(hits, 0);
    count += hits;
    l2 += hits*val*val;
  }
  if (!count) {
    nrrdDStore[ansType](ans, AIR_NAN);
    return;
  }
  nrrdDStore[ansType](ans, l2);
}
Beispiel #10
0
void
_nrrdMeasureHistoMax(void *ans, int ansType,
                     const void *line, int lineType, size_t len, 
                     double axmin, double axmax) {
  double val, (*lup)(const void*, size_t);
  size_t ii;

  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
    axmin = -0.5;
    axmax = len-0.5;
  }
  lup = nrrdDLookup[lineType];
  /* we're using ii-1 as index to avoid wrap-around with size_t index */
  for (ii=len; ii>0; ii--) {
    if (lup(line, ii-1) > 0) {
      break;
    }
  }
  if (ii==0) {
    nrrdDStore[ansType](ans, AIR_NAN);
    return;
  }
  val = NRRD_CELL_POS(axmin, axmax, len, ii-1);
  nrrdDStore[ansType](ans, val);
}
Beispiel #11
0
void
_nrrdMeasureHistoMode(void *ans, int ansType,
                      const void *line, int lineType, size_t len, 
                      double axmin, double axmax) {
  double val, max, idxsum, ansD, (*lup)(const void*, size_t);
  size_t ii, idxcount;
  
  lup = nrrdDLookup[lineType];
  max = -DBL_MAX;
  for (ii=0; ii<len; ii++) {
    val = lup(line, ii);
    max = AIR_MAX(max, val);
  }
  if (-DBL_MAX == max) {
    nrrdDStore[ansType](ans, AIR_NAN);
    return;
  }
  /* else there was something in the histogram */
  /* we assume that there may be multiple bins which reach the maximum
     height, and we average all those indices.  This may well be
     bone-headed, and is subject to change.  19 July 03: with the
     addition of the final "type" argument to nrrdProject, the
     bone-headedness has been alleviated somewhat, since you can pass
     nrrdTypeFloat or nrrdTypeDouble to get an accurate answer */
  idxsum = 0;
  idxcount = 0;
  for (ii=0; ii<len; ii++) {
    val = lup(line, ii);
    if (val == max) {
      idxcount++;
      idxsum += ii;
    }
  }
  ansD = idxsum/idxcount;
  /*
  printf("idxsum = %g; idxcount = %d --> ansD = %g --> ",
         (float)idxsum, idxcount, ansD);
  */
  if (AIR_EXISTS(axmin) && AIR_EXISTS(axmax)) {
    ansD = NRRD_CELL_POS(axmin, axmax, len, ansD);
  }
  /*
  printf("%g\n", ansD);
  */
  nrrdDStore[ansType](ans, ansD);
}
Beispiel #12
0
void
_nrrdMeasureMean(void *ans, int ansType,
                 const void *line, int lineType, size_t len, 
                 double axmin, double axmax) {
  double val, S, M, (*lup)(const void*, size_t);
  size_t ii, count;

  AIR_UNUSED(axmin);
  AIR_UNUSED(axmax);
  lup = nrrdDLookup[lineType];
  if (nrrdTypeIsIntegral[lineType]) {
    S = 0.0;
    for (ii=0; ii<len; ii++) {
      S += lup(line, ii);
    }
    M = S/len;
  } else {
    S = AIR_NAN;
    for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) {
      S = lup(line, ii);
    }
    if (AIR_EXISTS(S)) {
      /* there was an existant value */
      count = 1;
      for (; ii<len; ii++) {
        val = lup(line, ii);
        if (AIR_EXISTS(val)) {
          count++;
          S += val;
        }
      }
      M = S/count;
    } else {
      /* there were NO existant values */
      M = AIR_NAN;
    }
  }
  nrrdDStore[ansType](ans, M);
}
Beispiel #13
0
void
_nrrdMeasureMedian(void *ans, int ansType,
                   const void *_line, int lineType, size_t len, 
                   double axmin, double axmax) {
  double M=0, (*lup)(const void*, size_t);
  size_t ii, mid;
  void *line;

  AIR_UNUSED(axmin);
  AIR_UNUSED(axmax);
  lup = nrrdDLookup[lineType];
  line = calloc(len, nrrdTypeSize[lineType]);
  if (line) {
    memcpy(line, _line, len*nrrdTypeSize[lineType]);
  
    /* yes, I know, this is not the fastest median.  I'll get to it ... */
    qsort(line, len, nrrdTypeSize[lineType], nrrdValCompare[lineType]);
    M = AIR_NAN;
    for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) {
      M = lup(line, ii);
    }
    
    if (AIR_EXISTS(M)) {
      /* i is index AFTER first existant value */
      ii--;
      len -= ii;
      mid = len/2;
      if (len % 2) {
        /* len is odd, there is a middle value, its at mid */
        M = lup(line, ii+mid);
      } else {
        /* len is even, two middle values are at mid-1 and mid */
        M = (lup(line, ii+mid-1) + lup(line, ii+mid))/2;
      }
    }
  }
  nrrdDStore[ansType](ans, M);
}
Beispiel #14
0
void
_nrrdMeasureVariance(void *ans, int ansType,
                     const void *line, int lineType, size_t len, 
                     double axmin, double axmax) {
  double val, S, SS, (*lup)(const void*, size_t);
  size_t ii, count;

  AIR_UNUSED(axmin);
  AIR_UNUSED(axmax);
  SS = S = 0.0;
  lup = nrrdDLookup[lineType];
  if (nrrdTypeIsIntegral[lineType]) {
    for (ii=0; ii<len; ii++) {
      val = lup(line, ii);
      S += val;
      SS += val*val;
    }
    S /= len;
    SS /= len;
  } else {
    count = 0;
    for (ii=0; ii<len; ii++) {
      val = lup(line, ii);
      if (AIR_EXISTS(val)) {
        count++;
        S += val;
        SS += val*val;
      }
    }
    if (count) {
      S /= count;
      SS /= count;
    } else {
      S = SS = AIR_NAN;
    }
  }
  nrrdDStore[ansType](ans, SS - S*S);
}
Beispiel #15
0
int
nrrdArithAffine(Nrrd *nout, double minIn,
                const Nrrd *nin, double maxIn,
                double minOut, double maxOut, int clamp) {
  static const char me[]="nrrdArithAffine";
  size_t I, N;
  double (*ins)(void *v, size_t I, double d),
    (*lup)(const void *v, size_t I), mmin, mmax;

  if ( !nout || nrrdCheck(nin) ) {
    biffAddf(NRRD, "%s: got NULL pointer or invalid input", me);
    return 1;
  }
  if (nout != nin) {
    if (nrrdCopy(nout, nin)) {
      biffAddf(NRRD, "%s: couldn't initialize output", me);
      return 1;
    }
  }
  N = nrrdElementNumber(nin);
  ins = nrrdDInsert[nout->type];
  lup = nrrdDLookup[nin->type];
  mmin = AIR_MIN(minOut, maxOut);
  mmax = AIR_MAX(minOut, maxOut);
  for (I=0; I<N; I++) {
    double val;
    val = lup(nin->data, I);
    val = AIR_AFFINE(minIn, val, maxIn, minOut, maxOut);
    if (clamp) {
      val = AIR_CLAMP(mmin, val, mmax);
    }
    ins(nout->data, I, val);
  }
  /* HEY: it would be much better if the ordering here was the same as in
     AIR_AFFINE, but that's not easy with the way the content functions are
     now set up */
  if (nrrdContentSet_va(nout, "affine", nin,
                        "%g,%g,%g,%g", minIn, maxIn,
                        minOut, maxOut)) {
    biffAddf(NRRD, "%s:", me);
  }
  return 0;
}
Beispiel #16
0
void
_nrrdMeasureHistoSum(void *ans, int ansType,
                     const void *line, int lineType, size_t len, 
                     double axmin, double axmax) {
  double sum, hits, val, (*lup)(const void*, size_t);
  size_t ii;
  
  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
    axmin = -0.5;
    axmax = len-0.5;
  }
  lup = nrrdDLookup[lineType];
  sum = 0;
  for (ii=0; ii<len; ii++) {
    val = NRRD_CELL_POS(axmin, axmax, len, ii);
    hits = lup(line, ii);
    hits = AIR_MAX(hits, 0);
    sum += hits*val;
  }
  nrrdDStore[ansType](ans, sum);
}
Beispiel #17
0
void
_nrrdMeasureLineError(void *ans, int ansType,
                      const void *line, int lineType, size_t len, 
                      double axmin, double axmax) {
  double x, y, slope, intc, tmp, err=0, (*lup)(const void*, size_t);
  size_t ii;
  
  _nrrdMeasureLineFit(&intc, &slope, line, lineType, len, axmin, axmax);

  if (!( AIR_EXISTS(axmin) && AIR_EXISTS(axmax) )) {
    axmin = 0;
    axmax = len-1;
  }
  lup = nrrdDLookup[lineType];
  for (ii=0; ii<len; ii++) {
    x = NRRD_NODE_POS(axmin, axmax, len, ii);
    y = lup(line, ii);
    tmp = slope*x + intc - y;
    err += tmp*tmp;
  }
  nrrdDStore[ansType](ans, err);
}
Beispiel #18
0
int
limnSplineNrrdEvaluate(Nrrd *nout, limnSpline *spline, Nrrd *nin) {
  char me[]="limnSplineNrrdEvaluate", err[BIFF_STRLEN];
  double tt, *out, (*lup)(const void *, size_t);
  int odim, infoSize;
  size_t I, M, size[NRRD_DIM_MAX+1];

  if (!(nout && spline && nin)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(LIMN, err); return 1;
  }
  if (limnSplineInfoScalar == spline->info) {
    nrrdAxisInfoGet_va(nin, nrrdAxisInfoSize, size);
    infoSize = 1;
    odim = nin->dim;
  } else {
    nrrdAxisInfoGet_va(nin, nrrdAxisInfoSize, size+1);
    infoSize = size[0] = limnSplineInfoSize[spline->info];
    odim = 1 + nin->dim;
  }
  if (nrrdMaybeAlloc_nva(nout, nrrdTypeDouble, odim, size)) {
    sprintf(err, "%s: output allocation failed", me);
    biffMove(LIMN, err, NRRD); return 1;
  }
  lup = nrrdDLookup[nin->type];
  out = (double*)(nout->data);
  M = nrrdElementNumber(nin);
  for (I=0; I<M; I++) {
    tt = lup(nin->data, I);
    limnSplineEvaluate(out, spline, tt);
    out += infoSize;
  }

  /* HEY: peripheral info copying? */

  return 0;
}
Beispiel #19
0
void
_nrrdMeasureHistoMin(void *ans, int ansType,
                     const void *line, int lineType, size_t len, 
                     double axmin, double axmax) {
  double val, (*lup)(const void*, size_t);
  size_t ii;

  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
    axmin = -0.5;
    axmax = len-0.5;
  }
  lup = nrrdDLookup[lineType];
  for (ii=0; ii<len; ii++) {
    if (lup(line, ii) > 0) {
      break;
    }
  }
  if (ii==len) {
    nrrdDStore[ansType](ans, AIR_NAN);
    return;
  }
  val = NRRD_CELL_POS(axmin, axmax, len, ii);
  nrrdDStore[ansType](ans, val);
}
/*
******** nrrdApply1DSubstitution
**
** A "subst" is a substitution table, i.e. a list of pairs that
** describes what values should be substituted with what (substitution
** rules).  So, nsubst must be a scalar 2xN array.  The output is a
** copy of the input with values substituted using this table.
**
** Unlike with lookup tables and maps (irregular and regular), we
** aren't at liberty to change the dimensionality of the data (can't
** substitute a grayscale with a color).  The ability to apply
** substitutions to non-scalar data will be in a different function.
** Also unlike lookup tables and maps, the output type is the SAME as
** the input type; the output does NOT inherit the type of the
** substitution
*/
int
nrrdApply1DSubstitution(Nrrd *nout, const Nrrd *nin, const Nrrd *_nsubst) {
  char me[]="nrrdApply1DSubstitution", err[BIFF_STRLEN];
  double (*lup)(const void *, size_t);
  double (*ins)(void *, size_t, double);
  Nrrd *nsubst;
  double val, *subst;
  size_t ii, num;
  int jj, asize0, asize1, changed;
  airArray *mop;

  if (!(nout && _nsubst && nin)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdTypeBlock == nin->type || nrrdTypeBlock == _nsubst->type) {
    sprintf(err, "%s: input or substitution type is %s, need scalar",
            me, airEnumStr(nrrdType, nrrdTypeBlock));
    biffAdd(NRRD, err); return 1;
  }
  if (2 != _nsubst->dim) {
    sprintf(err, "%s: substitution table has to be 2-D, not %d-D",
            me, _nsubst->dim);
    biffAdd(NRRD, err); return 1;
  }
  nrrdAxisInfoGet_va(_nsubst, nrrdAxisInfoSize, &asize0, &asize1);
  if (2 != asize0) {
    sprintf(err, "%s: substitution table has to be 2xN, not %dxN",
            me, asize0);
    biffAdd(NRRD, err); return 1;
  }
  if (nout != nin) {
    if (nrrdCopy(nout, nin)) {
      sprintf(err, "%s: couldn't initialize by copy to output", me);
      biffAdd(NRRD, err); return 1;
    }
  }

  mop = airMopNew();
  nsubst = nrrdNew();
  airMopAdd(mop, nsubst, (airMopper)nrrdNuke, airMopAlways);
  if (nrrdConvert(nsubst, _nsubst, nrrdTypeDouble)) {
    sprintf(err, "%s: couldn't create double copy of substitution table", me);
    biffAdd(NRRD, err); airMopError(mop); return 1;
  }
  lup = nrrdDLookup[nout->type];
  ins = nrrdDInsert[nout->type];
  subst = (double *)nsubst->data;
  num = nrrdElementNumber(nout);
  for (ii=0; ii<num; ii++) {
    val = lup(nout->data, ii);
    changed = AIR_FALSE;
    for (jj=0; jj<asize1; jj++) {
      if (val == subst[jj*2+0]) {
        val = subst[jj*2+1];
        changed = AIR_TRUE;
      }
    }
    if (changed) {
      ins(nout->data, ii, val);
    }
  }

  airMopOkay(mop);
  return 0;
}
Beispiel #21
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;
}
Beispiel #22
0
int
main(int argc, char *argv[]) {
  char *me, *outS;
  hestOpt *hopt;
  hestParm *hparm;
  airArray *mop;

  char *err, done[13];
  Nrrd *nin, *nblur, *nout;
  NrrdKernelSpec *kb0, *kb1, *k00, *k11, *k22;
  NrrdResampleContext *rsmc;
  int E;
  unsigned int sx, sy, sz, xi, yi, zi, ai;
  gageContext *ctx;
  gagePerVolume *pvl;
  const double *gvec, *gmag, *evec0, *eval;
  double (*ins)(void *v, size_t I, double d);
  double (*lup)(const void *v, size_t I);
  double dotmax, dotpow, gmmax, evalshift, gmpow, _dotmax, _gmmax, scl, clamp;

  me = argv[0];
  mop = airMopNew();
  hparm = hestParmNew();
  hopt = NULL;
  airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways);
  hestOptAdd(&hopt, "i", "nin", airTypeOther, 1, 1, &nin, NULL,
             "input volume", NULL, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "kb0", "kernel", airTypeOther, 1, 1, &kb0,
             "guass:3,5", "kernel to use for pre-process blurring",
             NULL, NULL, nrrdHestKernelSpec);
  hestOptAdd(&hopt, "kb1", "kernel", airTypeOther, 1, 1, &kb1,
             "cubic:1.5,1,0", "kernel to use for pos-process blurring",
             NULL, NULL, nrrdHestKernelSpec);
  hestOptAdd(&hopt, "k00", "kernel", airTypeOther, 1, 1, &k00,
             "cubic:1,0", "k00", NULL, NULL, nrrdHestKernelSpec);
  hestOptAdd(&hopt, "k11", "kernel", airTypeOther, 1, 1, &k11,
             "cubicd:1,0", "k00", NULL, NULL, nrrdHestKernelSpec);
  hestOptAdd(&hopt, "k22", "kernel", airTypeOther, 1, 1, &k22,
             "cubicdd:1,0", "k00", NULL, NULL, nrrdHestKernelSpec);
  hestOptAdd(&hopt, "dotmax", "dot", airTypeDouble, 1, 1, &dotmax, "5",
             "max effective value of dot(gvec, evec0)");
  hestOptAdd(&hopt, "evs", "shift", airTypeDouble, 1, 1, &evalshift, "0",
             "negative shift to avoid changing mostly flat regions");
  hestOptAdd(&hopt, "clamp", "clamp", airTypeDouble, 1, 1, &clamp, "nan",
             "if it exists, data value can't be forced below this");
  hestOptAdd(&hopt, "dotpow", "pow", airTypeDouble, 1, 1, &dotpow, "1",
             "exponent for dot");
  hestOptAdd(&hopt, "gmmax", "dot", airTypeDouble, 1, 1, &gmmax, "2",
             "max effective value of gmag");
  hestOptAdd(&hopt, "gmpow", "pow", airTypeDouble, 1, 1, &gmpow, "1",
             "exponent for gmag");
  hestOptAdd(&hopt, "scl", "scale", airTypeDouble, 1, 1, &scl, "0.1",
             "how much to scale hack to decrease input value");
  hestOptAdd(&hopt, "o", "filename", airTypeString, 1, 1, &outS, "-",
             "fixed volume output");
  hestParseOrDie(hopt, argc-1, argv+1, hparm,
                 me, vhInfo, AIR_TRUE, AIR_TRUE, AIR_TRUE);
  airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways);
  airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways);

  if (!( 3 == nin->dim
         && nrrdTypeBlock != nin->type )) {
    fprintf(stderr, "%s: need a 3-D scalar nrrd (not %u-D %s)", me,
            nin->dim, airEnumStr(nrrdType, nin->type));
    airMopError(mop); return 1;
  }

  nblur = nrrdNew();
  airMopAdd(mop, nblur, (airMopper)nrrdNuke, airMopAlways);
  if (nrrdCopy(nblur, nin)) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't allocate output:\n%s", me, err);
    airMopError(mop); return 1;
  }

  fprintf(stderr, "%s: pre-blurring ... ", me);
  fflush(stderr);
  rsmc = nrrdResampleContextNew();
  airMopAdd(mop, rsmc, (airMopper)nrrdResampleContextNix, airMopAlways);
  E = AIR_FALSE;
  if (!E) E |= nrrdResampleDefaultCenterSet(rsmc, nrrdCenterCell);
  if (!E) E |= nrrdResampleNrrdSet(rsmc, nin);
  for (ai=0; ai<3; ai++) {
    if (!E) E |= nrrdResampleKernelSet(rsmc, ai, kb0->kernel, kb0->parm);
    if (!E) E |= nrrdResampleSamplesSet(rsmc, ai, nin->axis[ai].size);
    if (!E) E |= nrrdResampleRangeFullSet(rsmc, ai);
  }
  if (!E) E |= nrrdResampleBoundarySet(rsmc, nrrdBoundaryBleed);
  if (!E) E |= nrrdResampleTypeOutSet(rsmc, nrrdTypeDefault);
  if (!E) E |= nrrdResampleRenormalizeSet(rsmc, AIR_TRUE);
  if (!E) E |= nrrdResampleExecute(rsmc, nblur);
  if (E) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: error resampling nrrd:\n%s", me, err);
    airMopError(mop);
    return 1;
  }
  fprintf(stderr, "done.\n");

  ctx = gageContextNew();
  airMopAdd(mop, ctx, (airMopper)gageContextNix, airMopAlways);
  gageParmSet(ctx, gageParmRenormalize, AIR_TRUE);
  gageParmSet(ctx, gageParmCheckIntegrals, AIR_TRUE);
  E = 0;
  if (!E) E |= !(pvl = gagePerVolumeNew(ctx, nblur, gageKindScl));
  if (!E) E |= gagePerVolumeAttach(ctx, pvl);
  if (!E) E |= gageKernelSet(ctx, gageKernel00, k00->kernel, k00->parm);
  if (!E) E |= gageKernelSet(ctx, gageKernel11, k11->kernel, k11->parm);
  if (!E) E |= gageKernelSet(ctx, gageKernel22, k22->kernel, k22->parm);
  if (!E) E |= gageQueryItemOn(ctx, pvl, gageSclGradVec);
  if (!E) E |= gageQueryItemOn(ctx, pvl, gageSclGradMag);
  if (!E) E |= gageQueryItemOn(ctx, pvl, gageSclHessEvec0);
  if (!E) E |= gageQueryItemOn(ctx, pvl, gageSclHessEval);
  if (!E) E |= gageUpdate(ctx);
  if (E) {
    airMopAdd(mop, err = biffGetDone(GAGE), airFree, airMopAlways);
    fprintf(stderr, "%s: trouble:\n%s\n", me, err);
    airMopError(mop); return 1;
  }
  gvec = gageAnswerPointer(ctx, pvl, gageSclGradVec);
  gmag = gageAnswerPointer(ctx, pvl, gageSclGradMag);
  evec0 = gageAnswerPointer(ctx, pvl, gageSclHessEvec0);
  eval = gageAnswerPointer(ctx, pvl, gageSclHessEval);

  nout = nrrdNew();
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);
  if (nrrdCopy(nout, nin)) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't allocate output:\n%s", me, err);
    airMopError(mop); return 1;
  }

  if (!(nout->type == nin->type && nblur->type == nin->type)) {
    fprintf(stderr, "%s: whoa, types (%s %s %s) not all equal\n", me,
            airEnumStr(nrrdType, nin->type),
            airEnumStr(nrrdType, nblur->type),
            airEnumStr(nrrdType, nout->type));
  }
  ins = nrrdDInsert[nout->type];
  lup = nrrdDLookup[nout->type];
  sx = nin->axis[0].size;
  sy = nin->axis[1].size;
  sz = nin->axis[2].size;

  gageProbe(ctx, 0, 0, 0);
  _dotmax = ELL_3V_DOT(gvec, evec0);
  _gmmax = *gmag;

  fprintf(stderr, "%s: hacking       ", me);
  fflush(stderr);
  for (zi=0; zi<sz; zi++) {
    fprintf(stderr, "%s", airDoneStr(0, zi, sz-1, done));
    fflush(stderr);
    for (yi=0; yi<sy; yi++) {
      for (xi=0; xi<sx; xi++) {
        size_t si;
        double dot, evl, gm, shift, in, out, mode;

        gageProbe(ctx, xi, yi, zi);
        si = xi + sx*(yi + sy*zi);

        dot = ELL_3V_DOT(gvec, evec0);
        _dotmax = AIR_MAX(_dotmax, dot);
        dot = AIR_ABS(dot);
        dot = 1 - AIR_MIN(dot, dotmax)/dotmax;
        dot = pow(dot, dotpow);

        evl = AIR_MAX(0, eval[0] - evalshift);
        mode = airMode3_d(eval);
        evl *= AIR_AFFINE(-1, mode, 1, 0, 1);

        _gmmax = AIR_MAX(_gmmax, *gmag);
        gm = 1 - AIR_MIN(*gmag, gmmax)/gmmax;
        gm = pow(gm, gmpow);

        shift = scl*gm*evl*dot;
        if (AIR_EXISTS(clamp)) {
          in = lup(nin->data, si);
          out = in - shift;
          out = AIR_MAX(out, clamp);
          shift = AIR_MAX(0, in - out);
        }

        ins(nout->data, si, shift);
      }
    }
  }
  fprintf(stderr, "\n");
  fprintf(stderr, "%s: max dot seen: %g\n", me, _dotmax);
  fprintf(stderr, "%s: max gm seen: %g\n", me, _gmmax);

  fprintf(stderr, "%s: post-blurring ... ", me);
  fflush(stderr);
  E = AIR_FALSE;
  if (!E) E |= nrrdResampleNrrdSet(rsmc, nout);
  for (ai=0; ai<3; ai++) {
    if (!E) E |= nrrdResampleKernelSet(rsmc, ai, kb1->kernel, kb1->parm);
    if (!E) E |= nrrdResampleSamplesSet(rsmc, ai, nout->axis[ai].size);
    if (!E) E |= nrrdResampleRangeFullSet(rsmc, ai);
  }
  if (!E) E |= nrrdResampleExecute(rsmc, nblur);
  if (E) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: error resampling nrrd:\n%s", me, err);
    airMopError(mop);
    return 1;
  }
  fprintf(stderr, "done.\n");

  for (zi=0; zi<sz; zi++) {
    for (yi=0; yi<sy; yi++) {
      for (xi=0; xi<sx; xi++) {
        size_t si;
        double in, shift;

        si = xi + sx*(yi + sy*zi);
        in = lup(nin->data, si);
        shift = lup(nblur->data, si);
        ins(nout->data, si, in - shift);
      }
    }
  }

  if (nrrdSave(outS, nout, NULL)) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't save output:\n%s", me, err);
    airMopError(mop); return 1;
  }

  airMopOkay(mop);
  exit(0);
}
Beispiel #23
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;
}
Beispiel #24
0
int
coilStart(coilContext *cctx) {
  char me[]="coilStart", err[BIFF_STRLEN];
  int valIdx, valLen;
  coil_t (*lup)(const void*, size_t), *val;
  unsigned tidx, elIdx;

  if (!cctx) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(COIL, err); return 1;
  }
  cctx->task = (coilTask **)calloc(cctx->numThreads, sizeof(coilTask *));
  if (!(cctx->task)) {
    sprintf(err, "%s: couldn't allocate array of tasks", me);
    biffAdd(COIL, err); return 1;
  }
  
  /* we create tasks for ALL threads, including me, thread 0 */
  cctx->task[0] = NULL;
  for (tidx=0; tidx<cctx->numThreads; tidx++) {
    cctx->task[tidx] = _coilTaskNew(cctx, tidx);
    if (!(cctx->task[tidx])) {
      sprintf(err, "%s: couldn't allocate task %d", me, tidx);
      biffAdd(COIL, err); return 1;
    }
  }
  
  cctx->finished = AIR_FALSE;
  if (cctx->numThreads > 1) {
    cctx->nextSliceMutex = airThreadMutexNew();
    cctx->filterBarrier = airThreadBarrierNew(cctx->numThreads);
    cctx->updateBarrier = airThreadBarrierNew(cctx->numThreads);
  }

  /* initialize the values in cctx->nvol */
  val = (coil_t*)(cctx->nvol->data);
  valLen = cctx->kind->valLen;
#if COIL_TYPE_FLOAT
  lup = nrrdFLookup[cctx->nin->type];
#else
  lup = nrrdDLookup[cctx->nin->type];
#endif
  for (elIdx=0; elIdx<cctx->size[0]*cctx->size[1]*cctx->size[2]; elIdx++) {
    for (valIdx=0; valIdx<valLen; valIdx++) {
      val[valIdx + 0*valLen] = lup(cctx->nin->data, valIdx + valLen*elIdx);
      val[valIdx + 1*valLen] = 0;
    }
    val += 2*valLen;
  }
  
  /* start threads 1 and up running; they'll all hit filterBarrier  */
  if (cctx->numThreads > 1) {
    for (tidx=1; tidx<cctx->numThreads; tidx++) {
      if (cctx->verbose > 1) {
        fprintf(stderr, "%s: spawning thread %d\n", me, tidx);
      }
      airThreadStart(cctx->task[tidx]->thread, _coilWorker,
                     (void *)(cctx->task[tidx]));
    }
  }

  /* set things as though we've just finished an update phase */
  cctx->nextSlice = cctx->size[2];
  cctx->todoFilter = AIR_TRUE;
  cctx->todoUpdate = AIR_FALSE;
  
  return 0;
}
int
main(int argc, char *argv[]) {
  char *me, *outS;
  hestOpt *hopt;
  hestParm *hparm;
  airArray *mop;

  char *err;
  Nrrd *nin, *nhist;
  double vmin, vmax, rmax, val, cent[2], rad;
  int bins[2], sx, sy, xi, yi, ridx, hidx, rbins, hbins;
  NrrdRange *range;
  double (*lup)(const void *v, size_t I), *hist;
  
  me = argv[0];
  mop = airMopNew();
  hparm = hestParmNew();
  hopt = NULL;
  airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways);
  hestOptAdd(&hopt, "i", "nin", airTypeOther, 1, 1, &nin, NULL,
             "input image", NULL, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "b", "rbins hbins", airTypeInt, 2, 2, bins, NULL,
             "# of histogram bins: radial and value");
  hestOptAdd(&hopt, "min", "value", airTypeDouble, 1, 1, &vmin, "nan",
             "Value at low end of histogram. Defaults to lowest value "
             "found in input nrrd.");
  hestOptAdd(&hopt, "max", "value", airTypeDouble, 1, 1, &vmax, "nan",
             "Value at high end of histogram. Defaults to highest value "
             "found in input nrrd.");
  hestOptAdd(&hopt, "rmax", "max radius", airTypeDouble, 1, 1, &rmax, "nan",
             "largest radius to include in histogram");
  hestOptAdd(&hopt, "c", "center x, y", airTypeDouble, 2, 2, cent, NULL,
             "The center point around which to build radial histogram");
  hestOptAdd(&hopt, "o", "filename", airTypeString, 1, 1, &outS, "-",
             "file to write histogram to");
  hestParseOrDie(hopt, argc-1, argv+1, hparm,
                 me, histradInfo, AIR_TRUE, AIR_TRUE, AIR_TRUE);
  airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways);
  airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways);

  if (2 != nin->dim) {
    fprintf(stderr, "%s: need 2-D input (not %d-D)\n", me, nin->dim);
    airMopError(mop); return 1;
  }

  rbins = bins[0];
  hbins = bins[1];
  nhist = nrrdNew();
  airMopAdd(mop, nhist, (airMopper)nrrdNuke, airMopAlways);
  if (nrrdMaybeAlloc_va(nhist, nrrdTypeDouble, 2,
                        AIR_CAST(size_t, rbins),
                        AIR_CAST(size_t, hbins))) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't allocate histogram:\n%s", me, err);
    airMopError(mop); return 1;
  }

  if (!( AIR_EXISTS(vmin) && AIR_EXISTS(vmax) )) {
    range = nrrdRangeNewSet(nin, nrrdStateBlind8BitRange);
    airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways);
    vmin = AIR_EXISTS(vmin) ? vmin : range->min;
    vmax = AIR_EXISTS(vmax) ? vmax : range->max;
  }

#define DIST(x0, y0, x1, y1) (sqrt((x0-x1)*(x0-x1) + (y0-y1)*(y0-y1)))

  sx = nin->axis[0].size;
  sy = nin->axis[1].size;
  if (!AIR_EXISTS(rmax)) {
    rmax = 0;
    rmax = AIR_MAX(rmax, DIST(cent[0], cent[1], 0, 0));
    rmax = AIR_MAX(rmax, DIST(cent[0], cent[1], sx-1, 0));
    rmax = AIR_MAX(rmax, DIST(cent[0], cent[1], 0, sy-1));
    rmax = AIR_MAX(rmax, DIST(cent[0], cent[1], sx-1, sy-1));
  }
  
  lup = nrrdDLookup[nin->type];
  hist = (double*)(nhist->data);
  for (xi=0; xi<sx; xi++) {
    for (yi=0; yi<sy; yi++) {
      rad = DIST(cent[0], cent[1], xi, yi);
      if (!AIR_IN_OP(0, rad, rmax)) {
        continue;
      }
      val = lup(nin->data, xi + sx*yi);
      if (!AIR_IN_OP(vmin, val, vmax)) {
        continue;
      }
      ridx = airIndex(0, rad, rmax, rbins);
      hidx = airIndex(vmin, val, vmax, hbins);
      hist[ridx + rbins*hidx] += 1;
    }
  }
  
  nhist->axis[0].min = 0;
  nhist->axis[0].max = rmax;
  nhist->axis[1].min = vmin;
  nhist->axis[1].max = vmax;
  if (nrrdSave(outS, nhist, NULL)) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't save output:\n%s", me, err);
    airMopError(mop); return 1;
  }

  airMopOkay(mop);
  exit(0);
}
Beispiel #26
0
/*
******** nrrdHisto()
**
** makes a 1D histogram of a given size and type
**
** pre-NrrdRange policy:
** this looks at nin->min and nin->max to see if they are both non-NaN.
** If so, it uses these as the range of the histogram, otherwise it
** finds the min and max present in the volume.  If nin->min and nin->max
** are being used as the histogram range, then values which fall outside
** this are ignored (they don't contribute to the histogram).
**
** post-NrrdRange policy:
*/
int
nrrdHisto(Nrrd *nout, const Nrrd *nin, const NrrdRange *_range,
          const Nrrd *nwght, size_t bins, int type) {
  static const char me[]="nrrdHisto", func[]="histo";
  size_t I, num, idx;
  airArray *mop;
  NrrdRange *range;
  double min, max, eps, val, count, incr, (*lup)(const void *v, size_t I);

  if (!(nin && nout)) {
    /* _range and nwght can be NULL */
    biffAddf(NRRD, "%s: got NULL pointer", me);
    return 1;
  }
  if (nout == nin) {
    biffAddf(NRRD, "%s: nout==nin disallowed", me);
    return 1;
  }
  if (!(bins > 0)) {
    biffAddf(NRRD, "%s: bins value (" _AIR_SIZE_T_CNV ") invalid", me, bins);
    return 1;
  }
  if (airEnumValCheck(nrrdType, type) || nrrdTypeBlock == type) {
    biffAddf(NRRD, "%s: invalid nrrd type %d", me, type);
    return 1;
  }
  if (nwght) {
    if (nout==nwght) {
      biffAddf(NRRD, "%s: nout==nwght disallowed", me);
      return 1;
    }
    if (nrrdTypeBlock == nwght->type) {
      biffAddf(NRRD, "%s: nwght type %s invalid", me,
               airEnumStr(nrrdType, nrrdTypeBlock));
      return 1;
    }
    if (!nrrdSameSize(nin, nwght, AIR_TRUE)) {
      biffAddf(NRRD, "%s: nwght size mismatch with nin", me);
      return 1;
    }
    lup = nrrdDLookup[nwght->type];
  } else {
    lup = NULL;
  }

  if (nrrdMaybeAlloc_va(nout, type, 1, bins)) {
    biffAddf(NRRD, "%s: failed to alloc histo array (len " _AIR_SIZE_T_CNV
             ")", me, bins);
    return 1;
  }
  mop = airMopNew();
  /* nout->axis[0].size set */
  nout->axis[0].spacing = AIR_NAN;
  nout->axis[0].thickness = AIR_NAN;
  if (nout && AIR_EXISTS(nout->axis[0].min) && AIR_EXISTS(nout->axis[0].max)) {
    /* HEY: total hack to externally nail down min and max of histogram:
       use the min and max already set on axis[0] */
    /* HEY: shouldn't this blatent hack be further restricted by also 
       checking the existence of range->min and range->max ? */
    min = nout->axis[0].min;
    max = nout->axis[0].max;
  } else {
    if (_range) {
      range = nrrdRangeCopy(_range);
      nrrdRangeSafeSet(range, nin, nrrdBlind8BitRangeState);
    } else {
      range = nrrdRangeNewSet(nin, nrrdBlind8BitRangeState);
    }
    airMopAdd(mop, range, (airMopper)nrrdRangeNix, airMopAlways);
    min = range->min;
    max = range->max;
    nout->axis[0].min = min;
    nout->axis[0].max = max;
  }
  eps = (min == max ? 1.0 : 0.0);
  nout->axis[0].center = nrrdCenterCell;
  /* nout->axis[0].label set below */
  
  /* make histogram */
  num = nrrdElementNumber(nin);
  for (I=0; I<num; I++) {
    val = nrrdDLookup[nin->type](nin->data, I);
    if (AIR_EXISTS(val)) {
      if (val < min || val > max+eps) {
        /* value is outside range; ignore it */
        continue;
      }
      if (AIR_IN_CL(min, val, max)) {
        idx = airIndex(min, val, max+eps, AIR_CAST(unsigned int, bins));
        /*
        printf("!%s: %d: index(%g, %g, %g, %d) = %d\n", 
               me, (int)I, min, val, max, bins, idx);
        */
        /* count is a double in order to simplify clamping the
           hit values to the representable range for nout->type */
        count = nrrdDLookup[nout->type](nout->data, idx);
        incr = nwght ? lup(nwght->data, I) : 1;
        count = nrrdDClamp[nout->type](count + incr);
        nrrdDInsert[nout->type](nout->data, idx, count);
      }
    }
  }

  if (nrrdContentSet_va(nout, func, nin, "%d", bins)) {
    biffAddf(NRRD, "%s:", me);
    airMopError(mop); return 1;
  }
  nout->axis[0].label = (char *)airFree(nout->axis[0].label);
  nout->axis[0].label = (char *)airStrdup(nout->content);
  if (!nrrdStateKindNoop) {
    nout->axis[0].kind = nrrdKindDomain;
  }

  airMopOkay(mop);
  return 0;
}
Beispiel #27
0
void
_nrrdMeasureSkew(void *ans, int ansType,
                 const void *line, int lineType, size_t len, 
                 double axmin, double axmax) {
  double val, diff, mean, vari, third, (*lup)(const void*, size_t);
  size_t ii, count;
  
  AIR_UNUSED(axmin);
  AIR_UNUSED(axmax);
  /* we don't try to do any one-pass short-cuts */

  /* find the mean */
  mean = 0;
  lup = nrrdDLookup[lineType];
  if (nrrdTypeIsIntegral[lineType]) {
    count = len;
    for (ii=0; ii<len; ii++) {
      val = lup(line, ii);
      mean += val;
    }
  } else {
    count = 0;
    for (ii=0; ii<len; ii++) {
      val = lup(line, ii);
      if (AIR_EXISTS(val)) {
        count++;
        mean += val;
      }
    }
  }
  if (0 == count) {
    nrrdDStore[ansType](ans, AIR_NAN);
    return;
  }
  mean /= count;

  /* find the variance and third moment */
  vari = third = 0;
  if (nrrdTypeIsIntegral[lineType]) {
    for (ii=0; ii<len; ii++) {
      diff = lup(line, ii) - mean;
      vari += diff*diff;
      third += diff*diff*diff;
    }
  } else {
    for (ii=0; ii<len; ii++) {
      val = lup(line, ii);
      if (AIR_EXISTS(val)) {
        diff = val - mean;
        vari += diff*diff;
        third += diff*diff*diff;
      }
    }
  }
  if (0 == vari) {
    /* why not have an existant value ... */
    nrrdDStore[ansType](ans, 0);
    return;
  }
  vari /= count;
  third /= count;

  nrrdDStore[ansType](ans, third/(vari*sqrt(vari)));
}
Beispiel #28
0
int
gageDeconvolveSeparable(Nrrd *nout, const Nrrd *nin,
                        const gageKind *kind,
                        const NrrdKernelSpec *ksp,
                        int typeOut) {
  static const char me[]="gageDeconvolveSeparable";
  double *line, (*lup)(const void *, size_t),
    (*ins)(void *, size_t, double);
  airArray *mop;
  size_t lineLen, sx, sy, sz, idx, ii, jj;
  unsigned int vi, valLen;

  if (!(nout && nin && kind && ksp)) {
    biffAddf(GAGE, "%s: got NULL pointer", me);
    return 1;
  }
  if (!(nrrdTypeDefault == typeOut
        || !airEnumValCheck(nrrdType, typeOut))) {
    biffAddf(GAGE, "%s: typeOut %d not valid", me, typeOut);
    return 1;
  }
  if (!gageDeconvolveSeparableKnown(ksp)) {
    biffAddf(GAGE, "%s: separable deconv not known for %s kernel",
             me, ksp->kernel->name);
    return 1;
  }
  if (gageKindVolumeCheck(kind, nin)) {
    biffAddf(GAGE, "%s: given volume doesn't fit %s kind",
             me, kind->name);
    return 1;
  }
  if (nrrdTypeDefault == typeOut
      ? nrrdCopy(nout, nin)
      : nrrdConvert(nout, nin, typeOut)) {
    biffMovef(GAGE, NRRD, "%s: problem allocating output", me);
    return 1;
  }
  if (deconvTrivial(ksp)) {
    /* if there's no real work for the deconvolution, then by
       copying the values we're already done; bye */
    return 0;
  }

  valLen = kind->valLen;
  sx = nin->axis[kind->baseDim + 0].size;
  sy = nin->axis[kind->baseDim + 1].size;
  sz = nin->axis[kind->baseDim + 2].size;
  lineLen = sx;
  lineLen = AIR_MAX(lineLen, sy);
  lineLen = AIR_MAX(lineLen, sz);
  lup = nrrdDLookup[nin->type];
  ins = nrrdDInsert[nout->type];

  mop = airMopNew();
  line = AIR_CALLOC(lineLen*valLen, double);
  airMopAdd(mop, line, airFree, airMopAlways);

  /* process along X scanlines */
  for (jj=0; jj<sy*sz; jj++) {
    /* xi = 0, yi = jj%sy, zi = jj/sy
       ==> xi + sx*(yi + sy*zi)
       == 0 + sx*(jj%sy + sy*(jj/sy)) == 0 + sx*jj */
    idx = 0 + valLen*(0 + sx*jj);
    for (ii=0; ii<sx; ii++) {
      for (vi=0; vi<valLen; vi++) {
        line[ii + sx*vi] = lup(nin->data, idx + vi + valLen*ii);
      }
    }
    for (vi=0; vi<valLen; vi++) {
      deconvLine(line + sx*vi, sx, ksp);
    }
    for (ii=0; ii<sx; ii++) {
      for (vi=0; vi<valLen; vi++) {
        ins(nout->data, idx + vi + valLen*ii, line[ii + sx*vi]);
      }
    }
  }

  /* process along Y scanlines */
  for (jj=0; jj<sx*sz; jj++) {
    /* xi = jj%sx, yi = 0, zi = jj/sx
       ==> xi + sx*(yi + sy*zi)
       == jj%sx + sx*(0 + sy*jj/sx) */
    idx = 0 + valLen*((jj%sx) + sx*(0 + sy*(jj/sx)));
    for (ii=0; ii<sy; ii++) {
      for (vi=0; vi<valLen; vi++) {
        line[ii + sy*vi] = lup(nin->data, idx + vi + valLen*sx*ii);
      }
    }
    for (vi=0; vi<valLen; vi++) {
      deconvLine(line + sy*vi, sy, ksp);
    }
    for (ii=0; ii<sx; ii++) {
      for (vi=0; vi<valLen; vi++) {
        ins(nout->data, idx + vi + valLen*sx*ii, line[ii + sy*vi]);
      }
    }
  }

  /* process along Z scanlines */
  for (jj=0; jj<sx*sy; jj++) {
    /* xi = jj%sx, yi = jj/sx, zi = 0
       ==> xi + sx*(yi + sy*zi)
       == jj%sx + sx*(jj/sx + sy*0)
       == jj%sx + sx*(jj/sx) == jj */
    idx = 0 + valLen*jj;
    for (ii=0; ii<sz; ii++) {
      for (vi=0; vi<valLen; vi++) {
        line[ii + sz*vi] = lup(nin->data, idx + vi + valLen*sx*sy*ii);
      }
    }
    for (vi=0; vi<valLen; vi++) {
      deconvLine(line + sz*vi, sz, ksp);
    }
    for (ii=0; ii<sx; ii++) {
      for (vi=0; vi<valLen; vi++) {
        ins(nout->data, idx + vi + valLen*sx*sy*ii, line[ii + sz*vi]);
      }
    }
  }

  airMopOkay(mop);
  return 0;
}
Beispiel #29
0
int
gageDeconvolve(Nrrd *_nout, double *lastDiffP,
               const Nrrd *nin, const gageKind *kind,
               const NrrdKernelSpec *ksp, int typeOut,
               unsigned int maxIter, int saveAnyway,
               double step, double epsilon, int verbose) {
  static const char me[]="gageDeconvolve";
  gageContext *ctx[2];
  gagePerVolume *pvl[2];
  double *out[2], *val[2], alpha, (*lup)(const void *, size_t), meandiff=0;
  const double *ans[2];
  Nrrd *nout[2];
  airArray *mop;
  unsigned int sx, sy, sz, xi, yi, zi, anslen, thiz=0, last, inIdx, iter;
  int E, valItem;

  if (!(_nout && lastDiffP && nin && kind && ksp)) {
    biffAddf(GAGE, "%s: got NULL pointer", me);
    return 1;
  }
  if (!(nrrdTypeDefault == typeOut
        || !airEnumValCheck(nrrdType, typeOut))) {
    biffAddf(GAGE, "%s: typeOut %d not valid", me, typeOut);
    return 1;
  }
  if (!( maxIter >= 1 )) {
    biffAddf(GAGE, "%s: need maxIter >= 1 (not %u)", me, maxIter);
    return 1;
  }
  if (!( epsilon >= 0 )) {
    biffAddf(GAGE, "%s: need epsilon >= 0.0 (not %g)", me, epsilon);
    return 1;
  }

  /* this once changed from 0 to 1, but is unlikely to change again */
  valItem = 1;

  mop = airMopNew();
  for (iter=0; iter<2; iter++) {
    nout[iter] = nrrdNew();
    airMopAdd(mop, nout[iter], (airMopper)nrrdNuke, airMopAlways);
    if (nrrdConvert(nout[iter], nin, nrrdTypeDouble)) {
      biffMovef(GAGE, NRRD, "%s: couldn't allocate working buffer %u",
                me, iter);
      airMopError(mop); return 1;
    }
    ctx[iter] = gageContextNew();
    airMopAdd(mop, ctx[iter], (airMopper)gageContextNix, airMopAlways);
    E = 0;
    if (!E) E |= !(pvl[iter] = gagePerVolumeNew(ctx[iter], nout[iter], kind));
    if (!E) E |= gagePerVolumeAttach(ctx[iter], pvl[iter]);
    if (!E) E |= gageKernelSet(ctx[iter], gageKernel00,
                               ksp->kernel, ksp->parm);
    if (!E) E |= gageQueryItemOn(ctx[iter], pvl[iter], valItem);
    if (!E) E |= gageUpdate(ctx[iter]);
    if (E) {
      biffAddf(GAGE, "%s: trouble setting up context %u", me, iter);
      airMopError(mop); return 1;
    }
    out[iter] = AIR_CAST(double*, nout[iter]->data);
    ans[iter] = gageAnswerPointer(ctx[iter], pvl[iter], valItem);
  }

  anslen = kind->table[valItem].answerLength;
  lup = nrrdDLookup[nin->type];

  alpha = ksp->kernel->eval1_d(0.0, ksp->parm);
  sx = ctx[0]->shape->size[0];
  sy = ctx[0]->shape->size[1];
  sz = ctx[0]->shape->size[2];

  for (iter=0; iter<maxIter; iter++) {
    thiz = (iter+1) % 2;
    last = (iter+0) % 2;
    val[thiz] = out[thiz];
    val[last] = out[last];
    inIdx = 0;
    meandiff = 0;
    for (zi=0; zi<sz; zi++) {
      for (yi=0; yi<sy; yi++) {
        for (xi=0; xi<sx; xi++) {
          unsigned int ai;
          double in, aa;
          gageProbe(ctx[last], xi, yi, zi);
          for (ai=0; ai<anslen; ai++) {
            in = lup(nin->data, ai + anslen*inIdx);
            aa = ans[last][ai];
            val[thiz][ai] = val[last][ai] + step*(in - aa)/alpha;
            meandiff += 2*(in - aa)*(in - aa)/(DBL_EPSILON + in*in + aa*aa);
          }
          val[thiz] += anslen;
          val[last] += anslen;
          ++inIdx;
        }
      }
    }
    meandiff /= sx*sy*sz;
    if (verbose) {
      fprintf(stderr, "%s: iter %u meandiff = %g\n", me, iter, meandiff);
    }
    if (meandiff < epsilon) {
      /* we have indeed converged while iter < maxIter */
      break;
    }
  }
  if (iter == maxIter) {
    if (!saveAnyway) {
      biffAddf(GAGE, "%s: failed to converge in %u iterations, meandiff = %g",
               me, maxIter, meandiff);
      airMopError(mop); return 1;
    } else {
      if (verbose) {
        fprintf(stderr, "%s: at maxIter %u; err %g still > thresh %g\n", me,
                iter, meandiff, epsilon);
      }
    }
  }

  if (nrrdClampConvert(_nout, nout[thiz], (nrrdTypeDefault == typeOut
                                           ? nin->type
                                           : typeOut))) {
    biffAddf(GAGE, "%s: couldn't create output", me);
    airMopError(mop); return 1;
  }
  *lastDiffP = meandiff;

  airMopOkay(mop);
  return 0;
}
Beispiel #30
0
int
main(int argc, char *argv[]) {
  char *me, *err;
  hestOpt *hopt=NULL;
  airArray *mop;

  char *outTenS, *outCovarS, *outRmvS;
  int seed, E;
  unsigned int NN;
  Nrrd *_ninTen, *ninTen, *ngrad, *_ninB0, *ninB0, *nmask,
    *noutCovar, *noutTen, *noutRmv, *ntbuff;
  float sigma, bval;
  size_t sizeX, sizeY, sizeZ;
  tenEstimateContext *tec;
  int axmap[NRRD_DIM_MAX], randrot;

  mop = airMopNew();
  me = argv[0];
  hestOptAdd(&hopt, "i", "ten", airTypeOther, 1, 1, &_ninTen, NULL,
             "input tensor volume", NULL, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "n", "#sim", airTypeUInt, 1, 1, &NN, "100",
             "number of simulations to run");
  hestOptAdd(&hopt, "seed", "seed", airTypeInt, 1, 1, &seed, "42",
             "seed value for RNG which creates noise");
  hestOptAdd(&hopt, "r", "reference field", airTypeOther, 1, 1, &_ninB0, NULL,
             "reference anatomical scan, with no diffusion weighting",
             NULL, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "rr", NULL, airTypeOther, 0, 0, &randrot, NULL,
             "randomize gradient set orientation");
  hestOptAdd(&hopt, "g", "grad list", airTypeOther, 1, 1, &ngrad, "",
             "gradient list, one row per diffusion-weighted image", 
             NULL, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "b", "b", airTypeFloat, 1, 1, &bval, "1000",
             "b value for simulated scan");
  hestOptAdd(&hopt, "sigma", "sigma", airTypeFloat, 1, 1, &sigma, "0.0",
             "Rician noise parameter");
  hestOptAdd(&hopt, "ot", "filename", airTypeString, 1, 1, &outTenS, 
             "tout.nrrd", "file to write output tensor nrrd to");
  hestOptAdd(&hopt, "oc", "filename", airTypeString, 1, 1, &outCovarS, 
             "cout.nrrd", "file to write output covariance nrrd to");
  hestOptAdd(&hopt, "or", "filename", airTypeString, 1, 1, &outRmvS, 
             "rout.nrrd", "file to write output R_i means, variances to");
  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);

  if (tenGradientCheck(ngrad, nrrdTypeDefault, 7)) {
    airMopAdd(mop, err = biffGetDone(TEN), airFree, airMopAlways);
    fprintf(stderr, "%s: problem with gradient list:\n%s\n", me, err);
    airMopError(mop); 
    return 1;
  }
  if (tenTensorCheck(_ninTen, nrrdTypeDefault, AIR_TRUE, AIR_TRUE)) {
    airMopAdd(mop, err = biffGetDone(TEN), airFree, airMopAlways);
    fprintf(stderr, "%s: didn't like input:\n%s\n", me, err);
    airMopError(mop); 
    return 1;
  }
  sizeX = _ninTen->axis[1].size;
  sizeY = _ninTen->axis[2].size;
  sizeZ = _ninTen->axis[3].size;
  if (!(3 == _ninB0->dim &&
        sizeX == _ninB0->axis[0].size &&
        sizeY == _ninB0->axis[1].size &&
        sizeZ == _ninB0->axis[2].size)) {
    fprintf(stderr, "%s: given B0 (%u-D) volume not 3-D " _AIR_SIZE_T_CNV
            "x" _AIR_SIZE_T_CNV "x" _AIR_SIZE_T_CNV, me, _ninB0->dim,
            sizeX, sizeY, sizeZ);
    airMopError(mop); 
    return 1;
  }

  ninTen = nrrdNew();
  airMopAdd(mop, ninTen, (airMopper)nrrdNuke, airMopOnError);
  nmask = nrrdNew();
  airMopAdd(mop, nmask, (airMopper)nrrdNuke, airMopOnError);
  ninB0 = nrrdNew();
  airMopAdd(mop, ninB0, (airMopper)nrrdNuke, airMopOnError);
  noutCovar = nrrdNew();
  airMopAdd(mop, noutCovar, (airMopper)nrrdNuke, airMopOnError);
  noutTen = nrrdNew();
  airMopAdd(mop, noutTen, (airMopper)nrrdNuke, airMopOnError);
  noutRmv = nrrdNew();
  airMopAdd(mop, noutRmv, (airMopper)nrrdNuke, airMopOnError);
  ntbuff = nrrdNew();
  airMopAdd(mop, ntbuff, (airMopper)nrrdNuke, airMopOnError);

  if (nrrdConvert(ninTen, _ninTen, nrrdTypeDouble)
      || nrrdSlice(nmask, ninTen, 0, 0)
      || nrrdConvert(ninB0, _ninB0, nrrdTypeDouble)
      || nrrdMaybeAlloc_va(noutTen, nrrdTypeDouble, 4, 
                           AIR_CAST(size_t, 7), sizeX, sizeY, sizeZ)
      || nrrdMaybeAlloc_va(noutCovar, nrrdTypeDouble, 4, 
                           AIR_CAST(size_t, 21), sizeX, sizeY, sizeZ)
      || nrrdMaybeAlloc_va(noutRmv, nrrdTypeDouble, 4, 
                           AIR_CAST(size_t, 6), sizeX, sizeY, sizeZ)
      || nrrdMaybeAlloc_va(ntbuff, nrrdTypeDouble, 2,
                           AIR_CAST(size_t, 7), NN)) {
    airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: trouble setting up tec:\n%s\n", me, err);
    airMopError(mop);
    return 1;
  }

  tec = tenEstimateContextNew();
  airMopAdd(mop, tec, (airMopper)tenEstimateContextNix, airMopAlways);

  E = 0;
  if (!E) E |= tenEstimateMethodSet(tec, tenEstimate1MethodLLS);
  if (!E) E |= tenEstimateValueMinSet(tec, 0.000000001);
  if (!E) E |= tenEstimateGradientsSet(tec, ngrad, bval, AIR_TRUE);
  if (!E) E |= tenEstimateThresholdSet(tec, 0, 0);
  if (!E) E |= tenEstimateUpdate(tec);
  if (E) {
    airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways);
    fprintf(stderr, "%s: trouble setting up tec:\n%s\n", me, err);
    airMopError(mop);
    return 1;
  }

  airSrandMT(seed);

  fprintf(stderr, "!%s: randrot = %d\n", me, randrot);
  if (1) {
    unsigned int II;
    unsigned int nsamp;
    double *inTen, *outTen, *outCovar, *outRmv, 
      *dwibuff, (*lup)(const void *, size_t);
    char doneStr[AIR_STRLEN_SMALL];

    dwibuff = AIR_CAST(double *, calloc(ngrad->axis[1].size, sizeof(double)));
    airMopAdd(mop, dwibuff, airFree, airMopAlways);
    nsamp = sizeX*sizeY*sizeZ;
    inTen = AIR_CAST(double *, ninTen->data);
    lup  = nrrdDLookup[nrrdTypeDouble];
    outTen = AIR_CAST(double *, noutTen->data);
    outCovar = AIR_CAST(double *, noutCovar->data);
    outRmv = AIR_CAST(double *, noutRmv->data);
    fprintf(stderr, "!%s: simulating ...       ", me);
    fflush(stderr);
    for (II=0; II<nsamp; II++) {
      if (!(II % sizeX)) {
        fprintf(stderr, "%s", airDoneStr(0, II, nsamp, doneStr));
        fflush(stderr);
      }
      if (csimDo(outTen, outCovar, outRmv + 0, outRmv + 3, ntbuff,
                 tec, dwibuff, sigma,
                 bval, lup(ninB0->data, II), NN, randrot, inTen)) {
        airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways);
        fprintf(stderr, "%s: trouble:\n%s\n", me, err);
        airMopError(mop);
        return 1;
      }
      inTen += 7;
      outTen += 7;
      outCovar += 21;
      outRmv += 6;
    }
    fprintf(stderr, "%s\n", airDoneStr(0, II, nsamp, doneStr));
  }