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; }
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; }
/* ******** 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; }
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; }
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; }
/* ******** 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; }
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; }
/* ******** 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; }
/* ******** 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; }
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, ¢, &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)) {
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 {
/* ******** 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; }
/* ******** 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; }
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; }
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; }
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); }
/* ******** 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; }
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); }
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++) {
/* ******** 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; }
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; }
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; }
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; }
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; }
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; }
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); } } }
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; }
/* ******** 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; }
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; }
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; }