int tend_anplotMain(int argc, const char **argv, const char *me, hestParm *hparm) { int pret; hestOpt *hopt = NULL; char *perr, *err; airArray *mop; int res, aniso, whole, nanout, hflip; Nrrd *nout; char *outS; hestOptAdd(&hopt, "r", "res", airTypeInt, 1, 1, &res, "256", "resolution of anisotropy plot"); 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, "hflip", NULL, airTypeInt, 0, 0, &hflip, NULL, "flip the two bottom corners (swapping the place of " "linear and planar)"); hestOptAdd(&hopt, "nan", NULL, airTypeInt, 0, 0, &nanout, NULL, "set the pixel values outside the triangle to be NaN, " "instead of 0"); hestOptAdd(&hopt, "a", "aniso", airTypeEnum, 1, 1, &aniso, NULL, "Which anisotropy metric to plot. " TEN_ANISO_DESC, NULL, tenAniso); hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-", "output image (floating point)"); mop = airMopNew(); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); USAGE(_tend_anplotInfoL); JUSTPARSE(); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); if (tenAnisoPlot(nout, aniso, res, hflip, whole, nanout)) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble making plot:\n%s\n", me, err); airMopError(mop); return 1; } 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 tend_makeMain(int argc, char **argv, char *me, hestParm *hparm) { int pret; hestOpt *hopt = NULL; char *perr, *err; airArray *mop; Nrrd *nin[3], *nout; char *outS; hestOptAdd(&hopt, "i", "conf evals evecs", airTypeOther, 3, 3, nin, NULL, "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_makeInfoL); JUSTPARSE(); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); if (tenMake(nout, nin[0], nin[1], nin[2])) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble making tensor volume:\n%s\n", me, err); airMopError(mop); return 1; } 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 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 tend_mfitMain(int argc, char **argv, char *me, hestParm *hparm) { int pret; hestOpt *hopt = NULL; char *perr, *err; airArray *mop; Nrrd *nin, *nout, *nterr; char *outS, *terrS, *modS; int knownB0, saveB0, verbose, mlfit, typeOut; unsigned int maxIter, minIter, starts; double sigma, eps; const tenModel *model; tenExperSpec *espec; hestOptAdd(&hopt, "v", "verbose", airTypeInt, 1, 1, &verbose, "0", "verbosity level"); hestOptAdd(&hopt, "m", "model", airTypeString, 1, 1, &modS, NULL, "which model to fit. Use optional \"b0+\" prefix to " "indicate that the B0 image should also be saved."); hestOptAdd(&hopt, "ns", "# starts", airTypeUInt, 1, 1, &starts, "1", "number of random starting points at which to initialize " "fitting"); hestOptAdd(&hopt, "ml", NULL, airTypeInt, 0, 0, &mlfit, NULL, "do ML fitting, rather than least-squares, which also " "requires setting \"-sigma\""); hestOptAdd(&hopt, "sigma", "sigma", airTypeDouble, 1, 1, &sigma, "nan", "Rician noise parameter"); hestOptAdd(&hopt, "eps", "eps", airTypeDouble, 1, 1, &eps, "0.01", "convergence epsilon"); hestOptAdd(&hopt, "mini", "min iters", airTypeUInt, 1, 1, &minIter, "3", "minimum required # iterations for fitting."); hestOptAdd(&hopt, "maxi", "max iters", airTypeUInt, 1, 1, &maxIter, "100", "maximum allowable # iterations for fitting."); hestOptAdd(&hopt, "knownB0", "bool", airTypeBool, 1, 1, &knownB0, NULL, "Indicates if the B=0 non-diffusion-weighted reference image " "is known (\"true\"), or if it has to be estimated along with " "the other model parameters (\"false\")"); hestOptAdd(&hopt, "t", "type", airTypeEnum, 1, 1, &typeOut, "float", "output type of model parameters", NULL, nrrdType); hestOptAdd(&hopt, "i", "dwi", airTypeOther, 1, 1, &nin, "-", "all the diffusion-weighted images in one 4D nrrd", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-", "output tensor volume"); hestOptAdd(&hopt, "eo", "filename", airTypeString, 1, 1, &terrS, "", "Giving a filename here allows you to save out the per-sample " "fitting error. By default, no such error is saved."); mop = airMopNew(); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); USAGE(_tend_mfitInfoL); JUSTPARSE(); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); nterr = NULL; espec = tenExperSpecNew(); airMopAdd(mop, espec, (airMopper)tenExperSpecNix, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); if (tenModelParse(&model, &saveB0, AIR_FALSE, modS)) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble parsing model \"%s\":\n%s\n", me, modS, err); airMopError(mop); return 1; } if (tenExperSpecFromKeyValueSet(espec, nin)) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble getting exper from kvp:\n%s\n", me, err); airMopError(mop); return 1; } if (tenModelSqeFit(nout, airStrlen(terrS) ? &nterr : NULL, model, espec, nin, knownB0, saveB0, typeOut, minIter, maxIter, starts, eps, NULL)) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble fitting:\n%s\n", me, err); airMopError(mop); return 1; } if (nrrdSave(outS, nout, NULL) || (airStrlen(terrS) && nrrdSave(terrS, nterr, NULL))) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble writing output:\n%s\n", me, err); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
int tend_estimMain(int argc, char **argv, char *me, hestParm *hparm) { int pret; hestOpt *hopt = NULL; char *perr, *err; airArray *mop; Nrrd **nin, *nin4d, *nbmat, *nterr, *nB0, *nout; char *outS, *terrS, *bmatS, *eb0S; float soft, scale, sigma; int dwiax, EE, knownB0, oldstuff, estmeth, verbose, fixneg; unsigned int ninLen, axmap[4], wlsi, *skip, skipNum, skipIdx; double valueMin, thresh; Nrrd *ngradKVP=NULL, *nbmatKVP=NULL; double bKVP, bval; tenEstimateContext *tec; hestOptAdd(&hopt, "old", NULL, airTypeInt, 0, 0, &oldstuff, NULL, "instead of the new tenEstimateContext code, use " "the old tenEstimateLinear code"); hestOptAdd(&hopt, "sigma", "sigma", airTypeFloat, 1, 1, &sigma, "nan", "Rician noise parameter"); hestOptAdd(&hopt, "v", "verbose", airTypeInt, 1, 1, &verbose, "0", "verbosity level"); hestOptAdd(&hopt, "est", "estimate method", airTypeEnum, 1, 1, &estmeth, "lls", "estimation method to use. \"lls\": linear-least squares", NULL, tenEstimate1Method); hestOptAdd(&hopt, "wlsi", "WLS iters", airTypeUInt, 1, 1, &wlsi, "1", "when using weighted-least-squares (\"-est wls\"), how " "many iterations to do after the initial weighted fit."); hestOptAdd(&hopt, "fixneg", NULL, airTypeInt, 0, 0, &fixneg, NULL, "after estimating the tensor, ensure that there are no negative " "eigenvalues by adding (to all eigenvalues) the amount by which " "the smallest is negative (corresponding to increasing the " "non-DWI image value)."); hestOptAdd(&hopt, "ee", "filename", airTypeString, 1, 1, &terrS, "", "Giving a filename here allows you to save out the tensor " "estimation error: a value which measures how much error there " "is between the tensor model and the given diffusion weighted " "measurements for each sample. By default, no such error " "calculation is saved."); hestOptAdd(&hopt, "eb", "filename", airTypeString, 1, 1, &eb0S, "", "In those cases where there is no B=0 reference image given " "(\"-knownB0 false\"), " "giving a filename here allows you to save out the B=0 image " "which is estimated from the data. By default, this image value " "is estimated but not saved."); hestOptAdd(&hopt, "t", "thresh", airTypeDouble, 1, 1, &thresh, "nan", "value at which to threshold the mean DWI value per pixel " "in order to generate the \"confidence\" mask. By default, " "the threshold value is calculated automatically, based on " "histogram analysis."); hestOptAdd(&hopt, "soft", "soft", airTypeFloat, 1, 1, &soft, "0", "how fuzzy the confidence boundary should be. By default, " "confidence boundary is perfectly sharp"); hestOptAdd(&hopt, "scale", "scale", airTypeFloat, 1, 1, &scale, "1", "After estimating the tensor, scale all of its elements " "(but not the confidence value) by this amount. Can help with " "downstream numerical precision if values are very large " "or small."); hestOptAdd(&hopt, "mv", "min val", airTypeDouble, 1, 1, &valueMin, "1.0", "minimum plausible value (especially important for linear " "least squares estimation)"); hestOptAdd(&hopt, "B", "B-list", airTypeString, 1, 1, &bmatS, NULL, "6-by-N list of B-matrices characterizing " "the diffusion weighting for each " "image. \"tend bmat\" is one source for such a matrix; see " "its usage info for specifics on how the coefficients of " "the B-matrix are ordered. " "An unadorned plain text file is a great way to " "specify the B-matrix.\n **OR**\n " "Can say just \"-B kvp\" to try to learn B matrices from " "key/value pair information in input images."); hestOptAdd(&hopt, "b", "b", airTypeDouble, 1, 1, &bval, "nan", "\"b\" diffusion-weighting factor (units of sec/mm^2)"); hestOptAdd(&hopt, "knownB0", "bool", airTypeBool, 1, 1, &knownB0, NULL, "Determines of the B=0 non-diffusion-weighted reference image " "is known, or if it has to be estimated along with the tensor " "elements.\n " "\b\bo if \"true\": in the given list of diffusion gradients or " "B-matrices, there are one or more with zero norm, which are " "simply averaged to find the B=0 reference image value\n " "\b\bo if \"false\": there may or may not be diffusion-weighted " "images among the input; the B=0 image value is going to be " "estimated along with the diffusion model"); hestOptAdd(&hopt, "i", "dwi0 dwi1", airTypeOther, 1, -1, &nin, "-", "all the diffusion-weighted images (DWIs), as seperate 3D nrrds, " "**OR**: One 4D nrrd of all DWIs stacked along axis 0", &ninLen, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-", "output tensor volume"); mop = airMopNew(); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); USAGE(_tend_estimInfoL); JUSTPARSE(); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); nbmat = nrrdNew(); airMopAdd(mop, nbmat, (airMopper)nrrdNuke, airMopAlways); /* figure out B-matrix */ if (strcmp("kvp", airToLower(bmatS))) { /* its NOT coming from key/value pairs */ if (!AIR_EXISTS(bval)) { fprintf(stderr, "%s: need to specify scalar b-value\n", me); airMopError(mop); return 1; } if (nrrdLoad(nbmat, bmatS, NULL)) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble loading B-matrix:\n%s\n", me, err); airMopError(mop); return 1; } nin4d = nin[0]; skip = NULL; skipNum = 0; } else { /* it IS coming from key/value pairs */ if (1 != ninLen) { fprintf(stderr, "%s: require a single 4-D DWI volume for " "key/value pair based calculation of B-matrix\n", me); airMopError(mop); return 1; } if (oldstuff) { if (knownB0) { fprintf(stderr, "%s: sorry, key/value-based DWI info not compatible " "with older implementation of knownB0\n", me); airMopError(mop); return 1; } } if (tenDWMRIKeyValueParse(&ngradKVP, &nbmatKVP, &bKVP, &skip, &skipNum, nin[0])) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble parsing DWI info:\n%s\n", me, err); airMopError(mop); return 1; } if (AIR_EXISTS(bval)) { fprintf(stderr, "%s: WARNING: key/value pair derived b-value %g " "over-riding %g from command-line", me, bKVP, bval); } bval = bKVP; if (ngradKVP) { airMopAdd(mop, ngradKVP, (airMopper)nrrdNuke, airMopAlways); if (tenBMatrixCalc(nbmat, ngradKVP)) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble finding B-matrix:\n%s\n", me, err); airMopError(mop); return 1; } } else { airMopAdd(mop, nbmatKVP, (airMopper)nrrdNuke, airMopAlways); if (nrrdConvert(nbmat, nbmatKVP, nrrdTypeDouble)) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble converting B-matrix:\n%s\n", me, err); airMopError(mop); return 1; } } /* this will work because of the impositions of tenDWMRIKeyValueParse */ dwiax = ((nrrdKindList == nin[0]->axis[0].kind || nrrdKindVector == nin[0]->axis[0].kind) ? 0 : ((nrrdKindList == nin[0]->axis[1].kind || nrrdKindVector == nin[0]->axis[1].kind) ? 1 : ((nrrdKindList == nin[0]->axis[2].kind || nrrdKindVector == nin[0]->axis[2].kind) ? 2 : 3))); if (0 == dwiax) { nin4d = nin[0]; } else { axmap[0] = dwiax; axmap[1] = 1 > dwiax ? 1 : 0; axmap[2] = 2 > dwiax ? 2 : 1; axmap[3] = 3 > dwiax ? 3 : 2; nin4d = nrrdNew(); airMopAdd(mop, nin4d, (airMopper)nrrdNuke, airMopAlways); if (nrrdAxesPermute(nin4d, nin[0], axmap)) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble creating DWI volume:\n%s\n", me, err); airMopError(mop); return 1; } } } nterr = NULL; nB0 = NULL; if (!oldstuff) { if (1 != ninLen) { fprintf(stderr, "%s: sorry, currently need single 4D volume " "for new implementation\n", me); airMopError(mop); return 1; } if (!AIR_EXISTS(thresh)) { if (tend_estimThresholdFind(&thresh, nbmat, nin4d)) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble finding threshold:\n%s\n", me, err); airMopError(mop); return 1; } /* HACK to lower threshold a titch */ thresh *= 0.93; fprintf(stderr, "%s: using mean DWI threshold %g\n", me, thresh); } tec = tenEstimateContextNew(); tec->progress = AIR_TRUE; airMopAdd(mop, tec, (airMopper)tenEstimateContextNix, airMopAlways); EE = 0; if (!EE) tenEstimateVerboseSet(tec, verbose); if (!EE) tenEstimateNegEvalShiftSet(tec, fixneg); if (!EE) EE |= tenEstimateMethodSet(tec, estmeth); if (!EE) EE |= tenEstimateBMatricesSet(tec, nbmat, bval, !knownB0); if (!EE) EE |= tenEstimateValueMinSet(tec, valueMin); for (skipIdx=0; skipIdx<skipNum; skipIdx++) { /* fprintf(stderr, "%s: skipping %u\n", me, skip[skipIdx]); */ if (!EE) EE |= tenEstimateSkipSet(tec, skip[skipIdx], AIR_TRUE); } switch(estmeth) { case tenEstimate1MethodLLS: if (airStrlen(terrS)) { tec->recordErrorLogDwi = AIR_TRUE; /* tec->recordErrorDwi = AIR_TRUE; */ } break; case tenEstimate1MethodNLS: if (airStrlen(terrS)) { tec->recordErrorDwi = AIR_TRUE; } break; case tenEstimate1MethodWLS: if (!EE) tec->WLSIterNum = wlsi; if (airStrlen(terrS)) { tec->recordErrorDwi = AIR_TRUE; } break; case tenEstimate1MethodMLE: if (!(AIR_EXISTS(sigma) && sigma > 0.0)) { fprintf(stderr, "%s: can't do %s w/out sigma > 0 (not %g)\n", me, airEnumStr(tenEstimate1Method, tenEstimate1MethodMLE), sigma); airMopError(mop); return 1; } if (!EE) EE |= tenEstimateSigmaSet(tec, sigma); if (airStrlen(terrS)) { tec->recordLikelihoodDwi = AIR_TRUE; } break; } if (!EE) EE |= tenEstimateThresholdSet(tec, thresh, soft); if (!EE) EE |= tenEstimateUpdate(tec); if (EE) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble setting up estimation:\n%s\n", me, err); airMopError(mop); return 1; } if (tenEstimate1TensorVolume4D(tec, nout, &nB0, airStrlen(terrS) ? &nterr : NULL, nin4d, nrrdTypeFloat)) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble doing estimation:\n%s\n", me, err); airMopError(mop); return 1; } if (airStrlen(terrS)) { airMopAdd(mop, nterr, (airMopper)nrrdNuke, airMopAlways); } } else { EE = 0; if (1 == ninLen) { EE = tenEstimateLinear4D(nout, airStrlen(terrS) ? &nterr : NULL, &nB0, nin4d, nbmat, knownB0, thresh, soft, bval); } else { EE = tenEstimateLinear3D(nout, airStrlen(terrS) ? &nterr : NULL, &nB0, (const Nrrd**)nin, ninLen, nbmat, knownB0, thresh, soft, bval); } if (EE) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble making tensor volume:\n%s\n", me, err); airMopError(mop); return 1; } } if (nterr) { /* it was allocated by tenEstimate*, we have to clean it up */ airMopAdd(mop, nterr, (airMopper)nrrdNuke, airMopAlways); } if (nB0) { /* it was allocated by tenEstimate*, we have to clean it up */ airMopAdd(mop, nB0, (airMopper)nrrdNuke, airMopAlways); } if (1 != scale) { if (tenSizeScale(nout, nout, scale)) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble doing scaling:\n%s\n", me, err); airMopError(mop); return 1; } } if (nterr) { if (nrrdSave(terrS, nterr, NULL)) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble writing error image:\n%s\n", me, err); airMopError(mop); return 1; } } if (!knownB0 && airStrlen(eb0S)) { if (nrrdSave(eb0S, nB0, NULL)) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble writing estimated B=0 image:\n%s\n", me, err); airMopError(mop); return 1; } } 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 tend_epiregMain(int argc, const char **argv, const char *me, hestParm *hparm) { int pret, rret; hestOpt *hopt = NULL; char *perr, *err; airArray *mop; char *outS, *buff; char *gradS; NrrdKernelSpec *ksp; Nrrd **nin, **nout3D, *nout4D, *ngrad, *ngradKVP, *nbmatKVP; unsigned int ni, ninLen, *skip, skipNum; int ref, noverbose, progress, nocc, baseNum; float bw[2], thr, fitFrac; double bvalue; hestOptAdd(&hopt, "i", "dwi0 dwi1", airTypeOther, 1, -1, &nin, NULL, "all the diffusion-weighted images (DWIs), as separate 3D nrrds, " "**OR**: one 4D nrrd of all DWIs stacked along axis 0", &ninLen, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "g", "grads", airTypeString, 1, 1, &gradS, NULL, "array of gradient directions, in the same order as the " "associated DWIs were given to \"-i\", " "**OR** \"-g kvp\" signifies that gradient directions should " "be read from the key/value pairs of the DWI", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "r", "reference", airTypeInt, 1, 1, &ref, "-1", "which of the DW volumes (zero-based numbering) should be used " "as the standard, to which all other images are transformed. " "Using -1 (the default) means that 9 intrinsic parameters " "governing the relationship between the gradient direction " "and the resulting distortion are estimated and fitted, " "ensuring good registration with the non-diffusion-weighted " "T2 image (which is never explicitly used in registration). " "Otherwise, by picking a specific DWI, no distortion parameter " "estimation is done. "); hestOptAdd(&hopt, "nv", NULL, airTypeInt, 0, 0, &noverbose, NULL, "turn OFF verbose mode, and " "have no idea what stage processing is at."); hestOptAdd(&hopt, "p", NULL, airTypeInt, 0, 0, &progress, NULL, "save out intermediate steps of processing"); hestOptAdd(&hopt, "bw", "x,y blur", airTypeFloat, 2, 2, bw, "1.0 2.0", "standard devs in X and Y directions of gaussian filter used " "to blur the DWIs prior to doing segmentation. This blurring " "does not effect the final resampling of registered DWIs. " "Use \"0.0 0.0\" to say \"no blurring\""); hestOptAdd(&hopt, "t", "DWI thresh", airTypeFloat, 1, 1, &thr, "nan", "Threshold value to use on DWIs, " "to do initial separation of brain and non-brain. By default, " "the threshold is determined automatically by histogram " "analysis. "); hestOptAdd(&hopt, "ncc", NULL, airTypeInt, 0, 0, &nocc, NULL, "do *NOT* do connected component (CC) analysis, after " "thresholding and before moment calculation. Doing CC analysis " "usually gives better results because it converts the " "thresholding output into something much closer to a " "real segmentation"); hestOptAdd(&hopt, "f", "fit frac", airTypeFloat, 1, 1, &fitFrac, "0.70", "(only meaningful with \"-r -1\") When doing linear fitting " "of the intrinsic distortion parameters, it is good " "to ignore the slices for which the segmentation was poor. A " "heuristic is used to rank the slices according to segmentation " "quality. This option controls how many of the (best) slices " "contribute to the fitting. Use \"0\" to disable distortion " "parameter fitting. "); hestOptAdd(&hopt, "k", "kernel", airTypeOther, 1, 1, &ksp, "cubic:0,0.5", "kernel for resampling DWIs along the phase-encoding " "direction during final registration stage", NULL, NULL, nrrdHestKernelSpec); hestOptAdd(&hopt, "s", "start #", airTypeInt, 1, 1, &baseNum, "1", "first number to use in numbered sequence of output files."); hestOptAdd(&hopt, "o", "output/prefix", airTypeString, 1, 1, &outS, "-", "For separate 3D DWI volume inputs: prefix for output filenames; " "will save out one (registered) " "DWI for each input DWI, using the same type as the input. " "**OR**: For single 4D DWI input: output file name. "); mop = airMopNew(); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); USAGE(_tend_epiregInfoL); JUSTPARSE(); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); if (strcmp("kvp", gradS)) { /* they're NOT coming from key/value pairs */ if (nrrdLoad(ngrad=nrrdNew(), gradS, NULL)) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble loading gradient list:\n%s\n", me, err); airMopError(mop); return 1; } } else { if (1 != ninLen) { fprintf(stderr, "%s: can do key/value pairs only from single nrrd", me); airMopError(mop); return 1; } /* they are coming from key/value pairs */ if (tenDWMRIKeyValueParse(&ngradKVP, &nbmatKVP, &bvalue, &skip, &skipNum, nin[0])) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble parsing gradient list:\n%s\n", me, err); airMopError(mop); return 1; } if (nbmatKVP) { fprintf(stderr, "%s: sorry, can only use gradients, not b-matrices", me); airMopError(mop); return 1; } ngrad = ngradKVP; } airMopAdd(mop, ngrad, (airMopper)nrrdNuke, airMopAlways); nout3D = AIR_CALLOC(ninLen, Nrrd *); airMopAdd(mop, nout3D, airFree, airMopAlways); nout4D = nrrdNew(); airMopAdd(mop, nout4D, (airMopper)nrrdNuke, airMopAlways); buff = AIR_CALLOC(airStrlen(outS) + 10, char); airMopAdd(mop, buff, airFree, airMopAlways); if (!( nout3D && nout4D && buff )) { fprintf(stderr, "%s: couldn't allocate buffers", me); airMopError(mop); return 1; } for (ni=0; ni<ninLen; ni++) { nout3D[ni]=nrrdNew(); airMopAdd(mop, nout3D[ni], (airMopper)nrrdNuke, airMopAlways); } if (1 == ninLen) { rret = tenEpiRegister4D(nout4D, nin[0], ngrad, ref, bw[0], bw[1], fitFrac, thr, !nocc, ksp->kernel, ksp->parm, progress, !noverbose); } else { rret = tenEpiRegister3D(nout3D, nin, ninLen, ngrad, ref, bw[0], bw[1], fitFrac, thr, !nocc, ksp->kernel, ksp->parm, progress, !noverbose); } if (rret) { airMopAdd(mop, err=biffGetDone(TEN), airFree, airMopAlways); fprintf(stderr, "%s: trouble doing epireg:\n%s\n", me, err); airMopError(mop); return 1; } if (1 == ninLen) { if (nrrdSave(outS, nout4D, NULL)) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble writing \"%s\":\n%s\n", me, outS, err); airMopError(mop); return 1; } } else { for (ni=0; ni<ninLen; ni++) { if (ninLen+baseNum > 99) { sprintf(buff, "%s%05d.nrrd", outS, ni+baseNum); } else if (ninLen+baseNum > 9) { sprintf(buff, "%s%02d.nrrd", outS, ni+baseNum); } else { sprintf(buff, "%s%d.nrrd", outS, ni+baseNum); } if (nrrdSave(buff, nout3D[ni], NULL)) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble writing \"%s\":\n%s\n", me, buff, err); airMopError(mop); return 1; } } } airMopOkay(mop); return 0; }
int tend_ellipseMain(int argc, char **argv, char *me, hestParm *hparm) { int pret; hestOpt *hopt = NULL; char *perr; airArray *mop; Nrrd *nten, *npos, *nstn; char *outS; float gscale, dotRad, lineWidth, cthresh, min[2], max[2]; FILE *fout; int invert; mop = airMopNew(); hestOptAdd(&hopt, "ctr", "conf thresh", airTypeFloat, 1, 1, &cthresh, "0.5", "Glyphs will be drawn only for tensors with confidence " "values greater than this threshold"); hestOptAdd(&hopt, "gsc", "scale", airTypeFloat, 1, 1, &gscale, "1", "over-all glyph size"); hestOptAdd(&hopt, "dot", "radius", airTypeFloat, 1, 1, &dotRad, "0.0", "radius of little dot to put in middle of ellipse, or \"0\" " "for no such dot"); hestOptAdd(&hopt, "wid", "width", airTypeFloat, 1, 1, &lineWidth, "0.0", "with of lines for tractlets"); hestOptAdd(&hopt, "inv", NULL, airTypeInt, 0, 0, &invert, NULL, "use white ellipses on black background, instead of reverse"); hestOptAdd(&hopt, "min", "minX minY", airTypeFloat, 2, 2, min, "-1 -1", "when using \"-p\", minimum corner"); hestOptAdd(&hopt, "max", "maxX maxY", airTypeFloat, 2, 2, max, "1 1", "when using \"-p\", maximum corner"); /* input/output */ hestOptAdd(&hopt, "i", "nin", airTypeOther, 1, 1, &nten, "-", "image of 2D tensors", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "p", "pos array", airTypeOther, 1, 1, &npos, "", "Instead of being on a grid, tensors are at arbitrary locations, " "as defined by this 2-by-N array of floats", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "s", "stn array", airTypeOther, 1, 1, &nstn, "", "Locations given by \"-p\" have this connectivity", NULL, NULL, nrrdHestNrrd); hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-", "output PostScript file"); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); USAGE(_tend_ellipseInfoL); JUSTPARSE(); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); if (npos) { if (!( 2 == nten->dim && 4 == nten->axis[0].size && 2 == npos->dim && 2 == npos->axis[0].size && nten->axis[1].size == npos->axis[1].size )) { fprintf(stderr, "%s: didn't get matching lists of tensors and pos's\n", me); airMopError(mop); return 1; } if (!( nrrdTypeFloat == npos->type )) { fprintf(stderr, "%s: didn't get float type positions\n", me); airMopError(mop); return 1; } } else { if (!(3 == nten->dim && 4 == nten->axis[0].size)) { fprintf(stderr, "%s: didn't get a 3-D 4-by-X-by-Y 2D tensor array\n", me); airMopError(mop); return 1; } } if (!( nrrdTypeFloat == nten->type )) { fprintf(stderr, "%s: didn't get float type tensors\n", me); airMopError(mop); return 1; } if (nstn) { if (!( nrrdTypeUInt == nstn->type && 2 == nstn->dim && 3 == nstn->axis[0].size )) { fprintf(stderr, "%s: connectivity isn't 2-D 3-by-N array of %ss\n", me, airEnumStr(nrrdType, nrrdTypeInt)); airMopError(mop); return 1; } } if (!(fout = airFopen(outS, stdout, "wb"))) { fprintf(stderr, "%s: couldn't open \"%s\" for writing\n", me, outS); airMopError(mop); return 1; } airMopAdd(mop, fout, (airMopper)airFclose, airMopAlways); tend_ellipseDoit(fout, nten, npos, nstn, min, max, gscale, dotRad, lineWidth, cthresh, invert); airMopOkay(mop); return 0; }