예제 #1
0
파일: methodsMoss.c 프로젝트: BRAINSia/teem
int
mossImageAlloc (Nrrd *image, int type, int sx, int sy, int ncol) {
  static const char me[]="mossImageAlloc";
  int ret;

  if (!(image && AIR_IN_OP(nrrdTypeUnknown, type, nrrdTypeBlock)
        && sx > 0 && sy > 0 && ncol > 0)) {
    biffAddf(MOSS, "%s: got NULL pointer or bad args", me);
    return 1;
  }
  if (1 == ncol) {
    ret = nrrdMaybeAlloc_va(image, type, 2,
                            AIR_CAST(size_t, sx),
                            AIR_CAST(size_t, sy));
  } else {
    ret = nrrdMaybeAlloc_va(image, type, 3,
                            AIR_CAST(size_t, ncol),
                            AIR_CAST(size_t, sx),
                            AIR_CAST(size_t, sy));
  }
  if (ret) {
    biffMovef(MOSS, NRRD, "%s: couldn't allocate image", me);
    return 1;
  }


  return 0;
}
예제 #2
0
파일: methodsMoss.c 프로젝트: rblake/seg3d2
int
mossImageAlloc (Nrrd *image, int type, int sx, int sy, int ncol) {
    char me[]="mossImageAlloc", err[BIFF_STRLEN];
    int ret;

    if (!(image && AIR_IN_OP(nrrdTypeUnknown, type, nrrdTypeBlock)
            && sx > 0 && sy > 0 && ncol > 0)) {
        sprintf(err, "%s: got NULL pointer or bad args", me);
        biffAdd(MOSS, err);
        return 1;
    }
    if (1 == ncol) {
        ret = nrrdMaybeAlloc_va(image, type, 2,
                                AIR_CAST(size_t, sx),
                                AIR_CAST(size_t, sy));
    } else {
        ret = nrrdMaybeAlloc_va(image, type, 3,
                                AIR_CAST(size_t, ncol),
                                AIR_CAST(size_t, sx),
                                AIR_CAST(size_t, sy));
    }
    if (ret) {
        sprintf(err, "%s: couldn't allocate image", me);
        biffMove(MOSS, err, NRRD);
        return 1;
    }


    return 0;
}
예제 #3
0
파일: grads.c 프로젝트: BRAINSia/teem
/*
******** tenGradientRandom
**
** generates num random unit vectors of type double
*/
int
tenGradientRandom(Nrrd *ngrad, unsigned int num, unsigned int seed) {
  static const char me[]="tenGradientRandom";
  double *grad, len;
  unsigned int gi;

  if (nrrdMaybeAlloc_va(ngrad, nrrdTypeDouble, 2,
                        AIR_CAST(size_t, 3), AIR_CAST(size_t, num))) {
    biffMovef(TEN, NRRD, "%s: couldn't allocate output", me);
    return 1;
  }
  airSrandMT(seed);
  grad = AIR_CAST(double*, ngrad->data);
  for (gi=0; gi<num; gi++) {
    do {
      grad[0] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1);
      grad[1] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1);
      grad[2] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1);
      len = ELL_3V_LEN(grad);
    } while (len > 1 || !len);
    ELL_3V_SCALE(grad, 1.0/len, grad);
    grad += 3;
  }
  return 0;
}
예제 #4
0
Nrrd *
_baneGkmsDonNew(int invert) {
  char me[]="_baneGkmsDonNew", err[BIFF_STRLEN];
  Nrrd *ret;
  float *data;

  if (nrrdMaybeAlloc_va(ret=nrrdNew(), nrrdTypeFloat, 2,
                        AIR_CAST(size_t, 4), AIR_CAST(size_t, 23))) {
    sprintf(err, "%s: can't create output", me);
    biffAdd(BANE, err); return NULL;
  }
  data = (float *)ret->data;
  memcpy(data, _baneGkmsDonData, 4*23*sizeof(float));
  data[0 + 4*0] = AIR_NEG_INF;
  data[0 + 4*1] = AIR_NAN;
  data[0 + 4*2] = AIR_POS_INF;
  if (invert) {
    INVERT(data, 0);
    INVERT(data, 1);
    INVERT(data, 2);
    INVERT(data, 12);
    INVERT(data, 13);
  }
  return ret;
}
예제 #5
0
파일: splineEval.c 프로젝트: rblake/seg3d2
int
limnSplineSample(Nrrd *nout, limnSpline *spline,
                 double minT, size_t M, double maxT) {
  char me[]="limnSplineSample", err[BIFF_STRLEN];
  airArray *mop;
  Nrrd *ntt;
  double *tt;
  size_t I;

  if (!(nout && spline)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(LIMN, err); return 1;
  }
  mop = airMopNew();
  airMopAdd(mop, ntt=nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  if (nrrdMaybeAlloc_va(ntt, nrrdTypeDouble, 1,
                        M)) {
    sprintf(err, "%s: trouble allocating tmp nrrd", me);
    biffMove(LIMN, err, NRRD); airMopError(mop); return 1;
  }
  tt = (double*)(ntt->data);
  for (I=0; I<M; I++) {
    tt[I] = AIR_AFFINE(0, I, M-1, minT, maxT);
  }
  if (limnSplineNrrdEvaluate(nout, spline, ntt)) {
    sprintf(err, "%s: trouble", me);
    biffAdd(LIMN, err); airMopError(mop); return 1;
  }
  airMopOkay(mop);
  return 0;
}
예제 #6
0
파일: genmat.c 프로젝트: CIBC-Internal/teem
/*
******** ell_Nm_inv
**
** computes the inverse of given matrix in nmat, and puts the
** inverse in the (maybe allocated) ninv.  Does not touch the
** values in nmat.
*/
int
ell_Nm_inv(Nrrd *ninv, Nrrd *nmat) {
  static const char me[]="ell_Nm_inv";
  double *mat, *inv;
  size_t NN;

  if (!( ninv && !ell_Nm_check(nmat, AIR_FALSE) )) {
    biffAddf(ELL, "%s: NULL or invalid args", me);
    return 1;
  }

  NN = nmat->axis[0].size;
  if (!( NN == nmat->axis[1].size )) {
    char stmp[2][AIR_STRLEN_SMALL];
    biffAddf(ELL, "%s: need a square matrix, not %s-by-%s", me,
             airSprintSize_t(stmp[0], nmat->axis[1].size),
             airSprintSize_t(stmp[1], NN));
    return 1;
  }
  if (nrrdMaybeAlloc_va(ninv, nrrdTypeDouble, 2,
                        NN, NN)) {
    biffMovef(ELL, NRRD, "%s: trouble", me);
    return 1;
  }
  inv = (double*)(ninv->data);
  mat = (double*)(nmat->data);
  if (_ell_inv(inv, mat, NN)) {
    biffAddf(ELL, "%s: trouble", me);
    return 1;
  }

  return 0;
}
예제 #7
0
int
alanUpdate(alanContext *actx) {
  char me[]="alanUpdate", err[BIFF_STRLEN];
  int ret;

  if (_alanCheck(actx)) {
    sprintf(err, "%s: ", me);
    biffAdd(ALAN, err); return 1;
  }
  if (actx->_nlev[0] || actx->_nlev[0]) {
    sprintf(err, "%s: confusion: _nlev[0,1] already allocated?", me);
    biffAdd(ALAN, err); return 1;
  }
  actx->_nlev[0] = nrrdNew();
  actx->_nlev[1] = nrrdNew();
  actx->nparm = nrrdNew();
  if (2 == actx->dim) {
    ret = (nrrdMaybeAlloc_va(actx->_nlev[0], alan_nt, 3,
                             AIR_CAST(size_t, 2),
                             AIR_CAST(size_t, actx->size[0]),
                             AIR_CAST(size_t, actx->size[1]))
           || nrrdCopy(actx->_nlev[1], actx->_nlev[0])
           || nrrdMaybeAlloc_va(actx->nparm, alan_nt, 3,
                                AIR_CAST(size_t, 3),
                                AIR_CAST(size_t, actx->size[0]),
                                AIR_CAST(size_t, actx->size[1])));
  } else {
    ret = (nrrdMaybeAlloc_va(actx->_nlev[0], alan_nt, 4,
                             AIR_CAST(size_t, 2),
                             AIR_CAST(size_t, actx->size[0]),
                             AIR_CAST(size_t, actx->size[1]),
                             AIR_CAST(size_t, actx->size[2]))
           || nrrdCopy(actx->_nlev[1], actx->_nlev[0])
           || nrrdMaybeAlloc_va(actx->nparm, alan_nt, 4,
                                AIR_CAST(size_t, 3),
                                AIR_CAST(size_t, actx->size[0]),
                                AIR_CAST(size_t, actx->size[1]),
                                AIR_CAST(size_t, actx->size[2])));
  }
  if (ret) {
    sprintf(err, "%s: trouble allocating buffers", me);
    biffMove(ALAN, err, NRRD); return 1;
  }
  
  return 0;
}
예제 #8
0
/*
******** nrrdPPM()
**
** for making a nrrd suitable for holding PPM data
**
** "don't mess with peripheral information"
*/
int
nrrdPPM(Nrrd *ppm, size_t sx, size_t sy) {
  char me[]="nrrdPPM", err[BIFF_STRLEN];

  if (nrrdMaybeAlloc_va(ppm, nrrdTypeUChar, 3,
                        AIR_CAST(size_t, 3), sx, sy)) {
    sprintf(err, "%s: couldn't allocate " _AIR_SIZE_T_CNV
            " x " _AIR_SIZE_T_CNV " 24-bit image", me, sx, sy);
    biffAdd(NRRD, err); return 1;
  }
  return 0;
}
예제 #9
0
파일: genmat.c 프로젝트: CIBC-Internal/teem
/*
******** ell_Nm_mul
**
** Currently, only useful for matrix-matrix multiplication
**
** matrix-matrix:      M       N
**                  L [A] . M [B]
*/
int
ell_Nm_mul(Nrrd *nAB, Nrrd *nA, Nrrd *nB) {
  static const char me[]="ell_Nm_mul";
  double *A, *B, *AB, tmp;
  size_t LL, MM, NN, ll, mm, nn;
  char stmp[4][AIR_STRLEN_SMALL];

  if (!( nAB && !ell_Nm_check(nA, AIR_FALSE)
         && !ell_Nm_check(nB, AIR_FALSE) )) {
    biffAddf(ELL, "%s: NULL or invalid args", me);
    return 1;
  }
  if (nAB == nA || nAB == nB) {
    biffAddf(ELL, "%s: can't do in-place multiplication", me);
    return 1;
  }
  LL = nA->axis[1].size;
  MM = nA->axis[0].size;
  NN = nB->axis[0].size;
  if (MM != nB->axis[1].size) {
    biffAddf(ELL, "%s: size mismatch: %s-by-%s times %s-by-%s", me,
             airSprintSize_t(stmp[0], LL),
             airSprintSize_t(stmp[1], MM),
             airSprintSize_t(stmp[2], nB->axis[1].size),
             airSprintSize_t(stmp[3], NN));
    return 1;
  }
  if (nrrdMaybeAlloc_va(nAB, nrrdTypeDouble, 2,
                        NN, LL)) {
    biffMovef(ELL, NRRD, "%s: trouble", me);
    return 1;
  }
  A = (double*)(nA->data);
  B = (double*)(nB->data);
  AB = (double*)(nAB->data);
  for (ll=0; ll<LL; ll++) {
    for (nn=0; nn<NN; nn++) {
      tmp = 0;
      for (mm=0; mm<MM; mm++) {
        tmp += A[mm + MM*ll]*B[nn + NN*mm];
      }
      AB[ll*NN + nn] = tmp;
    }
  }

  return 0;
}
예제 #10
0
int
baneGkmsParseBEF(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) {
  char me[]="baneGkmsParseBEF", mesg[AIR_STRLEN_MED], *nerr;
  float cent, width, shape, alpha, off, *bef;
  Nrrd **nrrdP;
  airArray *mop;
  
  if (!(ptr && str)) {
    sprintf(err, "%s: got NULL pointer", me);
    return 1;
  }
  mop = airMopNew();
  nrrdP = (Nrrd **)ptr;
  airMopAdd(mop, *nrrdP=nrrdNew(), (airMopper)nrrdNuke, airMopOnError);
  if (4 == sscanf(str, "%g,%g,%g,%g", &shape, &width, &cent, &alpha)) {
    /* its a valid BEF specification, we make the nrrd ourselves */
    if (nrrdMaybeAlloc_va(*nrrdP, nrrdTypeFloat, 2,
                          AIR_CAST(size_t, 2), AIR_CAST(size_t, 6))) {
      airMopAdd(mop, nerr = biffGetDone(NRRD), airFree, airMopOnError);
      strncpy(err, nerr, AIR_STRLEN_HUGE-1);
      airMopError(mop);
      return 1;
    }
    bef = (float *)((*nrrdP)->data);
    off = AIR_CAST(float, AIR_AFFINE(0.0, shape, 1.0, 0.0, width/2));
    /* positions */
    bef[0 + 2*0] = cent - 2*width;
    bef[0 + 2*1] = cent - width/2 - off;
    bef[0 + 2*2] = cent - width/2 + off;
    bef[0 + 2*3] = cent + width/2 - off;
    bef[0 + 2*4] = cent + width/2 + off;
    bef[0 + 2*5] = cent + 2*width;
    if (bef[0 + 2*1] == bef[0 + 2*2]) bef[0 + 2*1] -= 0.001f;
    if (bef[0 + 2*2] == bef[0 + 2*3]) bef[0 + 2*2] -= 0.001f;
    if (bef[0 + 2*3] == bef[0 + 2*4]) bef[0 + 2*4] += 0.001f;
    /* opacities */
    bef[1 + 2*0] = 0.0;
    bef[1 + 2*1] = 0.0;
    bef[1 + 2*2] = alpha;
    bef[1 + 2*3] = alpha;
    bef[1 + 2*4] = 0.0;
    bef[1 + 2*5] = 0.0;
    /* to tell gkms opac that this came from four floats */
    (*nrrdP)->ptr = *nrrdP;
  } else {
    if (nrrdLoad(*nrrdP, str, NULL)) {
예제 #11
0
int
limnPolyDataSpiralTubeWrap(limnPolyData *pldOut, const limnPolyData *pldIn,
                           unsigned int infoBitFlag, Nrrd *nvertmap,
                           unsigned int tubeFacet, unsigned int endFacet,
                           double radius) {
  char me[]="limnPolyDataSpiralTubeWrap", err[BIFF_STRLEN];
  double *cost, *sint;
  unsigned int tubeVertNum = 0, tubeIndxNum = 0, primIdx, pi, *vertmap;
  unsigned int inVertTotalIdx = 0, outVertTotalIdx = 0, outIndxIdx = 0;
  int color;
  airArray *mop;

  if (!( pldOut && pldIn )) {
    sprintf(err, "%s: got NULL pointer", me);
    return 1;
  }
  if ((1 << limnPrimitiveLineStrip) != limnPolyDataPrimitiveTypes(pldIn)) {
    sprintf(err, "%s: sorry, can only handle %s primitives", me,
            airEnumStr(limnPrimitive, limnPrimitiveLineStrip));
    biffAdd(LIMN, err); return 1;
  }
  
  for (primIdx=0; primIdx<pldIn->primNum; primIdx++) {
    tubeVertNum += tubeFacet*(2*endFacet
                              + pldIn->icnt[primIdx]) + 1;
    tubeIndxNum += 2*tubeFacet*(2*endFacet
                                + pldIn->icnt[primIdx] + 1)-2;
  }
  if (limnPolyDataAlloc(pldOut,
                        /* sorry have to have normals, even if they weren't
                           asked for, because currently they're used as part
                           of vertex position calc */
                        (infoBitFlag | (1 << limnPolyDataInfoNorm)),
                        tubeVertNum, tubeIndxNum, pldIn->primNum)) {
    sprintf(err, "%s: trouble allocating output", me);
    biffAdd(LIMN, err); return 1;
  }
  if (nvertmap) {
    if (nrrdMaybeAlloc_va(nvertmap, nrrdTypeUInt, 1,
                          AIR_CAST(size_t, tubeVertNum))) {
      sprintf(err, "%s: trouble allocating vert map", me);
      biffMove(LIMN, err, NRRD); return 1;
    }
    vertmap = AIR_CAST(unsigned int *, nvertmap->data);
  } else {
예제 #12
0
/*
******** nrrd1DIrregAclGenerate()
**
** Generates the "acl" that is used to speed up the action of
** nrrdApply1DIrregMap().  Basically, the domain of the map
** is quantized into "acllen" bins, and for each bin, the
** lowest and highest possible map interval is stored. This
** either obviates or speeds up the task of finding which
** interval contains a given value.
**
** Assumes that nrrd1DIrregMapCheck has been called on "nmap".
*/
int
nrrd1DIrregAclGenerate(Nrrd *nacl, const Nrrd *nmap, size_t aclLen) {
  char me[]="nrrd1DIrregAclGenerate", err[BIFF_STRLEN];
  int posLen;
  unsigned int ii;
  unsigned short *acl;
  double lo, hi, min, max, *pos;

  if (!(nacl && nmap)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err); return 1;
  }
  if (!(aclLen >= 2)) {
    sprintf(err, "%s: given acl length (" _AIR_SIZE_T_CNV 
            ") is too small", me, aclLen);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdMaybeAlloc_va(nacl, nrrdTypeUShort, 2, 
                        AIR_CAST(size_t, 2), AIR_CAST(size_t, aclLen))) {
    sprintf(err, "%s: ", me);
    biffAdd(NRRD, err); return 1;
  }
  acl = (unsigned short *)nacl->data;
  pos = _nrrd1DIrregMapDomain(&posLen, NULL, nmap);
  if (!pos) {
    sprintf(err, "%s: couldn't determine domain", me); 
    biffAdd(NRRD, err); return 1;
  }
  nacl->axis[1].min = min = pos[0];
  nacl->axis[1].max = max = pos[posLen-1];
  for (ii=0; ii<=aclLen-1; ii++) {
    lo = AIR_AFFINE(0, ii, aclLen, min, max);
    hi = AIR_AFFINE(0, ii+1, aclLen, min, max);
    acl[0 + 2*ii] = _nrrd1DIrregFindInterval(pos, lo, 0, posLen-2);
    acl[1 + 2*ii] = _nrrd1DIrregFindInterval(pos, hi, 0, posLen-2);
  }
  free(pos);

  return 0;
}
예제 #13
0
파일: genmat.c 프로젝트: CIBC-Internal/teem
/*
******** ell_Nm_tran
**
**     M             N
** N [trn]  <--  M [mat]
*/
int
ell_Nm_tran(Nrrd *ntrn, Nrrd *nmat) {
  static const char me[]="ell_Nm_tran";
  double *mat, *trn;
  size_t MM, NN, mm, nn;

  if (!( ntrn && !ell_Nm_check(nmat, AIR_FALSE) )) {
    biffAddf(ELL, "%s: NULL or invalid args", me);
    return 1;
  }
  if (ntrn == nmat) {
    biffAddf(ELL, "%s: sorry, can't work in-place yet", me);
    return 1;
  }
  /*
  if (nrrdAxesSwap(ntrn, nmat, 0, 1)) {
    biffMovef(ELL, NRRD, "%s: trouble", me);
    return 1;
    }
  */
  NN = nmat->axis[0].size;
  MM = nmat->axis[1].size;
  if (nrrdMaybeAlloc_va(ntrn, nrrdTypeDouble, 2,
                        MM, NN)) {
    biffMovef(ELL, NRRD, "%s: trouble", me);
    return 1;
  }
  mat = AIR_CAST(double *, nmat->data);
  trn = AIR_CAST(double *, ntrn->data);
  for (nn=0; nn<NN; nn++) {
    for (mm=0; mm<MM; mm++) {
      trn[mm + MM*nn] = mat[nn + NN*mm];
    }
  }

  return 0;
}
예제 #14
0
파일: tt.c 프로젝트: SCIInstitute/Cleaver
int
main(int argc, char *argv[]) {
  char *me, *err, *outS;
  hestOpt *hopt=NULL;
  airArray *mop;
  
  int sx, sy, xi, yi, samp, version, whole, right;
  float *tdata;
  double p[3], xyz[3], q[4], len, hackcp=0, maxca;
  double ca, cp, mD[9], mRF[9], mRI[9], mT[9], hack;
  Nrrd *nten;
  mop = airMopNew();
  
  me = argv[0];
  hestOptAdd(&hopt, "n", "# samples", airTypeInt, 1, 1, &samp, "4",
             "number of glyphs along each edge of triangle");
  hestOptAdd(&hopt, "p", "x y z", airTypeDouble, 3, 3, p, NULL,
             "location in quaternion quotient space");
  hestOptAdd(&hopt, "ca", "max ca", airTypeDouble, 1, 1, &maxca, "0.8",
             "maximum ca to use at bottom edge of triangle");
  hestOptAdd(&hopt, "r", NULL, airTypeInt, 0, 0, &right, NULL,
             "sample a right-triangle-shaped region, instead of "
             "a roughly equilateral triangle. ");
  hestOptAdd(&hopt, "w", NULL, airTypeInt, 0, 0, &whole, NULL,
             "sample the whole triangle of constant trace, "
             "instead of just the "
             "sixth of it in which the eigenvalues have the "
             "traditional sorted order. ");
  hestOptAdd(&hopt, "hack", "hack", airTypeDouble, 1, 1, &hack, "0.04",
             "this is a hack");
  hestOptAdd(&hopt, "v", "version", airTypeInt, 1, 1, &version, "1",
             "which version of the Westin metrics to use to parameterize "
             "triangle; \"1\" for ISMRM 97, \"2\" for MICCAI 99");
  hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-",
             "output file to save tensors into");
  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);
  
  nten = nrrdNew();
  airMopAdd(mop, nten, (airMopper)nrrdNuke, airMopAlways);

  if (!( 1 == version || 2 == version )) {
    fprintf(stderr, "%s: version must be 1 or 2 (not %d)\n", me, version);
    airMopError(mop); 
    return 1;
  }
  if (right) {
    sx = samp;
    sy = (int)(1.0*samp/sqrt(3.0));
  } else {
    sx = 2*samp-1;
    sy = samp;
  }
  if (nrrdMaybeAlloc_va(nten, nrrdTypeFloat, 4,
                        AIR_CAST(size_t, 7),
                        AIR_CAST(size_t, sx),
                        AIR_CAST(size_t, sy),
                        AIR_CAST(size_t, 3))) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't allocate output:\n%s\n", me, err);
    airMopError(mop); 
    return 1;
  }
  q[0] = 1.0;
  q[1] = p[0];
  q[2] = p[1];
  q[3] = p[2];
  len = ELL_4V_LEN(q);
  ELL_4V_SCALE(q, 1.0/len, q);
  washQtoM3(mRF, q);
  ELL_3M_TRANSPOSE(mRI, mRF);
  if (right) {
    _ra2t(nten, 0.00, 0.0, mRI, mRF, hack);

    _ra2t(nten, 0.10, 0.0, mRI, mRF, hack);
    _ra2t(nten, 0.10, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.20, 0.0, mRI, mRF, hack);
    _ra2t(nten, 0.20, 30.0, mRI, mRF, hack);
    _ra2t(nten, 0.20, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.30, 0.0, mRI, mRF, hack);
    _ra2t(nten, 0.30, 20.0, mRI, mRF, hack);
    _ra2t(nten, 0.30, 40.0, mRI, mRF, hack);
    _ra2t(nten, 0.30, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.40, 0.0, mRI, mRF, hack);
    _ra2t(nten, 0.40, 15.0, mRI, mRF, hack);
    _ra2t(nten, 0.40, 30.0, mRI, mRF, hack);
    _ra2t(nten, 0.40, 45.0, mRI, mRF, hack);
    _ra2t(nten, 0.40, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.50, 0.0, mRI, mRF, hack);
    _ra2t(nten, 0.50, 12.0, mRI, mRF, hack);
    _ra2t(nten, 0.50, 24.0, mRI, mRF, hack);
    _ra2t(nten, 0.50, 36.0, mRI, mRF, hack);
    _ra2t(nten, 0.50, 48.0, mRI, mRF, hack);
    _ra2t(nten, 0.50, 60.0, mRI, mRF, hack);

    /* _ra2t(nten, 0.60, 30.0, mRI, mRF, hack); */
    _ra2t(nten, 0.60, 40.0, mRI, mRF, hack);
    _ra2t(nten, 0.60, 50.0, mRI, mRF, hack);
    _ra2t(nten, 0.60, 60.0, mRI, mRF, hack);

    /* _ra2t(nten, 0.70, 34.3, mRI, mRF, hack); */
    /* _ra2t(nten, 0.70, 42.8, mRI, mRF, hack); */
    _ra2t(nten, 0.70, 51.4, mRI, mRF, hack);
    _ra2t(nten, 0.70, 60.0, mRI, mRF, hack);

    /* _ra2t(nten, 0.80, 45.0, mRI, mRF, hack); */
    _ra2t(nten, 0.80, 52.5, mRI, mRF, hack);
    _ra2t(nten, 0.80, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.90, 60.0, mRI, mRF, hack);

    _ra2t(nten, 1.00, 60.0, mRI, mRF, hack);
    /*
    _ra2t(nten, 0.000, 0.0, mRI, mRF, hack);

    _ra2t(nten, 0.125, 0.0, mRI, mRF, hack);
    _ra2t(nten, 0.125, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.250, 0.0, mRI, mRF, hack);
    _ra2t(nten, 0.250, 30.0, mRI, mRF, hack);
    _ra2t(nten, 0.250, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.375, 0.0, mRI, mRF, hack);
    _ra2t(nten, 0.375, 20.0, mRI, mRF, hack);
    _ra2t(nten, 0.375, 40.0, mRI, mRF, hack);
    _ra2t(nten, 0.375, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.500, 0.0, mRI, mRF, hack);
    _ra2t(nten, 0.500, 15.0, mRI, mRF, hack);
    _ra2t(nten, 0.500, 30.0, mRI, mRF, hack);
    _ra2t(nten, 0.500, 45.0, mRI, mRF, hack);
    _ra2t(nten, 0.500, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.625, 37.0, mRI, mRF, hack);
    _ra2t(nten, 0.625, 47.5, mRI, mRF, hack);
    _ra2t(nten, 0.625, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.750, 49.2, mRI, mRF, hack);
    _ra2t(nten, 0.750, 60.0, mRI, mRF, hack);

    _ra2t(nten, 0.875, 60.0, mRI, mRF, hack);

    _ra2t(nten, 1.000, 60.0, mRI, mRF, hack);
    */
    nten->axis[1].spacing = 1;
    nten->axis[2].spacing = (sx-1)/(sqrt(3.0)*(sy-1));
    nten->axis[3].spacing = 1;
  } else {
    for (yi=0; yi<samp; yi++) {
      if (whole) {
        ca = AIR_AFFINE(0, yi, samp-1, 0.0, 1.0);
      } else {
        ca = AIR_AFFINE(0, yi, samp-1, hack, maxca);
        hackcp = AIR_AFFINE(0, yi, samp-1, hack, 0);
      }
      for (xi=0; xi<=yi; xi++) {
        if (whole) {
          cp = AIR_AFFINE(0, xi, samp-1, 0.0, 1.0);
        } else {
          cp = AIR_AFFINE(0, xi, samp-1, hackcp, maxca-hack/2.0);
        }
        _cap2xyz(xyz, ca, cp, version, whole);
        /*
          fprintf(stderr, "%s: (%d,%d) -> (%g,%g) -> %g %g %g\n", me,
          yi, xi, ca, cp, xyz[0], xyz[1], xyz[2]);
        */
        ELL_3M_IDENTITY_SET(mD);
        ELL_3M_DIAG_SET(mD, xyz[0], xyz[1], xyz[2]);
        ELL_3M_IDENTITY_SET(mT);
        ell_3m_post_mul_d(mT, mRI);
        ell_3m_post_mul_d(mT, mD);
        ell_3m_post_mul_d(mT, mRF);
        
        tdata = (float*)nten->data + 
          7*(2*(samp-1-xi) - (samp-1-yi) + (2*samp-1)*((samp-1-yi) + samp));
        tdata[0] = 1.0;
        TEN_M2T(tdata, mT);
      }
    }
    nten->axis[1].spacing = 1;
    nten->axis[2].spacing = 1.5;
    nten->axis[3].spacing = 1;
  }
  
  if (nrrdSave(outS, nten, NULL)) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't save output:\n%s\n", me, err);
    airMopError(mop); 
    return 1;
  }
  airMopOkay(mop);
  return 0;
}
예제 #15
0
int
limnEnvMapFill(Nrrd *map, limnEnvMapCB cb, int qnMethod, void *data) {
  char me[]="limnEnvMapFill", err[128];
  int sx, sy;
  int qn;
  float vec[3], *mapData;

  if (!(map && cb)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(LIMN, err); return 1;
  }
  if (!AIR_IN_OP(limnQNUnknown, qnMethod, limnQNLast)) {
    sprintf(err, "%s: QN method %d invalid", me, qnMethod);
    biffAdd(LIMN, err); return 1;
  }
  switch(qnMethod) {
  case limnQN16checker:
  case limnQN16octa:
    sx = sy = 256;
    break;
  case limnQN14checker:
  case limnQN14octa:
    sx = sy = 128;
    break;
  case limnQN12checker:
  case limnQN12octa:
    sx = sy = 64;
    break;
  case limnQN10checker:
  case limnQN10octa:
    sx = sy = 32;
    break;
  case limnQN8checker:
  case limnQN8octa:
    sx = sy = 16;
    break;
  case limnQN15octa:
    sx = 128;
    sy = 256;
    break;
  case limnQN13octa:
    sx = 64;
    sy = 128;
    break;
  case limnQN11octa:
    sx = 32;
    sy = 64;
    break;
  case limnQN9octa:
    sx = 16;
    sy = 32;
    break;
  default:
    sprintf(err, "%s: sorry, QN method %d not implemented", me, qnMethod);
    biffAdd(LIMN, err); return 1;
  }
  if (nrrdMaybeAlloc_va(map, nrrdTypeFloat, 3,
                        AIR_CAST(size_t, 3),
                        AIR_CAST(size_t, sx),
                        AIR_CAST(size_t, sy))) {
    sprintf(err, "%s: couldn't alloc output", me);
    biffMove(LIMN, err, NRRD); return 1;
  }
  mapData = (float *)map->data;
  for (qn=0; qn<sx*sy; qn++) {
    limnQNtoV_f[qnMethod](vec, qn);
    cb(mapData + 3*qn, vec, data);
  }

  return 0;
}
예제 #16
0
int
main(int argc, const char *argv[]) {
  const char *me;
  hestOpt *hopt;
  hestParm *hparm;
  airArray *mop;

  char *err, *outS;
  double sigmaMax, convEps, cutoff;
  int measr[2], tentRecon;
  unsigned int sampleNumMax, dim, measrSampleNum, maxIter, num, ii;
  gageOptimSigParm *osparm;
  double *scalePos, *out, info[512];
  Nrrd *nout;
  double *plotPos; unsigned int plotPosNum;

  me = argv[0];
  mop = airMopNew();
  hparm = hestParmNew();
  hopt = NULL;
  airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways);
  hestOptAdd(&hopt, "num", "# samp", airTypeUInt, 1, 1, &sampleNumMax, NULL,
             "maximum number of samples to optimize");
  hestOptAdd(&hopt, "dim", "dimension", airTypeUInt, 1, 1, &dim, "3",
             "dimension of image to work with");
  hestOptAdd(&hopt, "max", "sigma", airTypeDouble, 1, 1, &sigmaMax, NULL,
             "sigma to use for top sample (using 0 for bottom sample)");
  hestOptAdd(&hopt, "cut", "cut", airTypeDouble, 1, 1, &cutoff, "4",
             "at how many sigmas to cut-off discrete gaussian");
  hestOptAdd(&hopt, "mi", "max", airTypeUInt, 1, 1, &maxIter, "1000",
             "maximum # iterations");
  hestOptAdd(&hopt, "N", "# samp", airTypeUInt, 1, 1, &measrSampleNum, "300",
             "number of samples in the measurement of error across scales");
  hestOptAdd(&hopt, "eps", "eps", airTypeDouble, 1, 1, &convEps, "0.0001",
             "convergence threshold for optimization");
  hestOptAdd(&hopt, "m", "m1 m2", airTypeEnum, 2, 2, measr, "l2 l2",
             "how to measure error across image, and across scales",
             NULL, nrrdMeasure);
  hestOptAdd(&hopt, "p", "s0 s1", airTypeDouble, 2, -1, &plotPos, "nan nan",
             "hack: dont do optimization; just plot the recon error given "
             "these samples along scale", &plotPosNum);
  hestOptAdd(&hopt, "tent", NULL, airTypeInt, 0, 0, &tentRecon, NULL,
             "same hack: plot error with tent recon, not hermite");
  hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, NULL,
             "output array");
  hestParseOrDie(hopt, argc-1, argv+1, hparm,
                 me, optsigInfo, AIR_TRUE, AIR_TRUE, AIR_TRUE);
  airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways);
  airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways);

  nout = nrrdNew();
  airMopAdd(mop, nout, AIR_CAST(airMopper, nrrdNuke), airMopAlways);

  osparm = gageOptimSigParmNew(sampleNumMax);
  airMopAdd(mop, osparm, AIR_CAST(airMopper, gageOptimSigParmNix),
            airMopAlways);
  scalePos = AIR_CAST(double *, calloc(sampleNumMax, sizeof(double)));
  airMopAdd(mop, scalePos, airFree, airMopAlways);

  osparm->plotting = (AIR_EXISTS(plotPos[0]) && AIR_EXISTS(plotPos[1]));
  if (gageOptimSigTruthSet(osparm, dim, sigmaMax, cutoff, measrSampleNum)) {
    airMopAdd(mop, err = biffGetDone(GAGE), airFree, airMopAlways);
    fprintf(stderr, "%s: trouble:\n%s", me, err);
    airMopError(mop); return 1;
  }

  if (osparm->plotting) {
    if (gageOptimSigPlot(osparm, nout, plotPos, plotPosNum,
                         measr[0], tentRecon)) {
      airMopAdd(mop, err = biffGetDone(GAGE), airFree, airMopAlways);
      fprintf(stderr, "%s: trouble:\n%s", me, err);
      airMopError(mop); return 1;
    }
  } else {
    /* do sample position optimization */
    if (nrrdMaybeAlloc_va(nout, nrrdTypeDouble, 2,
                          AIR_CAST(size_t, sampleNumMax+1),
                          AIR_CAST(size_t, sampleNumMax+1))) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: trouble allocating output:\n%s", me, err);
      airMopError(mop); return 1;
    }
    out = AIR_CAST(double *, nout->data);
    /* hacky way of saving some of the computation information */
    info[0] = cutoff;
    info[1] = measrSampleNum;
    info[2] = measr[0];
    info[3] = measr[1];
    info[4] = convEps;
    info[5] = maxIter;
    for (ii=0; ii<sampleNumMax+1; ii++) {
      out[ii] = info[ii];
    }
    for (num=2; num<=sampleNumMax; num++) {
      printf("\n%s: ======= optimizing %u/%u samples (sigmaMax %g) \n\n",
             me, num, sampleNumMax, sigmaMax);
      if (gageOptimSigCalculate(osparm, scalePos, num,
                                measr[0], measr[1],
                                convEps, maxIter)) {
        airMopAdd(mop, err = biffGetDone(GAGE), airFree, airMopAlways);
        fprintf(stderr, "%s: trouble:\n%s", me, err);
        airMopError(mop); return 1;
      }
      out[sampleNumMax + (sampleNumMax+1)*num] = osparm->finalErr;
      for (ii=0; ii<num; ii++) {
        out[ii + (sampleNumMax+1)*num] = scalePos[ii];
      }
    }
  }
  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;
  }

  airMopOkay(mop);
  exit(0);
}
예제 #17
0
/*
******** tenFiberTraceSet
**
** slightly more flexible API for fiber tracking than tenFiberTrace
**
** EITHER: pass a non-NULL nfiber, and NULL, 0, NULL, NULL for 
** the following arguments, and things are the same as with tenFiberTrace:
** data inside the nfiber is allocated, and the tract vertices are copied
** into it, having been stored in dynamically allocated airArrays
**
** OR: pass a NULL nfiber, and a buff allocated for 3*(2*halfBuffLen + 1)
** (note the "+ 1" !!!) doubles.  The fiber tracking on each half will stop
** at halfBuffLen points. The given seedpoint will be stored in
** buff[0,1,2 + 3*halfBuffLen].  The indices for the end of the first
** tract half, and the end of the second tract half, will be set in
** *startIdxP and *endIdxP respectively.
*/
int
tenFiberTraceSet(tenFiberContext *tfx, Nrrd *nfiber,
                 double *buff, unsigned int halfBuffLen,
                 unsigned int *startIdxP, unsigned int *endIdxP,
                 double seed[3]) {
  char me[]="tenFiberTraceSet", err[BIFF_STRLEN];
  airArray *fptsArr[2];      /* airArrays of backward (0) and forward (1)
                                fiber points */
  double *fpts[2];           /* arrays storing forward and backward
                                fiber points */
  double
    tmp[3],
    iPos[3],
    currPoint[3], 
    forwDir[3],
    *fiber;                  /* array of both forward and backward points, 
                                when finished */
  int ret, whyStop, buffIdx, fptsIdx, outIdx, oldStop;
  unsigned int i;
  airArray *mop;

  if (!(tfx)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(TEN, err); return 1;
  }
  /* HEY: a hack to preserve the state inside tenFiberContext so that
     we have fewer side effects (tfx->maxNumSteps may still be set) */
  oldStop = tfx->stop;
  if (!nfiber) {
    if (!( buff && halfBuffLen > 0 && startIdxP && startIdxP )) {
      sprintf(err, "%s: need either non-NULL nfiber or fpts buffer info", me);
      biffAdd(TEN, err); return 1;
    }
    if (tenFiberStopSet(tfx, tenFiberStopNumSteps, halfBuffLen)) {
      sprintf(err, "%s: error setting new fiber stop", me);
      biffAdd(TEN, err); return 1;
    }
  }

  /* initialize the quantities which describe the fiber halves */
  tfx->halfLen[0] = tfx->halfLen[1] = 0.0;
  tfx->numSteps[0] = tfx->numSteps[1] = 0;
  tfx->whyStop[0] = tfx->whyStop[1] = tenFiberStopUnknown;

  /* try probing once */
  if (tfx->useIndexSpace) {
    ret = gageProbe(tfx->gtx,
                    AIR_CAST(gage_t, seed[0]),
                    AIR_CAST(gage_t, seed[1]),
                    AIR_CAST(gage_t, seed[2]));
  } else {
    gageShapeWtoI(tfx->gtx->shape, tmp, seed);
    ret = gageProbe(tfx->gtx,
                    AIR_CAST(gage_t, tmp[0]),
                    AIR_CAST(gage_t, tmp[1]),
                    AIR_CAST(gage_t, tmp[2]));
  }
  if (ret) {
    sprintf(err, "%s: first gageProbe failed: %s (%d)", 
            me, tfx->gtx->errStr, tfx->gtx->errNum);
    biffAdd(TEN, err); return 1;
  }

  /* see if we're doomed */
  if ((whyStop = _tenFiberStopCheck(tfx))) {
    /* stopped immediately at seed point, but that's not an error */
    tfx->whyNowhere = whyStop;
    if (nfiber) {
      nrrdEmpty(nfiber);
    } else {
      *startIdxP = *endIdxP = 0;
    }
    return 0;
  } else {
    /* did not immediately halt */
    tfx->whyNowhere = tenFiberStopUnknown;
  }

  /* record the principal eigenvector at the seed point, which
     is needed to align the 4 intermediate steps of RK4 for the
     FIRST step of each half of the tract */
  ELL_3V_COPY(tfx->firstEvec, tfx->evec + 3*0);

  /* airMop{Error,Okay}() can safely be called on NULL */
  mop = nfiber ? airMopNew() : NULL;

  for (tfx->dir=0; tfx->dir<=1; tfx->dir++) {
    if (nfiber) {
      fptsArr[tfx->dir] = airArrayNew((void**)&(fpts[tfx->dir]), NULL, 
                                      3*sizeof(double), TEN_FIBER_INCR);
      airMopAdd(mop, fptsArr[tfx->dir], (airMopper)airArrayNuke, airMopAlways);
      buffIdx = -1;
    } else {
      fptsArr[tfx->dir] = NULL;
      fpts[tfx->dir] = NULL;
      buffIdx = halfBuffLen;
      fptsIdx = -1;
    }
    tfx->halfLen[tfx->dir] = 0;
    if (tfx->useIndexSpace) {
      ELL_3V_COPY(iPos, seed);
      gageShapeItoW(tfx->gtx->shape, tfx->wPos, iPos);
    } else {
      gageShapeWtoI(tfx->gtx->shape, iPos, seed);
      ELL_3V_COPY(tfx->wPos, seed);
    }
    ELL_3V_SET(tfx->lastDir, 0, 0, 0);
    tfx->lastDirSet = AIR_FALSE;
    for (tfx->numSteps[tfx->dir] = 0; AIR_TRUE; tfx->numSteps[tfx->dir]++) {
      if (_tenFiberProbe(tfx, tfx->wPos)) {
        /* even if gageProbe had an error OTHER than going out of bounds,
           we're not going to report it any differently here, alas */
        tfx->whyStop[tfx->dir] = tenFiberStopBounds;
        break;
      }
      if ((whyStop = _tenFiberStopCheck(tfx))) {
        if (tenFiberStopNumSteps == whyStop) {
          /* we stopped along this direction because tfx->numSteps[tfx->dir]
             exceeded tfx->maxNumSteps.  Okay.  But tfx->numSteps[tfx->dir]
             is supposed to be a record of how steps were (successfully)
             taken.  So we need to decrementing before moving on ... */
          tfx->numSteps[tfx->dir]--;
        }
        tfx->whyStop[tfx->dir] = whyStop;
        break;
      }
      if (tfx->useIndexSpace) {
        gageShapeWtoI(tfx->gtx->shape, iPos, tfx->wPos);
        ELL_3V_COPY(currPoint, iPos);
      } else {
        ELL_3V_COPY(currPoint, tfx->wPos);
      }
      if (nfiber) {
        fptsIdx = airArrayLenIncr(fptsArr[tfx->dir], 1);
        ELL_3V_COPY(fpts[tfx->dir] + 3*fptsIdx, currPoint);
      } else {
        ELL_3V_COPY(buff + 3*buffIdx, currPoint);
        /*
        fprintf(stderr, "!%s: (dir %d) saving to %d pnt %g %g %g\n", me,
                tfx->dir, buffIdx,
                currPoint[0], currPoint[1], currPoint[2]);
        */
        buffIdx += !tfx->dir ? -1 : 1;
      }
      /* forwDir is set by this to point to the next fiber point */
      if (_tenFiberIntegrate[tfx->intg](tfx, forwDir)) {
        tfx->whyStop[tfx->dir] = tenFiberStopBounds;
        break;
      }
      ELL_3V_COPY(tfx->lastDir, forwDir);
      tfx->lastDirSet = AIR_TRUE;
      ELL_3V_ADD2(tfx->wPos, tfx->wPos, forwDir);
      tfx->halfLen[tfx->dir] += ELL_3V_LEN(forwDir);
    }
  }

  if (nfiber) {
    if (nrrdMaybeAlloc_va(nfiber, nrrdTypeDouble, 2,
                          AIR_CAST(size_t, 3),
                          AIR_CAST(size_t, (fptsArr[0]->len 
                                            + fptsArr[1]->len - 1)))) {
      sprintf(err, "%s: couldn't allocate fiber nrrd", me);
      biffMove(TEN, err, NRRD); airMopError(mop); return 1;
    }
    fiber = (double*)(nfiber->data);
    outIdx = 0;
    for (i=fptsArr[0]->len-1; i>=1; i--) {
      ELL_3V_COPY(fiber + 3*outIdx, fpts[0] + 3*i);
      outIdx++;
    }
    for (i=0; i<=fptsArr[1]->len-1; i++) {
      ELL_3V_COPY(fiber + 3*outIdx, fpts[1] + 3*i);
      outIdx++;
    }
  } else {
    *startIdxP = halfBuffLen - tfx->numSteps[0];
    *endIdxP = halfBuffLen + tfx->numSteps[1];
  }

  tfx->stop = oldStop;
  airMopOkay(mop);
  return 0;
}
예제 #18
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);
}
예제 #19
0
int
tend_evecMain(int argc, char **argv, char *me, hestParm *hparm) {
  int pret;
  hestOpt *hopt = NULL;
  char *perr, *err;
  airArray *mop;

  int ret, *comp, compLen, cc;
  Nrrd *nin, *nout;
  char *outS;
  float thresh, *edata, *tdata, eval[3], evec[9], scl;
  size_t N, I, sx, sy, sz;

  hestOptAdd(&hopt, "c", "c0 ", airTypeInt, 1, 3, &comp, NULL,
             "which eigenvalues should be saved out. \"0\" for the "
             "largest, \"1\" for the middle, \"2\" for the smallest, "
             "\"0 1\", \"1 2\", \"0 1 2\" or similar for more than one",
             &compLen);
  hestOptAdd(&hopt, "t", "thresh", airTypeFloat, 1, 1, &thresh, "0.5",
             "confidence threshold");
  hestOptAdd(&hopt, "i", "nin", airTypeOther, 1, 1, &nin, "-",
             "input diffusion tensor volume", NULL, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-",
             "output image (floating point)");

  mop = airMopNew();
  airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways);
  USAGE(_tend_evecInfoL);
  PARSE();
  airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways);

  for (cc=0; cc<compLen; cc++) {
    if (!AIR_IN_CL(0, comp[cc], 2)) {
      fprintf(stderr, "%s: requested component %d (%d of 3) not in [0..2]\n",
              me, comp[cc], cc+1);
      airMopError(mop); return 1;
    }
  }
  if (tenTensorCheck(nin, nrrdTypeFloat, AIR_TRUE, AIR_TRUE)) {
    airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways);
    fprintf(stderr, "%s: didn't get a valid DT volume:\n%s\n", me, err);
    airMopError(mop); return 1;
  }
  
  sx = nin->axis[1].size;
  sy = nin->axis[2].size;
  sz = nin->axis[3].size;

  nout = nrrdNew();
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);
  ret = nrrdMaybeAlloc_va(nout, nrrdTypeFloat, 4,
                          AIR_CAST(size_t, 3*compLen), sx, sy, sz);
  if (ret) {
    airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: trouble allocating output:\n%s\n", me, err);
    airMopError(mop); return 1;
  }

  N = sx*sy*sz;
  edata = (float *)nout->data;
  tdata = (float *)nin->data;
  if (1 == compLen) {
    for (I=0; I<N; I++) {
      tenEigensolve_f(eval, evec, tdata);
      scl = AIR_CAST(float, tdata[0] >= thresh);
      ELL_3V_SCALE(edata, scl, evec+3*comp[0]);
      edata += 3;
      tdata += 7;
    }
  } else {
    for (I=0; I<N; I++) {
예제 #20
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;
}
예제 #21
0
int
main(int argc, const char **argv) {
  const char *me;
  Nrrd *nscl;
  double *dscl;
  airArray *mop;
  char *fullname;
  gageContext *igctx[INTERP_KERN_NUM], *bgctx[BLUR_KERN_NUM];
  const NrrdKernel *ikern[INTERP_KERN_NUM] = {
    nrrdKernelBox,
    nrrdKernelTent,
    nrrdKernelBCCubic,
    nrrdKernelCatmullRom,
  };
  double ikparm[INTERP_KERN_NUM][NRRD_KERNEL_PARMS_NUM] = {
    {1.0},
    {1.0},
    {1.0, 0.0, 0.5},
    {AIR_NAN},
  };
  const NrrdKernel *bkern[BLUR_KERN_NUM] = {
    nrrdKernelTent,
    nrrdKernelBSpline3,
    nrrdKernelBSpline5,
    nrrdKernelBCCubic,
    nrrdKernelGaussian,
  };
  const NrrdKernel *bkernD[BLUR_KERN_NUM] = {
    nrrdKernelForwDiff,
    nrrdKernelBSpline3D,
    nrrdKernelBSpline5D,
    nrrdKernelBCCubicD,
    nrrdKernelGaussianD,
  };
  const NrrdKernel *bkernDD[BLUR_KERN_NUM] = {
    nrrdKernelZero,
    nrrdKernelBSpline3DD,
    nrrdKernelBSpline5DD,
    nrrdKernelBCCubicDD,
    nrrdKernelGaussianDD,
  };
  double bkparm[BLUR_KERN_NUM][NRRD_KERNEL_PARMS_NUM] = {
    {1.0},
    {AIR_NAN},
    {AIR_NAN},
    {2.0, 1.0, 0.0},
    {1.2, 5.0},
  };
  const double *ivalAns[INTERP_KERN_NUM], *bvalAns[BLUR_KERN_NUM],
    *bgrdAns[BLUR_KERN_NUM], *bhesAns[BLUR_KERN_NUM];
  int E;
  unsigned int sx, sy, sz, ki;

  AIR_UNUSED(argc);
  me = argv[0];
  mop = airMopNew();

  nscl = nrrdNew();
  airMopAdd(mop, nscl, (airMopper)nrrdNuke, airMopAlways);
  fullname = testDataPathPrefix("fmob-c4h.nrrd");
  airMopAdd(mop, fullname, airFree, airMopAlways);
  if (nrrdLoad(nscl, fullname, NULL)) {
    char *err;
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: trouble reading data \"%s\":\n%s",
            me, fullname, err);
    airMopError(mop); return 1;
  }
  /* make sure its a double-type volume (assumed below) */
  if (nrrdTypeDouble != nscl->type) {
    fprintf(stderr, "%s: volume type %s != expected type %s\n", me,
            airEnumStr(nrrdType, nscl->type),
            airEnumStr(nrrdType, nrrdTypeDouble));
    airMopError(mop); return 1;
  }
  dscl = AIR_CAST(double *, nscl->data);
  sx = AIR_CAST(unsigned int, nscl->axis[0].size);
  sy = AIR_CAST(unsigned int, nscl->axis[1].size);
  sz = AIR_CAST(unsigned int, nscl->axis[2].size);

  for (ki=0; ki<INTERP_KERN_NUM; ki++) {
    gagePerVolume *gpvl;
    igctx[ki] = gageContextNew();
    airMopAdd(mop, igctx[ki], (airMopper)gageContextNix, airMopAlways);
    gageParmSet(igctx[ki], gageParmRenormalize, AIR_FALSE);
    gageParmSet(igctx[ki], gageParmCheckIntegrals, AIR_TRUE);
    gageParmSet(igctx[ki], gageParmOrientationFromSpacing, AIR_FALSE);
    E = 0;
    if (!E) E |= !(gpvl = gagePerVolumeNew(igctx[ki], nscl, gageKindScl));
    if (!E) E |= gageKernelSet(igctx[ki], gageKernel00,
                               ikern[ki], ikparm[ki]);
    if (!E) E |= gagePerVolumeAttach(igctx[ki], gpvl);
    if (!E) E |= gageQueryItemOn(igctx[ki], gpvl, gageSclValue);
    if (!E) E |= gageUpdate(igctx[ki]);
    if (E) {
      char *err;
      airMopAdd(mop, err = biffGetDone(GAGE), airFree, airMopAlways);
      fprintf(stderr, "%s: trouble %s set-up:\n%s\n", me,
              ikern[ki]->name, err);
      airMopError(mop); return 1;
    }
    ivalAns[ki] = gageAnswerPointer(igctx[ki], gpvl, gageSclValue);
  }

  /* traverse all samples of volume, probing with the interpolating
     kernels, make sure we recover the original values */
  {
    unsigned int xi, yi, zi;
    double pval[INTERP_KERN_NUM], err, rval;
    int pret;
    for (zi=0; zi<sz; zi++) {
      for (yi=0; yi<sy; yi++) {
        for (xi=0; xi<sx; xi++) {
          rval = dscl[xi + sx*(yi + sy*zi)];
          for (ki=0; ki<INTERP_KERN_NUM; ki++) {
            pret = gageProbeSpace(igctx[ki], xi, yi, zi,
                                  AIR_TRUE /* indexSpace */,
                                  AIR_FALSE /* clamp */);
            if (pret) {
              fprintf(stderr, "%s: %s probe error(%d): %s\n", me,
                      ikern[ki]->name, igctx[ki]->errNum, igctx[ki]->errStr);

              airMopError(mop); return 1;
            }
            pval[ki] = *ivalAns[ki];
            err = AIR_ABS(rval - pval[ki]);
            if (err) {
              fprintf(stderr, "%s: interp's [%u,%u,%u] %s probe %f "
                      "!= true %f (err %f)\n", me, xi, yi, zi,
                      ikern[ki]->name, pval[ki], rval, err);
              airMopError(mop); return 1;
            }
          }
        }
      }
    }
  }

  /* set up contexts for non-interpolating (blurring) kernels,
     and their first and second derivatives */
  for (ki=0; ki<BLUR_KERN_NUM; ki++) {
    gagePerVolume *gpvl;
    bgctx[ki] = gageContextNew();
    airMopAdd(mop, bgctx[ki], (airMopper)gageContextNix, airMopAlways);
    gageParmSet(bgctx[ki], gageParmRenormalize, AIR_TRUE);
    gageParmSet(bgctx[ki], gageParmCheckIntegrals, AIR_TRUE);
    gageParmSet(bgctx[ki], gageParmOrientationFromSpacing, AIR_FALSE);
    E = 0;
    if (!E) E |= !(gpvl = gagePerVolumeNew(bgctx[ki], nscl, gageKindScl));
    if (!E) E |= gageKernelSet(bgctx[ki], gageKernel00,
                               bkern[ki], bkparm[ki]);
    if (!E) E |= gageKernelSet(bgctx[ki], gageKernel11,
                               bkernD[ki], bkparm[ki]);
    if (!E) E |= gageKernelSet(bgctx[ki], gageKernel22,
                               bkernDD[ki], bkparm[ki]);
    if (!E) E |= gagePerVolumeAttach(bgctx[ki], gpvl);
    if (!E) E |= gageQueryItemOn(bgctx[ki], gpvl, gageSclValue);
    if (!E) E |= gageQueryItemOn(bgctx[ki], gpvl, gageSclGradVec);
    if (!E) E |= gageQueryItemOn(bgctx[ki], gpvl, gageSclHessian);
    if (!E) E |= gageUpdate(bgctx[ki]);
    if (E) {
      char *err;
      airMopAdd(mop, err = biffGetDone(GAGE), airFree, airMopAlways);
      fprintf(stderr, "%s: trouble %s set-up:\n%s\n", me,
              bkern[ki]->name, err);
      airMopError(mop); return 1;
    }
    fprintf(stderr, "%s radius = %u\n", bkern[ki]->name, bgctx[ki]->radius);
    bvalAns[ki] = gageAnswerPointer(bgctx[ki], gpvl, gageSclValue);
    bgrdAns[ki] = gageAnswerPointer(bgctx[ki], gpvl, gageSclGradVec);
    bhesAns[ki] = gageAnswerPointer(bgctx[ki], gpvl, gageSclHessian);
  }

  {
#define POS_NUM 12
    double xp[POS_NUM], yp[POS_NUM], zp[POS_NUM],
      pos[POS_NUM*POS_NUM*POS_NUM][3], *prbd,
      offs[POS_NUM/2] = {0, 1.22222, 2.444444, 3.777777, 5.88888, 7.55555};
    Nrrd *nprbd, *ncorr;
    unsigned int ii, jj, kk, qlen = 1 + 3 + 9;
    char *corrfn, explain[AIR_STRLEN_LARGE];
    int pret, differ;

    corrfn = testDataPathPrefix("test/probeSclAns.nrrd");
    airMopAdd(mop, corrfn, airFree, airMopAlways);
    ncorr = nrrdNew();
    airMopAdd(mop, ncorr, (airMopper)nrrdNuke, airMopAlways);
    if (nrrdLoad(ncorr, corrfn, NULL)) {
      char *err;
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: trouble reading data \"%s\":\n%s",
              me, corrfn, err);
      airMopError(mop); return 1;
    }
    for (ii=0; ii<POS_NUM/2; ii++) {
      xp[ii] = yp[ii] = zp[ii] = offs[ii];
      xp[POS_NUM-1-ii] = AIR_CAST(double, sx)-1.0-offs[ii];
      yp[POS_NUM-1-ii] = AIR_CAST(double, sy)-1.0-offs[ii];
      zp[POS_NUM-1-ii] = AIR_CAST(double, sz)-1.0-offs[ii];
    }
    for (kk=0; kk<POS_NUM; kk++) {
      for (jj=0; jj<POS_NUM; jj++) {
        for (ii=0; ii<POS_NUM; ii++) {
          ELL_3V_SET(pos[ii + POS_NUM*(jj + POS_NUM*kk)],
                     xp[ii], yp[jj], zp[kk]);
        }
      }
    }
    nprbd = nrrdNew();
    airMopAdd(mop, nprbd, (airMopper)nrrdNuke, airMopAlways);
    if (nrrdMaybeAlloc_va(nprbd, nrrdTypeDouble, 3,
                          AIR_CAST(size_t, qlen),
                          AIR_CAST(size_t, BLUR_KERN_NUM),
                          AIR_CAST(size_t, POS_NUM*POS_NUM*POS_NUM))) {
      char *err;
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: trouble setting up prbd:\n%s", me, err);
      airMopError(mop); return 1;
    }
    prbd = AIR_CAST(double *, nprbd->data);
    for (ii=0; ii<POS_NUM*POS_NUM*POS_NUM; ii++) {
      for (ki=0; ki<BLUR_KERN_NUM; ki++) {
        pret = gageProbeSpace(bgctx[ki], pos[ii][0], pos[ii][1], pos[ii][2],
                              AIR_TRUE /* indexSpace */,
                              AIR_FALSE /* clamp */);
        if (pret) {
          fprintf(stderr, "%s: %s probe error(%d): %s\n", me,
                  bkern[ki]->name, bgctx[ki]->errNum, bgctx[ki]->errStr);
          airMopError(mop); return 1;
        }
        prbd[0 + qlen*(ki + BLUR_KERN_NUM*(ii))] = bvalAns[ki][0];
        ELL_3V_COPY(prbd + 1 + qlen*(ki + BLUR_KERN_NUM*(ii)), bgrdAns[ki]);
        ELL_9V_COPY(prbd + 4 + qlen*(ki + BLUR_KERN_NUM*(ii)), bhesAns[ki]);
      }
    }
    /* HEY: weirdly, so far its only on Windows (and more than 10 times worse
       on Cygwin) this epsilon needs to be larger than zero, and only for the
       radius 6 Gaussian? */
    if (nrrdCompare(ncorr, nprbd, AIR_FALSE /* onlyData */,
                    8.0e-14 /* epsilon */, &differ, explain)) {
      char *err;
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: trouble comparing:\n%s", me, err);
      airMopError(mop); return 1;
    }
    if (differ) {
      fprintf(stderr, "%s: probed values not correct: %s\n", me, explain);
      airMopError(mop); return 1;
    } else {
      fprintf(stderr, "all good\n");
    }
  }

  airMopOkay(mop);
  return 0;
}
예제 #22
0
int
baneGkms_txfMain(int argc, char **argv, char *me, hestParm *hparm) {
  hestOpt *opt = NULL;
  char *out, *perr, err[BIFF_STRLEN];
  Nrrd *nout;
  airArray *mop;
  int pret, E, res[2], vi, gi, step;
  float min[2], max[2], top[2], v0, g0, *data, v, g,
    gwidth, width, mwidth, 
    tvl, tvr, vl, vr, tmp, maxa;

  hestOptAdd(&opt, "r", "Vres Gres", airTypeInt, 2, 2, res, "256 256",
             "resolution of the transfer function in value and gradient "
             "magnitude");
  hestOptAdd(&opt, "min", "Vmin Gmin", airTypeFloat, 2, 2, min, "0.0 0.0",
             "minimum value and grad mag in txf");
  hestOptAdd(&opt, "max", "Vmax Gmax", airTypeFloat, 2, 2, max, NULL,
             "maximum value and grad mag in txf");
  hestOptAdd(&opt, "v", "base value", airTypeFloat, 1, 1, &v0, NULL,
             "data value at which to position bottom of triangle");
  hestOptAdd(&opt, "g", "gthresh", airTypeFloat, 1, 1, &g0, "0.0",
             "lowest grad mag to receive opacity");
  hestOptAdd(&opt, "gw", "gwidth", airTypeFloat, 1, 1, &gwidth, "0.0",
             "range of grad mag values over which to apply threshold "
             "at low gradient magnitudes");
  hestOptAdd(&opt, "top", "Vtop Gtop", airTypeFloat, 2, 2, top, NULL,
             "data value and grad mag at center of top of triangle");
  hestOptAdd(&opt, "w", "value width", airTypeFloat, 1, 1, &width, NULL,
             "range of values to be spanned at top of triangle");
  hestOptAdd(&opt, "mw", "value width", airTypeFloat, 1, 1, &mwidth, "0",
             "range of values to be spanned at BOTTOM of triangle");
  hestOptAdd(&opt, "step", NULL, airTypeInt, 0, 0, &step, NULL,
             "instead of assigning opacity inside a triangular region, "
             "make it more like a step function, in which opacity never "
             "decreases in increasing data value");
  hestOptAdd(&opt, "a", "max opac", airTypeFloat, 1, 1, &maxa, "1.0",
             "highest opacity to assign");
  hestOptAdd(&opt, "o", "opacOut", airTypeString, 1, 1, &out, NULL,
             "output opacity function filename");

  mop = airMopNew();
  airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways);
  USAGE(_baneGkms_txfInfoL);
  PARSE();
  airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways);

  nout = nrrdNew();
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);
  E = 0;
  if (!E) E |= nrrdMaybeAlloc_va(nout, nrrdTypeFloat, 3,
                                 AIR_CAST(size_t, 1),
                                 AIR_CAST(size_t, res[0]),
                                 AIR_CAST(size_t, res[1]));
  if (!E) E |= !(nout->axis[0].label = airStrdup("A"));
  if (!E) E |= !(nout->axis[1].label = airStrdup("gage(scalar:v)"));
  if (!E) nrrdAxisInfoSet_va(nout, nrrdAxisInfoMin,
                             AIR_NAN, (double)min[0], (double)min[1]);
  if (!E) nrrdAxisInfoSet_va(nout, nrrdAxisInfoMax,
                             AIR_NAN, (double)max[0], (double)max[1]);
  if (!E) E |= !(nout->axis[2].label = airStrdup("gage(scalar:gm)"));
  if (E) {
    sprintf(err, "%s: trouble creating opacity function nrrd", me);
    biffMove(BANE, err, NRRD); airMopError(mop); return 1;
  }
  data = (float *)nout->data;
  tvl = top[0] - width/2; 
  tvr = top[0] + width/2;
  mwidth /= 2;
  for (gi=0; gi<res[1]; gi++) {
    g = AIR_CAST(float, NRRD_CELL_POS(min[1], max[1], res[1], gi));
    for (vi=0; vi<res[0]; vi++) {
      v = AIR_CAST(float, NRRD_CELL_POS(min[0], max[0], res[0], vi));
      vl = AIR_CAST(float, AIR_AFFINE(0, g, top[1], v0-mwidth, tvl));
      vr = AIR_CAST(float, AIR_AFFINE(0, g, top[1], v0+mwidth, tvr));
      if (g > top[1]) {
        data[vi + res[0]*gi] = 0;
        continue;
      }
      tmp = AIR_CAST(float, (v - vl)/(0.00001 + vr - vl));
      tmp = 1 - AIR_ABS(2*tmp - 1);
      if (step && v > (vr + vl)/2) {
        tmp = 1;
      }
      tmp = AIR_MAX(0, tmp);
      data[vi + res[0]*gi] = tmp*maxa;
      tmp = AIR_CAST(float, AIR_AFFINE(g0 - gwidth/2, g, g0 + gwidth/2,
                                       0.0, 1.0));
      tmp = AIR_CLAMP(0, tmp, 1);
      data[vi + res[0]*gi] *= tmp;
    }
  }
  if (nrrdSave(out, nout, NULL)) {
    sprintf(err, "%s: trouble saving opacity function", me);
    biffMove(BANE, err, NRRD); airMopError(mop); return 1;
  }
  
  airMopOkay(mop);
  return 0;
}
예제 #23
0
int
miteRenderBegin(miteRender **mrrP, miteUser *muu) {
  static const char me[]="miteRenderBegin";
  gagePerVolume *pvl;
  int E, T, pvlIdx;
  gageQuery queryScl, queryVec, queryTen;
  gageItemSpec isp;
  unsigned int axi, thr;

  if (!(mrrP && muu)) {
    biffAddf(MITE, "%s: got NULL pointer", me);
    return 1;
  }
  if (_miteUserCheck(muu)) {
    biffAddf(MITE, "%s: problem with user-set parameters", me);
    return 1;
  }
  if (!( *mrrP = _miteRenderNew() )) {
    biffAddf(MITE, "%s: couldn't alloc miteRender", me);
    return 1;
  }
  if (_miteNtxfAlphaAdjust(*mrrP, muu)) {
    biffAddf(MITE, "%s: trouble copying and alpha-adjusting txfs", me);
    return 1;
  }

  GAGE_QUERY_RESET(queryScl);
  GAGE_QUERY_RESET(queryVec);
  GAGE_QUERY_RESET(queryTen);
  GAGE_QUERY_RESET((*mrrP)->queryMite);
  for (T=0; T<muu->ntxfNum; T++) {
    for (axi=1; axi<muu->ntxf[T]->dim; axi++) {
      miteVariableParse(&isp, muu->ntxf[T]->axis[axi].label);
      miteQueryAdd(queryScl, queryVec, queryTen, (*mrrP)->queryMite, &isp);
    }
  }
  miteVariableParse((*mrrP)->normalSpec, muu->normalStr);
  miteQueryAdd(queryScl, queryVec, queryTen, (*mrrP)->queryMite,
               (*mrrP)->normalSpec);
  miteShadeSpecParse((*mrrP)->shadeSpec, muu->shadeStr);
  miteShadeSpecQueryAdd(queryScl, queryVec, queryTen, (*mrrP)->queryMite,
                        (*mrrP)->shadeSpec);
  (*mrrP)->queryMiteNonzero = GAGE_QUERY_NONZERO((*mrrP)->queryMite);

  E = 0;
  pvlIdx = 0;
  if (muu->nsin) {
    if (!E) E |= !(pvl = gagePerVolumeNew(muu->gctx0, muu->nsin, gageKindScl));
    if (!E) E |= gageQuerySet(muu->gctx0, pvl, queryScl);
    if (!E) E |= gagePerVolumeAttach(muu->gctx0, pvl);
    if (!E) (*mrrP)->sclPvlIdx = pvlIdx++;
  }
  if (muu->nvin) {
    if (!E) E |= !(pvl = gagePerVolumeNew(muu->gctx0, muu->nvin, gageKindVec));
    if (!E) E |= gageQuerySet(muu->gctx0, pvl, queryVec);
    if (!E) E |= gagePerVolumeAttach(muu->gctx0, pvl);
    if (!E) (*mrrP)->vecPvlIdx = pvlIdx++;
  }
  if (muu->ntin) {
    if (!E) E |= !(pvl = gagePerVolumeNew(muu->gctx0, muu->ntin, tenGageKind));
    if (!E) E |= gageQuerySet(muu->gctx0, pvl, queryTen);
    if (!E) E |= gagePerVolumeAttach(muu->gctx0, pvl);
    if (!E) (*mrrP)->tenPvlIdx = pvlIdx++;
  }
  if (!E) E |= gageKernelSet(muu->gctx0, gageKernel00,
                             muu->ksp[gageKernel00]->kernel,
                             muu->ksp[gageKernel00]->parm);
  if (!E) E |= gageKernelSet(muu->gctx0, gageKernel11,
                             muu->ksp[gageKernel11]->kernel,
                             muu->ksp[gageKernel11]->parm);
  if (!E) E |= gageKernelSet(muu->gctx0, gageKernel22,
                             muu->ksp[gageKernel22]->kernel,
                             muu->ksp[gageKernel22]->parm);
  if (!E) E |= gageUpdate(muu->gctx0);
  if (E) {
    biffMovef(MITE, GAGE, "%s: gage trouble", me);
    return 1;
  }
  fprintf(stderr, "!%s: kernel support = %d^3 samples\n",
          me, 2*muu->gctx0->radius);

  if (nrrdMaybeAlloc_va(muu->nout, mite_nt, 3,
                        AIR_CAST(size_t, 5) /* RGBAZ */ ,
                        AIR_CAST(size_t, muu->hctx->imgSize[0]),
                        AIR_CAST(size_t, muu->hctx->imgSize[1]))) {
    biffMovef(MITE, NRRD, "%s: nrrd trouble", me);
    return 1;
  }
  muu->nout->axis[1].center = nrrdCenterCell;
  muu->nout->axis[1].min = muu->hctx->cam->uRange[0];
  muu->nout->axis[1].max = muu->hctx->cam->uRange[1];
  muu->nout->axis[2].center = nrrdCenterCell;
  muu->nout->axis[2].min = muu->hctx->cam->vRange[0];
  muu->nout->axis[2].max = muu->hctx->cam->vRange[1];

  for (thr=0; thr<muu->hctx->numThreads; thr++) {
    (*mrrP)->tt[thr] = miteThreadNew();
    if (!((*mrrP)->tt[thr])) {
      biffAddf(MITE, "%s: couldn't allocate thread[%d]", me, thr);
      return 1;
    }
    airMopAdd((*mrrP)->rmop, (*mrrP)->tt[thr],
              (airMopper)miteThreadNix, airMopAlways);
  }

  (*mrrP)->time0 = airTime();
  return 0;
}
예제 #24
0
int
tend_helixMain(int argc, char **argv, char *me, hestParm *hparm) {
  int pret;
  hestOpt *hopt = NULL;
  char *perr, *err;
  airArray *mop;

  int size[3], nit;
  Nrrd *nout;
  double R, r, S, bnd, angle, ev[3], ip[3], iq[4], mp[3], mq[4], tmp[9],
    orig[3], i2w[9], rot[9], mf[9], spd[4][3], bge;
  char *outS;

  hestOptAdd(&hopt, "s", "size", airTypeInt, 3, 3, size, NULL, 
             "sizes along fast, medium, and slow axes of the sampled volume, "
             "often called \"X\", \"Y\", and \"Z\".  It is best to use "
             "slightly different sizes here, to expose errors in interpreting "
             "axis ordering (e.g. \"-s 39 40 41\")");
  hestOptAdd(&hopt, "ip", "image orientation", airTypeDouble, 3, 3, ip,
             "0 0 0",
             "quaternion quotient space orientation of image");
  hestOptAdd(&hopt, "mp", "measurement orientation", airTypeDouble, 3, 3, mp,
             "0 0 0",
             "quaternion quotient space orientation of measurement frame");
  hestOptAdd(&hopt, "b", "boundary", airTypeDouble, 1, 1, &bnd, "10",
             "parameter governing how fuzzy the boundary between high and "
             "low anisotropy is. Use \"-b 0\" for no fuzziness");
  hestOptAdd(&hopt, "r", "little radius", airTypeDouble, 1, 1, &r, "30",
             "(minor) radius of cylinder tracing helix");
  hestOptAdd(&hopt, "R", "big radius", airTypeDouble, 1, 1, &R, "50",
             "(major) radius of helical turns");
  hestOptAdd(&hopt, "S", "spacing", airTypeDouble, 1, 1, &S, "100",
             "spacing between turns of helix (along its axis)");
  hestOptAdd(&hopt, "a", "angle", airTypeDouble, 1, 1, &angle, "60",
             "maximal angle of twist of tensors along path.  There is no "
             "twist at helical core of path, and twist increases linearly "
             "with radius around this path.  Positive twist angle with "
             "positive spacing resulting in a right-handed twist around a "
             "right-handed helix. ");
  hestOptAdd(&hopt, "nit", NULL, airTypeInt, 0, 0, &nit, NULL,
             "changes behavior of twist angle as function of distance from "
             "center of helical core: instead of increasing linearly as "
             "describe above, be at a constant angle");
  hestOptAdd(&hopt, "ev", "eigenvalues", airTypeDouble, 3, 3, ev,
             "0.006 0.002 0.001",
             "eigenvalues of tensors (in order) along direction of coil, "
             "circumferential around coil, and radial around coil. ");
  hestOptAdd(&hopt, "bg", "background", airTypeDouble, 1, 1, &bge, "0.5",
             "eigenvalue of isotropic background");
  hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-",
             "output file");

  mop = airMopNew();
  airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways);
  USAGE(_tend_helixInfoL);
  JUSTPARSE();
  airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways);

  nout = nrrdNew();
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);
  if (nrrdMaybeAlloc_va(nout, nrrdTypeFloat, 4,
                        AIR_CAST(size_t, 7),
                        AIR_CAST(size_t, size[0]),
                        AIR_CAST(size_t, size[1]),
                        AIR_CAST(size_t, size[2]))) {
    airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: trouble allocating output:\n%s\n", me, err);
    airMopError(mop); return 1;
  }

  ELL_4V_SET(iq, 1.0, ip[0], ip[1], ip[2]);
  ell_q_to_3m_d(rot, iq);
  ELL_3V_SET(orig,
             -2*R + 2*R/size[0],
             -2*R + 2*R/size[1],
             -2*R + 2*R/size[2]);
  ELL_3M_ZERO_SET(i2w);
  ELL_3M_DIAG_SET(i2w, 4*R/size[0], 4*R/size[1], 4*R/size[2]);
  ELL_3MV_MUL(tmp, rot, orig);
  ELL_3V_COPY(orig, tmp);
  ELL_3M_MUL(tmp, rot, i2w);
  ELL_3M_COPY(i2w, tmp);
  ELL_4V_SET(mq, 1.0, mp[0], mp[1], mp[2]);
  ell_q_to_3m_d(mf, mq);
  tend_helixDoit(nout, bnd,
                 orig, i2w, mf,
                 r, R, S, angle*AIR_PI/180, !nit, ev, bge);
  nrrdSpaceSet(nout, nrrdSpaceRightAnteriorSuperior);
  nrrdSpaceOriginSet(nout, orig);
  ELL_3V_SET(spd[0], AIR_NAN, AIR_NAN, AIR_NAN);
  ELL_3MV_COL0_GET(spd[1], i2w);
  ELL_3MV_COL1_GET(spd[2], i2w);
  ELL_3MV_COL2_GET(spd[3], i2w);
  nrrdAxisInfoSet_va(nout, nrrdAxisInfoSpaceDirection,
                     spd[0], spd[1], spd[2], spd[3]);
  nrrdAxisInfoSet_va(nout, nrrdAxisInfoCenter,
                     nrrdCenterUnknown, nrrdCenterCell,
                     nrrdCenterCell, nrrdCenterCell);
  nrrdAxisInfoSet_va(nout, nrrdAxisInfoKind,
                     nrrdKind3DMaskedSymMatrix, nrrdKindSpace,
                     nrrdKindSpace, nrrdKindSpace);
  nout->measurementFrame[0][0] = mf[0];
  nout->measurementFrame[1][0] = mf[1];
  nout->measurementFrame[2][0] = mf[2];
  nout->measurementFrame[0][1] = mf[3];
  nout->measurementFrame[1][1] = mf[4];
  nout->measurementFrame[2][1] = mf[5];
  nout->measurementFrame[0][2] = mf[6];
  nout->measurementFrame[1][2] = mf[7];
  nout->measurementFrame[2][2] = mf[8];

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

  airMopOkay(mop);
  return 0;
}
예제 #25
0
파일: acrop.c 프로젝트: BRAINSia/teem
int
unrrdu_acropMain(int argc, const char **argv, const char *me,
                 hestParm *hparm) {
  hestOpt *opt = NULL;
  char *out, *err;
  Nrrd *nin, *nout;
  int pret;
  airArray *mop;

  size_t min[NRRD_DIM_MAX], max[NRRD_DIM_MAX];
  unsigned int *axes, axesLen;
  double frac;
  int measr, offset;
  Nrrd *nbounds;
  char *boundsSave;

  hestOptAdd(&opt, "a,axes", "ax0", airTypeUInt, 0, -1, &axes, "",
             "the axes (if any) that should NOT be cropped", &axesLen);
  hestOptAdd(&opt, "m,measure", "measr", airTypeEnum, 1, 1, &measr, NULL,
             "How to measure slices (along axes to crop) as scalars, "
             "to form 1-D array analyzed to determine cropping extent. "
             "All the measures from \"unu project\" can be used, but "
             "those that make more sense here include:\n "
             "\b\bo \"max\", \"mean\", \"median\", "
             "\"variance\": (self-explanatory)\n "
             "\b\bo \"stdv\": standard deviation\n "
             "\b\bo \"cov\": coefficient of variation\n "
             "\b\bo \"product\", \"sum\": product or sum of all values\n "
             "\b\bo \"L1\", \"L2\", \"NL2\", \"RMS\", \"Linf\": "
             "different norms.", NULL, nrrdMeasure);
  hestOptAdd(&opt, "f,frac", "frac", airTypeDouble, 1, 1, &frac, "0.1",
             "threshold of cumulative sum of 1-D array at which to crop. "
             "Needs to be in interval [0.0,0.5).");
  hestOptAdd(&opt, "off,offset", "offset", airTypeInt, 1, 1, &offset, "1",
             "how much to offset the numerically determined cropping; "
             "positive offsets means expanding the interval of kept "
             "indices (less cropping)");
  hestOptAdd(&opt, "b,bounds", "filename", airTypeString, 1, 1,
             &boundsSave, "",
             "if a filename is given here, the automatically determined "
             "min and max bounds for cropping are saved to this file "
             "as a 2-D array; first scanline is for -min, second is for -max. "
             "Unfortunately nothing using the \"m\" and \"M\" semantics "
             "(above) can currently be saved in the bounds file.");
  OPT_ADD_NIN(nin, "input nrrd");
  OPT_ADD_NOUT(out, "output nrrd");

  mop = airMopNew();
  airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways);

  USAGE(_unrrdu_acropInfoL);
  PARSE();
  airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways);

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

  if (nrrdCropAuto(nout, nin, min, max,
                   axes, axesLen,
                   measr, frac, offset)) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: error cropping nrrd:\n%s", me, err);
    airMopError(mop);
    return 1;
  }
  if (airStrlen(boundsSave)) {
    unsigned int axi;
    airULLong *bounds;
    nbounds = nrrdNew();
    airMopAdd(mop, nbounds, (airMopper)nrrdNuke, airMopAlways);
    if (nrrdMaybeAlloc_va(nbounds, nrrdTypeULLong, 2,
                          AIR_CAST(airULLong, nin->dim),
                          AIR_CAST(airULLong, 2))) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: error allocating cropping bounds array:\n%s",
              me, err);
      airMopError(mop);
      return 1;
    }
    bounds = AIR_CAST(airULLong*, nbounds->data);
    for (axi=0; axi<nin->dim; axi++) {
      bounds[axi + 0*(nin->dim)] = AIR_CAST(airULLong, min[axi]);
      bounds[axi + 1*(nin->dim)] = AIR_CAST(airULLong, max[axi]);
    }
    if (nrrdSave(boundsSave, nbounds, NULL)) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: error saving cropping bounds array:\n%s",
              me, err);
      airMopError(mop);
      return 1;
    }
  }

  SAVE(out, nout, NULL);

  airMopOkay(mop);
  return 0;
}
예제 #26
0
파일: emap.c 프로젝트: BRAINSia/teem
int
main(int argc, const char *argv[]) {
    hestOpt *hopt=NULL;
    hestParm *hparm;
    Nrrd *nlight, *nmap, *ndebug;
    const char *me;
    char *outS, *errS, *debugS;
    airArray *mop;
    float amb[3], *linfo, *debug, *map, vscl;
    unsigned li, ui, vi;
    int qn, bits, method, doerr;
    limnLight *light;
    limnCamera *cam;
    double u, v, r, w, V2W[9], diff, WW[3], VV[3];

    me = argv[0];
    mop = airMopNew();
    hparm = hestParmNew();
    airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways);
    hparm->elideSingleEmptyStringDefault = AIR_TRUE;
    cam = limnCameraNew();
    airMopAdd(mop, cam, (airMopper)limnCameraNix, airMopAlways);
    hestOptAdd(&hopt, "i", "nlight", airTypeOther, 1, 1, &nlight, NULL,
               "input nrrd containing light information",
               NULL, NULL, nrrdHestNrrd);
    hestOptAdd(&hopt, "b", "# bits", airTypeInt, 1, 1, &bits, "16",
               "number of bits to use for normal quantization, "
               "between 8 and 16 inclusive. ");
    hestOptAdd(&hopt, "amb", "ambient RGB", airTypeFloat, 3, 3, amb, "0 0 0",
               "ambient light color");
    hestOptAdd(&hopt, "fr", "from point", airTypeDouble, 3, 3, cam->from,"1 0 0",
               "position of camera, used to determine view vector");
    hestOptAdd(&hopt, "at", "at point", airTypeDouble, 3, 3, cam->at, "0 0 0",
               "camera look-at point, used to determine view vector");
    hestOptAdd(&hopt, "up", "up vector", airTypeDouble, 3, 3, cam->up, "0 0 1",
               "camera pseudo-up vector, used to determine view coordinates");
    hestOptAdd(&hopt, "rh", NULL, airTypeInt, 0, 0, &(cam->rightHanded), NULL,
               "use a right-handed UVN frame (V points down)");
    hestOptAdd(&hopt, "vs", "view-dir scaling", airTypeFloat, 1, 1, &vscl, "1",
               "scaling along view-direction of location of "
               "view-space lights");
    hestOptAdd(&hopt, "o", "filename", airTypeString, 1, 1, &outS, NULL,
               "file to write output envmap to");
    hestOptAdd(&hopt, "d", "filename", airTypeString, 1, 1, &debugS, "",
               "Use this option to save out (to the given filename) a rendering "
               "of the front (on the left) and back (on the right) of a sphere "
               "as shaded with the new environment map.  U increases "
               "right-ward, V increases downward.  The back sphere half is "
               "rendered as though the front half was removed");
    hestOptAdd(&hopt, "err", NULL, airTypeInt, 0, 0, &doerr, NULL,
               "If using \"-d\", make the image represent the error between the "
               "real and quantized vector");
    hestParseOrDie(hopt, argc-1, argv+1, hparm, me, emapInfo,
                   AIR_TRUE, AIR_TRUE, AIR_TRUE);
    airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways);
    airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways);

    switch(bits) {
    case 16:
        method = limnQN16octa;
        break;
    case 15:
        method = limnQN15octa;
        break;
    case 14:
        method = limnQN14octa;
        break;
    case 13:
        method = limnQN13octa;
        break;
    case 12:
        method = limnQN12octa;
        break;
    case 11:
        method = limnQN11octa;
        break;
    case 10:
        method = limnQN10octa;
        break;
    case 9:
        method = limnQN9octa;
        break;
    case 8:
        method = limnQN8octa;
        break;
    default:
        fprintf(stderr, "%s: requested #bits (%d) not in valid range [8,16]\n",
                me, bits);
        airMopError(mop);
        return 1;
    }

    if (!(nrrdTypeFloat == nlight->type &&
            2 == nlight->dim &&
            7 == nlight->axis[0].size &&
            LIMN_LIGHT_NUM >= nlight->axis[1].size)) {
        fprintf(stderr, "%s: nlight isn't valid format for light specification, "
                "must be: float type, 2-dimensional, 7\tx\tN size, N <= %d\n",
                me, LIMN_LIGHT_NUM);
        airMopError(mop);
        return 1;
    }

    cam->neer = -0.000000001;
    cam->dist = 0;
    cam->faar = 0.0000000001;
    cam->atRelative = AIR_TRUE;
    if (limnCameraUpdate(cam)) {
        airMopAdd(mop, errS = biffGetDone(LIMN), airFree, airMopAlways);
        fprintf(stderr, "%s: problem with camera:\n%s\n", me, errS);
        airMopError(mop);
        return 1;
    }

    light = limnLightNew();
    airMopAdd(mop, light, (airMopper)limnLightNix, airMopAlways);
    limnLightAmbientSet(light, amb[0], amb[1], amb[2]);
    for (li=0; li<nlight->axis[1].size; li++) {
        int vsp;
        float lxyz[3];
        linfo = (float *)(nlight->data) + 7*li;
        vsp = !!linfo[0];
        ELL_3V_COPY(lxyz, linfo + 4);
        if (vsp) {
            lxyz[2] *= vscl;
        }
        limnLightSet(light, li, vsp,
                     linfo[1], linfo[2], linfo[3], lxyz[0], lxyz[1], lxyz[2]);
    }
    if (limnLightUpdate(light, cam)) {
        airMopAdd(mop, errS = biffGetDone(LIMN), airFree, airMopAlways);
        fprintf(stderr, "%s: problem with lights:\n%s\n", me, errS);
        airMopError(mop);
        return 1;
    }

    nmap=nrrdNew();
    airMopAdd(mop, nmap, (airMopper)nrrdNuke, airMopAlways);
    if (limnEnvMapFill(nmap, limnLightDiffuseCB, method, light)) {
        airMopAdd(mop, errS = biffGetDone(LIMN), airFree, airMopAlways);
        fprintf(stderr, "%s: problem making environment map:\n%s\n", me, errS);
        airMopError(mop);
        return 1;
    }
    map = (float *)nmap->data;

    if (nrrdSave(outS, nmap, NULL)) {
        fprintf(stderr, "%s: trouble:\n%s", me, errS = biffGetDone(NRRD));
        free(errS);
        return 1;
    }

    if (airStrlen(debugS)) {
        ELL_34M_EXTRACT(V2W, cam->V2W);
        ndebug = nrrdNew();
        nrrdMaybeAlloc_va(ndebug, nrrdTypeFloat, 3,
                          AIR_CAST(size_t, 3),
                          AIR_CAST(size_t, 1024),
                          AIR_CAST(size_t, 512));
        airMopAdd(mop, ndebug, (airMopper)nrrdNuke, airMopAlways);
        debug = (float *)ndebug->data;
        for (vi=0; vi<=511; vi++) {
            v = AIR_AFFINE(0, vi, 511, -0.999, 0.999);
            for (ui=0; ui<=511; ui++) {
                u = AIR_AFFINE(0, ui, 511, -0.999, 0.999);
                r = sqrt(u*u + v*v);
                if (r > 1) {
                    continue;
                }
                w = sqrt(1 - r*r);

                /* first, the near side of the sphere */
                ELL_3V_SET(VV, u, v, -w);
                ELL_3MV_MUL(WW, V2W, VV);
                qn = limnVtoQN_d[method](WW);
                if (doerr) {
                    limnQNtoV_d[method](VV, qn);
                    ELL_3V_SUB(WW, WW, VV);
                    diff = ELL_3V_LEN(WW);
                    ELL_3V_SET_TT(debug + 3*(ui + 1024*vi), float,
                                  diff, diff, diff);
                } else {
                    ELL_3V_COPY(debug + 3*(ui + 1024*vi), map + 3*qn);
                }

                /* second, the far side of the sphere */
                ELL_3V_SET(VV, u, v, w);
                ELL_3MV_MUL(WW, V2W, VV);
                qn = limnVtoQN_d[method](WW);
                if (doerr) {
                    limnQNtoV_d[method](VV, qn);
                    ELL_3V_SUB(WW, WW, VV);
                    diff = ELL_3V_LEN(WW);
                    ELL_3V_SET_TT(debug + 3*(ui + 512 + 1024*vi), float,
                                  diff, diff, diff);
                } else {
                    ELL_3V_COPY(debug + 3*(ui + 512 + 1024*vi), map + 3*qn);
                }
            }
        }
예제 #27
0
int
doit(Nrrd *nout, Nrrd *nin, int smart, float amount) {
  char me[]="doit", err[BIFF_STRLEN];
  Nrrd *nproj[3];
  airArray *mop;
  int axis, srl, sap, ssi, E, margin, which;
  size_t min[3];

  if (!(nout && nin)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NINSPECT, err);
    return 1;
  }
  if (!(3 == nin->dim)) {
    sprintf(err, "%s: given nrrd has dimension %d, not 3\n", me, nin->dim);
    biffAdd(NINSPECT, err);
    return 1;
  }
  
  mop = airMopNew();
  airMopAdd(mop, nproj[0]=nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  airMopAdd(mop, nproj[1]=nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  airMopAdd(mop, nproj[2]=nrrdNew(), (airMopper)nrrdNuke, airMopAlways);

  /* how much space to put between and around the projections */
  margin = 6;

  /* do projections for each axis, with some progress indication to sterr */
  for (axis=0; axis<=2; axis++) {
    fprintf(stderr, "%s: doing axis %d projections ... ", me, axis);
    fflush(stderr);
    if (ninspect_proj(nproj[axis], nin, axis, smart, amount)) {
      fprintf(stderr, "ERROR\n");
      sprintf(err, "%s: trouble doing projections for axis %d", me, axis);
      biffAdd(NINSPECT, err);
      airMopError(mop); return 1;
    }
    fprintf(stderr, "done\n");
  }

  if (nrrdSpaceRightAnteriorSuperior == nin->space) {
    if (fixproj(nproj, nin)) {
      fprintf(stderr, "ERROR\n");
      sprintf(err, "%s: trouble orienting projections", me);
      biffAdd(NINSPECT, err);
      airMopError(mop); return 1;
    }
  }
  srl = nproj[1]->axis[0+1].size;
  sap = nproj[0]->axis[0+1].size;
  ssi = nproj[1]->axis[1+1].size;

  /* allocate output as 8-bit color image.  We know output type is
     nrrdTypeUChar because ninspect_proj finishes each projection
     with nrrdQuantize to 8-bits */
  if (nrrdMaybeAlloc_va(nout, nrrdTypeUChar, 3,
                        AIR_CAST(size_t, 3),
                        AIR_CAST(size_t, srl + 3*margin + sap),
                        AIR_CAST(size_t, ssi + 3*margin + sap))) {
    sprintf(err, "%s: couldn't allocate output", me);
    biffMove(NINSPECT, err, NRRD);
    airMopError(mop); return 1;
  }

  min[0] = 0; 
  E = 0;
  which = 0;
  if (!E) { min[1] = margin; min[2] = margin; which = 1; }
  if (!E) E |= nrrdInset(nout, nout, nproj[1], min);
  if (!E) { min[1] = margin; min[2] = 2*margin + ssi; which = 2; }
  if (!E) E |= nrrdInset(nout, nout, nproj[2], min);
  if (!E) { min[1] = 2*margin + srl; min[2] = margin; which = 3; }
  if (!E) E |= nrrdInset(nout, nout, nproj[0], min);
  if (E) {
    sprintf(err, "%s: couldn't composite output (which = %d)", 
            me, which);
    biffMove(NINSPECT, err, NRRD);
    airMopError(mop); return 1;
  }

  airMopOkay(mop);
  return 0;
}
예제 #28
0
파일: cam.c 프로젝트: BRAINSia/teem
/*
******** limnCameraPathMake
**
** uses limnSplines to do camera paths based on key-frames
**
** output: cameras at all "numFrames" frames are set in the
** PRE-ALLOCATED array of output cameras, "cam".
**
** input:
** keycam: array of keyframe cameras
** time: times associated with the key frames
** ---> both of these arrays are length "numKeys" <---
** trackWhat: takes values from the limnCameraPathTrack* enum
** quatType: spline to control camera orientations. This is needed for
**          tracking at or from, but not needed for limnCameraPathTrackBoth.
**          This is the only limnSplineTypeSpec* argument that can be NULL.
** posType: spline to control whichever of from, at, and up are needed for
**          the given style of tracking.
** distType: spline to control neer, faar, dist: positions of near clipping,
**          far clipping, and image plane, as well as the
**          distance between from and at (which is used if not doing
**          limnCameraPathTrackBoth)
** viewType: spline to control fov (and aspect, if you're crazy)
**
** NOTE: The "atRelative", "orthographic", and "rightHanded" fields
** are copied from keycam[0] into all output cam[i], but you still need
** to correctly set them for all keycam[i] for limnCameraUpdate to work
** as expected.  Also, for the sake of simplicity, this function only works
** with fov and aspect, instead of {u,v}Range, and hence both "fov" and
** "aspect" need to set in *all* the keycams, even if neither of them
** ever changes!
*/
int
limnCameraPathMake(limnCamera *cam, int numFrames,
                   limnCamera *keycam, double *time, int numKeys,
                   int trackWhat,
                   limnSplineTypeSpec *quatType,
                   limnSplineTypeSpec *posType,
                   limnSplineTypeSpec *distType,
                   limnSplineTypeSpec *viewType) {
  static const char me[]="limnCameraPathMake";
  char which[AIR_STRLEN_MED];
  airArray *mop;
  Nrrd *nquat, *nfrom, *natpt, *nupvc, *ndist, *nfova, *ntime, *nsample;
  double fratVec[3], *quat, *from, *atpt, *upvc, *dist, *fova,
    W2V[9], N[3], fratDist;
  limnSpline *timeSpline, *quatSpline, *fromSpline, *atptSpline, *upvcSpline,
    *distSpline, *fovaSpline;
  limnSplineTypeSpec *timeType;
  int ii, E;

  if (!( cam && keycam && time && posType && distType && viewType )) {
    biffAddf(LIMN, "%s: got NULL pointer", me);
    return 1;
  }
  if (!( AIR_IN_OP(limnCameraPathTrackUnknown, trackWhat,
                   limnCameraPathTrackLast) )) {
    biffAddf(LIMN, "%s: trackWhat %d not in valid range [%d,%d]", me,
             trackWhat, limnCameraPathTrackUnknown+1,
             limnCameraPathTrackLast-1);
    return 1;
  }
  if (limnCameraPathTrackBoth != trackWhat && !quatType) {
    biffAddf(LIMN, "%s: need the quaternion limnSplineTypeSpec if not "
             "doing trackBoth", me);
    return 1;
  }

  /* create and allocate nrrds.  For the time being, we're allocating
     more different nrrds, and filling their contents, than we need
     to-- nquat is not needed if we're doing limnCameraPathTrackBoth,
     for example.  However, we do make an effort to only do the spline
     evaluation on the things we actually need to know. */
  mop = airMopNew();
  airMopAdd(mop, nquat = nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  airMopAdd(mop, nfrom = nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  airMopAdd(mop, natpt = nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  airMopAdd(mop, nupvc = nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  airMopAdd(mop, ndist = nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  airMopAdd(mop, nfova = nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  airMopAdd(mop, ntime = nrrdNew(), (airMopper)nrrdNix, airMopAlways);
  if (nrrdWrap_va(ntime, time, nrrdTypeDouble, 1,
                  AIR_CAST(size_t, numKeys))) {
    biffMovef(LIMN, NRRD, "%s: trouble wrapping time values", me);
    airMopError(mop); return 1;
  }
  airMopAdd(mop, nsample = nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  timeType = limnSplineTypeSpecNew(limnSplineTypeTimeWarp);
  airMopAdd(mop, timeType, (airMopper)limnSplineTypeSpecNix, airMopAlways);
  if (nrrdMaybeAlloc_va(nquat, nrrdTypeDouble, 2,
                        AIR_CAST(size_t, 4), AIR_CAST(size_t, numKeys))
      || nrrdMaybeAlloc_va(nfrom, nrrdTypeDouble, 2,
                           AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys))
      || nrrdMaybeAlloc_va(natpt, nrrdTypeDouble, 2,
                           AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys))
      || nrrdMaybeAlloc_va(nupvc, nrrdTypeDouble, 2,
                           AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys))
      || nrrdMaybeAlloc_va(ndist, nrrdTypeDouble, 2,
                           AIR_CAST(size_t, 4), AIR_CAST(size_t, numKeys))
      || nrrdMaybeAlloc_va(nfova, nrrdTypeDouble, 2,
                           AIR_CAST(size_t, 2), AIR_CAST(size_t, numKeys))) {
    biffMovef(LIMN, NRRD, "%s: couldn't allocate buffer nrrds", me);
    airMopError(mop); return 1;
  }
  quat = (double*)(nquat->data);
  from = (double*)(nfrom->data);
  atpt = (double*)(natpt->data);
  upvc = (double*)(nupvc->data);
  dist = (double*)(ndist->data);
  fova = (double*)(nfova->data);

  /* check cameras, and put camera information into nrrds */
  for (ii=0; ii<numKeys; ii++) {
    if (limnCameraUpdate(keycam + ii)) {
      biffAddf(LIMN, "%s: trouble with camera at keyframe %d\n", me, ii);
      airMopError(mop); return 1;
    }
    if (!( AIR_EXISTS(keycam[ii].fov) && AIR_EXISTS(keycam[ii].aspect) )) {
      biffAddf(LIMN, "%s: fov, aspect not both defined on keyframe %d",
               me, ii);
      airMopError(mop); return 1;
    }
    ell_4m_to_q_d(quat + 4*ii, keycam[ii].W2V);
    if (ii) {
      if (0 > ELL_4V_DOT(quat + 4*ii, quat + 4*(ii-1))) {
        ELL_4V_SCALE(quat + 4*ii, -1, quat + 4*ii);
      }
    }
    ELL_3V_COPY(from + 3*ii, keycam[ii].from);
    ELL_3V_COPY(atpt + 3*ii, keycam[ii].at);
    ELL_3V_COPY(upvc + 3*ii, keycam[ii].up);
    ELL_3V_SUB(fratVec, keycam[ii].from, keycam[ii].at);
    fratDist = ELL_3V_LEN(fratVec);
    ELL_4V_SET(dist + 4*ii, fratDist,
               keycam[ii].neer, keycam[ii].dist, keycam[ii].faar);
    ELL_2V_SET(fova + 2*ii, keycam[ii].fov, keycam[ii].aspect);
  }

  /* create splines from nrrds */
  if (!( (strcpy(which, "quaternion"), quatSpline =
          limnSplineCleverNew(nquat, limnSplineInfoQuaternion, quatType))
         && (strcpy(which, "from point"), fromSpline =
             limnSplineCleverNew(nfrom, limnSplineInfo3Vector, posType))
         && (strcpy(which, "at point"), atptSpline =
             limnSplineCleverNew(natpt, limnSplineInfo3Vector, posType))
         && (strcpy(which, "up vector"), upvcSpline =
             limnSplineCleverNew(nupvc, limnSplineInfo3Vector, posType))
         && (strcpy(which, "plane distances"), distSpline =
             limnSplineCleverNew(ndist, limnSplineInfo4Vector, distType))
         && (strcpy(which, "field-of-view"), fovaSpline =
             limnSplineCleverNew(nfova, limnSplineInfo2Vector, viewType))
         && (strcpy(which, "time warp"), timeSpline =
             limnSplineCleverNew(ntime, limnSplineInfoScalar, timeType)) )) {
    biffAddf(LIMN, "%s: trouble creating %s spline", me, which);
    airMopError(mop); return 1;
  }
  airMopAdd(mop, quatSpline, (airMopper)limnSplineNix, airMopAlways);
  airMopAdd(mop, fromSpline, (airMopper)limnSplineNix, airMopAlways);
  airMopAdd(mop, atptSpline, (airMopper)limnSplineNix, airMopAlways);
  airMopAdd(mop, upvcSpline, (airMopper)limnSplineNix, airMopAlways);
  airMopAdd(mop, distSpline, (airMopper)limnSplineNix, airMopAlways);
  airMopAdd(mop, fovaSpline, (airMopper)limnSplineNix, airMopAlways);
  airMopAdd(mop, timeSpline, (airMopper)limnSplineNix, airMopAlways);

  /* evaluate splines */
  E = AIR_FALSE;
  if (!E) E |= limnSplineSample(nsample, timeSpline,
                                limnSplineMinT(timeSpline), numFrames,
                                limnSplineMaxT(timeSpline));
  quat = NULL;
  from = NULL;
  atpt = NULL;
  upvc = NULL;
  switch(trackWhat) {
  case limnCameraPathTrackAt:
    if (!E) E |= limnSplineNrrdEvaluate(natpt, atptSpline, nsample);
    if (!E) atpt = (double*)(natpt->data);
    if (!E) E |= limnSplineNrrdEvaluate(nquat, quatSpline, nsample);
    if (!E) quat = (double*)(nquat->data);
    break;
  case limnCameraPathTrackFrom:
    if (!E) E |= limnSplineNrrdEvaluate(nfrom, fromSpline, nsample);
    if (!E) from = (double*)(nfrom->data);
    if (!E) E |= limnSplineNrrdEvaluate(nquat, quatSpline, nsample);
    if (!E) quat = (double*)(nquat->data);
    break;
  case limnCameraPathTrackBoth:
    if (!E) E |= limnSplineNrrdEvaluate(nfrom, fromSpline, nsample);
    if (!E) from = (double*)(nfrom->data);
    if (!E) E |= limnSplineNrrdEvaluate(natpt, atptSpline, nsample);
    if (!E) atpt = (double*)(natpt->data);
    if (!E) E |= limnSplineNrrdEvaluate(nupvc, upvcSpline, nsample);
    if (!E) upvc = (double*)(nupvc->data);
    break;
  }
  dist = NULL;
  if (!E) E |= limnSplineNrrdEvaluate(ndist, distSpline, nsample);
  if (!E) dist = (double*)(ndist->data);
  fova = NULL;
  if (!E) E |= limnSplineNrrdEvaluate(nfova, fovaSpline, nsample);
  if (!E) fova = (double*)(nfova->data);
  if (E) {
    biffAddf(LIMN, "%s: trouble evaluating splines", me);
    airMopError(mop); return 1;
  }

  /* copy information from nrrds back into cameras */
  for (ii=0; ii<numFrames; ii++) {
    cam[ii].atRelative = keycam[0].atRelative;
    cam[ii].orthographic = keycam[0].orthographic;
    cam[ii].rightHanded = keycam[0].rightHanded;
    if (limnCameraPathTrackBoth == trackWhat) {
      ELL_3V_COPY(cam[ii].from, from + 3*ii);
      ELL_3V_COPY(cam[ii].at, atpt + 3*ii);
      ELL_3V_COPY(cam[ii].up, upvc + 3*ii);
    } else {
      fratDist = (dist + 4*ii)[0];
      ell_q_to_3m_d(W2V, quat + 4*ii);
      ELL_3MV_ROW1_GET(cam[ii].up, W2V);
      if (cam[ii].rightHanded) {
        ELL_3V_SCALE(cam[ii].up, -1, cam[ii].up);
      }
      ELL_3MV_ROW2_GET(N, W2V);
      if (limnCameraPathTrackFrom == trackWhat) {
        ELL_3V_COPY(cam[ii].from, from + 3*ii);
        ELL_3V_SCALE_ADD2(cam[ii].at, 1.0, cam[ii].from, fratDist, N);
      } else {
        ELL_3V_COPY(cam[ii].at, atpt + 3*ii);
        ELL_3V_SCALE_ADD2(cam[ii].from, 1.0, cam[ii].at, -fratDist, N);
      }
    }
    cam[ii].neer = (dist + 4*ii)[1];
    cam[ii].dist = (dist + 4*ii)[2];
    cam[ii].faar = (dist + 4*ii)[3];
    cam[ii].fov = (fova + 2*ii)[0];
    cam[ii].aspect = (fova + 2*ii)[1];
    if (limnCameraUpdate(cam + ii)) {
      biffAddf(LIMN, "%s: trouble with output camera %d\n", me, ii);
      airMopError(mop); return 1;
    }
  }

  airMopOkay(mop);
  return 0;
}
예제 #29
0
파일: tg.c 프로젝트: BRAINSia/teem
int
main(int argc, const char *argv[]) {
  const char *me;
  char *err, *outS;
  hestOpt *hopt=NULL;
  airArray *mop;

  int xi, yi, zi, samp;
  float *tdata;
  double clp[2], xyz[3], q[4], len;
  double mD[9], mRF[9], mRI[9], mT[9];
  Nrrd *nten;
  mop = airMopNew();

  me = argv[0];
  hestOptAdd(&hopt, "n", "# samples", airTypeInt, 1, 1, &samp, "4",
             "number of samples along each edge of cube");
  hestOptAdd(&hopt, "c", "cl cp", airTypeDouble, 2, 2, clp, NULL,
             "shape of tensor to use; \"cl\" and \"cp\" are cl1 "
             "and cp1 values, both in [0.0,1.0]");
  hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-",
             "output file to save tensors into");
  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);

  nten = nrrdNew();
  airMopAdd(mop, nten, (airMopper)nrrdNuke, airMopAlways);

  _clp2xyz(xyz, clp);
  fprintf(stderr, "%s: want evals = %g %g %g\n", me, xyz[0], xyz[1], xyz[2]);

  if (nrrdMaybeAlloc_va(nten, nrrdTypeFloat, 4,
                        AIR_CAST(size_t, 7),
                        AIR_CAST(size_t, samp),
                        AIR_CAST(size_t, samp),
                        AIR_CAST(size_t, samp))) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't allocate output:\n%s\n", me, err);
    airMopError(mop);
    return 1;
  }
  ELL_3M_IDENTITY_SET(mD);
  ELL_3M_DIAG_SET(mD, xyz[0], xyz[1], xyz[2]);
  tdata = (float*)nten->data;
  for (zi=0; zi<samp; zi++) {
    for (yi=0; yi<samp; yi++) {
      for (xi=0; xi<samp; xi++) {
        q[0] = 1.0;
        q[1] = AIR_AFFINE(-0.5, (float)xi, samp-0.5, -1, 1);
        q[2] = AIR_AFFINE(-0.5, (float)yi, samp-0.5, -1, 1);
        q[3] = AIR_AFFINE(-0.5, (float)zi, samp-0.5, -1, 1);
        len = ELL_4V_LEN(q);
        ELL_4V_SCALE(q, 1.0/len, q);
        washQtoM3(mRF, q);
        ELL_3M_TRANSPOSE(mRI, mRF);

        ELL_3M_IDENTITY_SET(mT);
        ell_3m_post_mul_d(mT, mRI);
        ell_3m_post_mul_d(mT, mD);
        ell_3m_post_mul_d(mT, mRF);

        tdata[0] = 1.0;
        TEN_M2T(tdata, mT);
        tdata += 7;
      }
    }
  }

  if (nrrdSave(outS, nten, NULL)) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't save output:\n%s\n", me, err);
    airMopError(mop);
    return 1;
  }
  airMopOkay(mop);
  return 0;
}
예제 #30
0
int
main(int argc, char *argv[]) {
  char *me;
  hestOpt *hopt=NULL;
  airArray *mop;

  char *errS, *outS, *covarS;
  Nrrd *_nodf, *nvec, *nhist, *ncovar;
  int bins;
  size_t size[NRRD_DIM_MAX];
  float min;
  
  mop = airMopNew();
  me = argv[0];

  hestOptAdd(&hopt, "i", "odf", airTypeOther, 1, 1, &_nodf, NULL,
             "ODF volume to analyze", NULL, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "v", "odf", airTypeOther, 1, 1, &nvec, NULL,
             "list of vectors by which odf is sampled",
             NULL, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "min", "min", airTypeFloat, 1, 1, &min, "0.0",
             "ODF values below this are ignored, and per-voxel ODF is "
             "normalized to have sum 1.0.  Use \"nan\" to subtract out "
             "the per-voxel min.");
  hestOptAdd(&hopt, "b", "bins", airTypeInt, 1, 1, &bins, "128",
             "number of bins in histograms");
  hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-",
             "output file");
  hestOptAdd(&hopt, "co", "covariance out", airTypeString, 1, 1,
             &covarS, "covar.nrrd", "covariance output file");
  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 (!( nrrdTypeFloat == nvec->type )) {
    fprintf(stderr, "%s vector type (%s) not %s\n", me,
            airEnumStr(nrrdType, nvec->type),
            airEnumStr(nrrdType, nrrdTypeFloat));
    airMopError(mop); return 1;
  }
  if (!( 2 == nvec->dim && 3 == nvec->axis[0].size )) {
    fprintf(stderr, "%s: nvec not a 2-D 3-by-N array\n", me);
    airMopError(mop); return 1;
  }
  if (!( _nodf->axis[0].size == nvec->axis[1].size )) {
    fprintf(stderr, "%s mismatch of _nodf->axis[0].size (%d) vs. "
            "nvec->axis[1].size (%d)\n", me, 
            (int)_nodf->axis[0].size, (int)nvec->axis[1].size);
    airMopError(mop); return 1;
  }
  nrrdAxisInfoGet_nva(_nodf, nrrdAxisInfoSize, size);
  size[0] = bins;
  nhist = nrrdNew();
  airMopAdd(mop, nhist, (airMopper)nrrdNuke, airMopAlways);
  if (nrrdMaybeAlloc_nva(nhist, nrrdTypeFloat, _nodf->dim, size)) {
    airMopAdd(mop, errS = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: trouble allocating output:\n%s", me, errS);
    airMopError(mop); return 1;
  }
  ncovar = nrrdNew();
  airMopAdd(mop, ncovar, (airMopper)nrrdNuke, airMopAlways);
  if (nrrdMaybeAlloc_va(ncovar, nrrdTypeFloat, 2,
                        AIR_CAST(size_t, bins),
                        AIR_CAST(size_t, bins))) {
    airMopAdd(mop, errS = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: trouble allocating covariance output:\n%s", me, errS);
    airMopError(mop); return 1;
  }

  {
    /* we modify the lengths of the vectors here */
    int NN, VV, ii, jj=0, kk, *anglut;
    float *odf, *hist, *covar, *vec, *vi, *vj, tmp, pvmin;
    double *mean;
    Nrrd *nodf, *nanglut;

    VV = nvec->axis[1].size;
    NN = nrrdElementNumber(_nodf)/VV;

    nanglut = nrrdNew();
    airMopAdd(mop, nanglut, (airMopper)nrrdNuke, airMopAlways);
    if (nrrdMaybeAlloc_va(nanglut, nrrdTypeInt, 2,
                          AIR_CAST(size_t, VV),
                          AIR_CAST(size_t, VV))) {
      airMopAdd(mop, errS = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: trouble allocating lookup table:\n%s", me, errS);
      airMopError(mop); return 1;
    }
    if (nrrdTypeFloat == _nodf->type) {
      nodf = _nodf;
    } else {
      nodf = nrrdNew();
      airMopAdd(mop, nodf, (airMopper)nrrdNuke, airMopAlways);
      if (nrrdConvert(nodf, _nodf, nrrdTypeFloat)) {
        airMopAdd(mop, errS = biffGetDone(NRRD), airFree, airMopAlways);
        fprintf(stderr, "%s: trouble converting input:\n%s", me, errS);
        airMopError(mop); return 1;
      }
    }      
    
    /* normalize lengths (MODIFIES INPUT) */
    vec = (float*)nvec->data;
    for (ii=0; ii<=jj; ii++) {
      vi = vec + 3*ii;
      ELL_3V_NORM(vi, vi, tmp);
    }
    
    /* pre-compute pair-wise angles */
    anglut = (int*)nanglut->data;
    for (jj=0; jj<VV; jj++) {
      vj = vec + 3*jj;
      for (ii=0; ii<=jj; ii++) {
        vi = vec + 3*ii;
        tmp = ELL_3V_DOT(vi, vj);
        tmp = AIR_ABS(tmp);
        tmp = acos(tmp)/(AIR_PI/2.0);
        anglut[ii + VV*jj] = airIndex(0.0, tmp, 1.0, bins);
      }
    }

    /* process all samples (MODIFIES INPUT if input was already float) */
    odf = (float*)nodf->data;
    hist = (float*)nhist->data;
    for (kk=0; kk<NN; kk++) {
      if (!(kk % 100)) {
        fprintf(stderr, "%d/%d\n", kk, NN);
      }
      tmp = 0;
      if (AIR_EXISTS(min)) {
        for (ii=0; ii<VV; ii++) {
          odf[ii] = AIR_MAX(0.0, odf[ii]-min);
          tmp += odf[ii];
        }
      } else {
        /* we do the more sketchy per-voxel min subtraction */
        pvmin = airFPGen_f(airFP_POS_INF);
        for (ii=0; ii<VV; ii++) {
          pvmin = AIR_MIN(pvmin, odf[ii]);
        }
        for (ii=0; ii<VV; ii++) {
          odf[ii] -= pvmin;
          tmp += odf[ii];
        }
      }
      if (tmp) {
        /* something left after subtracting out baseline isotropic */
        for (ii=0; ii<VV; ii++) {
          odf[ii] /= tmp;
        }
        /* odf[] is normalized to 1.0 sum */
        for (jj=0; jj<VV; jj++) {
          for (ii=0; ii<=jj; ii++) {
            tmp = odf[ii]*odf[jj];
            hist[anglut[ii + VV*jj]] += tmp;
          }
        }
      }
      odf += VV;
      hist += bins;
    }
    odf = NULL;
    hist = NULL;

    /* find mean value of each bin (needed for covariance) */
    mean = (double*)calloc(bins, sizeof(double));
    if (!mean) {
      fprintf(stderr, "%s: couldn't allocate mean array", me);
      airMopError(mop); return 1;
    }
    hist = (float*)nhist->data;
    for (kk=0; kk<NN; kk++) {
      for (ii=0; ii<bins; ii++) {
        mean[ii] += hist[ii];
      }
      hist += bins;
    }
    hist = NULL;
    for (ii=0; ii<bins; ii++) {
      mean[ii] /= NN;
    }

    /* make covariance matrix of from all histograms */
    covar = (float*)ncovar->data;
    hist = (float*)nhist->data;
    for (kk=0; kk<NN; kk++) {
      for (jj=0; jj<bins; jj++) {
        for (ii=0; ii<jj; ii++) {
          tmp = (hist[ii] - mean[ii])*(hist[jj] - mean[jj]);
          covar[ii + bins*jj] += tmp;
          covar[jj + bins*ii] += tmp;
        }
        covar[jj + bins*jj] += (hist[jj] - mean[jj])*(hist[jj] - mean[jj]);
      }
      hist += bins;
    }
    hist = NULL;
  }

  if (nrrdSave(outS, nhist, NULL)) {
    airMopAdd(mop, errS = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't save output:\n%s\n", me, errS);
    airMopError(mop); return 1;
  }
  if (nrrdSave(covarS, ncovar, NULL)) {
    airMopAdd(mop, errS = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: couldn't save covariance output:\n%s\n", me, errS);
    airMopError(mop); return 1;
  }
  airMopOkay(mop);
  return 0;
}