int main(int argc, char *argv[]) { char **av, *in_vol, *out_vol; int ac, nargs; MRI *mri_in, *mri_out, *mri_tmp ; LTA *lta = 0; MATRIX *i_to_r_src = 0; /* src geometry of the input LTA */ MATRIX *V_to_V = 0; /* Final voxel-to-voxel transform */ MATRIX *r_to_i_dst = 0; /* dst geometry of the input LTA */ MATRIX *m_tmp = 0; MATRIX *i_to_r_reg = 0; /* i_to_r of the volume after registration */ MATRIX *r_to_i_out = 0; /* r_to_i of the final output volume */ VOL_GEOM vgm_in; int x, y, z; double maxV, minV, value; // MATRIX *i_to_r, *r_to_i; /* rkt: check for and handle version tag */ nargs = handle_version_option (argc, argv, "$Id: mri_transform_to_COR.c,v 1.8 2011/03/02 00:04:55 nicks Exp $", "$Name: stable5 $"); if (nargs && argc - nargs == 1) usage_exit (0); argc -= nargs; Progname = argv[0] ; ErrorInit(NULL, NULL, NULL) ; DiagInit(NULL, NULL, NULL) ; ac = argc ; av = argv ; for ( ; argc > 1 && ISOPTION(*argv[1]) ; argc--, argv++) { nargs = get_option(argc, argv) ; argc -= nargs ; argv += nargs ; } if (argc < 3) usage_exit(0) ; in_vol = argv[1] ; out_vol = argv[2] ; printf("reading volume from %s...\n", in_vol) ; mri_in = MRIread(in_vol) ; if (!mri_in) ErrorExit(ERROR_NOFILE, "%s: could not read MRI volume %s", Progname, in_vol) ; /* Convert mri_in to float type */ /* double would be more accurate */ if (mri_in->type != MRI_FLOAT) { printf("Input volume type is %d\n", mri_in->type); printf("Change input volume to float type for convenience and accuracy"); mri_tmp = MRIchangeType(mri_in, MRI_FLOAT, 0, 1.0, 1); MRIfree(&mri_in); mri_in = mri_tmp; //swap } /* Get input volume geometry, which is needed to compute i_to_r * and r_to_i of input volume. Note that i_to_r and r_to_i assumed * a certain prespecified c_r, c_a, c_s */ getVolGeom(mri_in, &vgm_in); maxV = -10000.0; minV = 10000.0; for (z=0; z < mri_in->depth; z++) for (y=0; y< mri_in->height; y++) for (x=0; x < mri_in->width; x++) { if (MRIFvox(mri_in, x, y, z) > maxV ) maxV = MRIFvox(mri_in, x, y,z) ; if (MRIFvox(mri_in, x, y, z) < minV ) minV = MRIFvox(mri_in, x, y,z) ; } printf("Input volume has max = %g, min =%g\n", maxV, minV); printf("Scale input volume by %g \n", scale); maxV = -10000.0; minV = 10000.0; for (z=0; z < mri_in->depth; z++) for (y=0; y< mri_in->height; y++) for (x=0; x < mri_in->width; x++) { MRIFvox(mri_in, x, y, z) *= scale; if (MRIFvox(mri_in, x, y, z) > maxV ) maxV = MRIFvox(mri_in, x, y,z) ; if (MRIFvox(mri_in, x, y, z) < minV ) minV = MRIFvox(mri_in, x, y,z) ; } printf("Input volume after scaling has max = %g, min =%g\n", maxV, minV); /* Try to compute the Voxel_to_Voxel transform from the input volume * and the registration target/reference volume! * If no registration is involved, vox_to_vox is simply identity */ /* Things become more complicated when allowing inverse transform */ if (transform_flag) { int transform_type; printf("INFO: Applying transformation from file %s...\n", transform_fname); transform_type = TransformFileNameType(transform_fname); /* Read in LTA transform file name */ if (transform_type == MNI_TRANSFORM_TYPE || transform_type == TRANSFORM_ARRAY_TYPE || transform_type == REGISTER_DAT || transform_type == FSLREG_TYPE ) { printf("Reading transform ...\n"); lta = LTAreadEx(transform_fname) ; if (!lta) ErrorExit(ERROR_NOFILE, "%s: could not read transform file %s", Progname, transform_fname) ; if (transform_type == FSLREG_TYPE) { if (lta_src == 0 || lta_dst == 0) { fprintf(stderr, "ERROR: fslmat does not have information on the src and dst volumes\n"); fprintf(stderr, "ERROR: you must give options '-src' and '-dst' to specify the src and dst volume infos for the registration\n"); } LTAmodifySrcDstGeom(lta, lta_src, lta_dst); // add src and dst information //The following is necessary to interpret FSLMAT correctly!!! LTAchangeType(lta, LINEAR_VOX_TO_VOX); } if (lta->xforms[0].src.valid == 0) { if (lta_src == 0) { fprintf(stderr, "The transform does not have the valid src volume info.\n"); fprintf(stderr, "Either you give src volume info by option -src or\n"); fprintf(stderr, "make the transform to have the valid src info.\n"); ErrorExit(ERROR_BAD_PARM, "Bailing out...\n"); } else { LTAmodifySrcDstGeom(lta, lta_src, NULL); // add src information } } if (lta->xforms[0].dst.valid == 0) { if (lta_dst == 0) { fprintf(stderr, "The transform does not have the valid dst volume info.\n"); fprintf(stderr, "Either you give src volume info by option -dst or\n"); fprintf(stderr, "make the transform to have the valid dst info.\n"); fprintf(stderr, "If the dst was average_305, then you can set\n"); fprintf(stderr, "environmental variable USE_AVERAGE305 true\n"); fprintf(stderr, "instead.\n"); ErrorExit(ERROR_BAD_PARM, "Bailing out...\n"); } else { LTAmodifySrcDstGeom(lta, NULL, lta_dst); // add dst information } } // The following procedure aims to apply an LTA computed from COR format to a volume in non-COR format, or vice versa, as long as they share the same RAS // first change to LINEAR RAS_TO_RAS using old info if (lta->type != LINEAR_RAS_TO_RAS) { LTAchangeType(lta, LINEAR_RAS_TO_RAS); } // now possiblly reset the src and dst if (lta_src != NULL) { //always trust the user LTAmodifySrcDstGeom(lta, lta_src, NULL); } if (lta_dst != NULL) { //always trust the user LTAmodifySrcDstGeom(lta, NULL, lta_dst); } if (lta->type == LINEAR_RAS_TO_RAS) { /* Convert it to VOX_TO_VOX */ /* VOXELsrc_to_VOXELdst = R2Vdst*R2Rlta*V2Rsrc */ /* Note whether the input should be identical to src or dst here depends * on whether the LTA here is the direct or inverse transform */ i_to_r_src = vg_i_to_r(<a->xforms[0].src); r_to_i_dst = vg_r_to_i(<a->xforms[0].dst); if (!r_to_i_dst || !i_to_r_src) ErrorExit(ERROR_BADFILE, "%s: failed to extract volume geometries from input LTA file",Progname); m_tmp = MatrixMultiply(lta->xforms[0].m_L, i_to_r_src, NULL); V_to_V = MatrixMultiply(r_to_i_dst, m_tmp, NULL); MatrixFree(&m_tmp); MatrixFree(&i_to_r_src); MatrixFree(&r_to_i_dst); } } else { fprintf(stderr, "unknown transform type in file %s\n", transform_fname); exit(1); } if (invert_flag) { /* Geometry of input volume should match that of the dst of the LTA */ if (MYvg_isEqual(<a->xforms[0].dst, &vgm_in) == 0) { ErrorExit(ERROR_BADFILE, "%s: dst volume of lta doesn't match that of input volume",Progname); } i_to_r_reg = vg_i_to_r(<a->xforms[0].src); if (!i_to_r_reg) ErrorExit(ERROR_BADFILE, "%s: failed to extract i_to_r of registered volume from LTA",Progname); m_tmp = MatrixInverse(V_to_V, NULL); if (!m_tmp) ErrorExit(ERROR_BADPARM, "%s: transform is singular!", Progname); MatrixFree(&V_to_V); V_to_V = m_tmp; } else { /* Geometry of input volume should match that of the src of the LTA */ if (MYvg_isEqual(<a->xforms[0].src, &vgm_in) == 0) { ErrorExit(ERROR_BADFILE, "%s: src volume of lta doesn't match that of input volume",Progname); } i_to_r_reg = vg_i_to_r(<a->xforms[0].dst); if (!i_to_r_reg) ErrorExit(ERROR_BADFILE, "%s: failed to extract i_to_r of registered volume from LTA",Progname); } } else { /* No registration transform need be applied */ V_to_V = MatrixIdentity(4, NULL); i_to_r_reg = extract_i_to_r(mri_in); if (!i_to_r_reg) ErrorExit(ERROR_BADFILE, "%s: failed to extract i_to_r from input volume",Progname); } /* Now need to find the vox-to-vox transformation between registered volume * (or input volume itself if no registration involved) and the output * volume, either in COR format or as the out-like volume */ /* Given a volume with a certain i_to_r, we need to compute the necessary * vox-to-voxel transform to change its i_to_r to like another volume. * The vox-to-vox is equal to R2V(r_to_i)_likevol*i_to_r_current_vol. */ if (out_like_fname) { mri_tmp = MRIread(out_like_fname) ; if (!mri_tmp) ErrorExit(ERROR_NOFILE, "%s: could not read template volume from %s",out_like_fname) ; /* out_type = mri_tmp->type; */ /* specify the out-type to float initially so as not to lose accuracy * during reslicing, will change type to correct type later. */ mri_out = MRIalloc(mri_tmp->width, mri_tmp->height, mri_tmp->depth, MRI_FLOAT) ; MRIcopyHeader(mri_tmp, mri_out) ; MRIfree(&mri_tmp); } else /* assume output is in COR format */ { mri_out = MRIalloc(256, 256, 256, MRI_FLOAT) ; /* out_type = MRI_UCHAR; */ /* Who says MRIlinearTransformInterp will change the header?? * I don't think so! */ //E/ set xyzc_ras to coronal ones.. - these'll get zorched //by MRIlinearTransformInterp() - copy again later - is there //any use in having them here now? yes, so we can pass mri_out //to the ras2vox fns. mri_out->imnr0 = 1; /* what's this? */ mri_out->imnr1 = 256; /* what's this? */ mri_out->thick = 1.0; mri_out->ps = 1.0; /* what's this? */ mri_out->xsize = mri_out->ysize = mri_out->zsize = 1.0; mri_out->xstart = mri_out->ystart = mri_out->zstart = -128.0; mri_out->xend = mri_out->yend = mri_out->zend = 128.0; mri_out->x_r =-1; mri_out->y_r = 0; mri_out->z_r = 0; mri_out->x_a = 0; mri_out->y_a = 0; mri_out->z_a = 1; mri_out->x_s = 0; mri_out->y_s =-1; mri_out->z_s = 0; /* In this case, the RAS itself is not fully determined, i.e., c_ras. * It's quite arbitrary, different values just change the final * sitting of the volume inside the RAS system. */ /* NO! The C_RAS has to be set correctly, depending which target * volume the previous Vox_to_Vox transformation assumes! * When a registration is involved, the target volume is either * the src of LTA (direct) or the dst (inverse transform). When * just change format, the target volume is the input itself!! */ if (transform_flag) { if (invert_flag) { mri_out->c_r = lta->xforms[0].src.c_r; mri_out->c_a = lta->xforms[0].src.c_a; mri_out->c_s = lta->xforms[0].src.c_s; } else { mri_out->c_r = lta->xforms[0].dst.c_r; mri_out->c_a = lta->xforms[0].dst.c_a; mri_out->c_s = lta->xforms[0].dst.c_s; } } else { mri_out->c_r = mri_in->c_r; mri_out->c_a = mri_in->c_a; mri_out->c_s = mri_in->c_s; } mri_out->ras_good_flag=1; /* What does this flag mean ? */ /* since output is just transformed input */ MRIcopyPulseParameters(mri_in, mri_out) ; } /* Compute the final input-to-output VOX_to_VOX transformation matrix */ r_to_i_out = extract_r_to_i(mri_out); m_tmp = MatrixMultiply(r_to_i_out, i_to_r_reg, NULL); V_to_V = MatrixMultiply(m_tmp, V_to_V, V_to_V); MatrixFree(&m_tmp); printf("InterpMethod = %d\n", InterpMethod); /* Modify the MyMRIlinearTr... if I want to implement my cubic-B-spline * interpolation method. Otherwise, unnecessary */ /* mri_out = MyMRIlinearTransformInterp(mri_in, mri_out, V_to_V, InterpMethod); */ if (InterpMethod == SAMPLE_BSPLINE) mri_out = MRIlinearTransformInterpBSpline(mri_in, mri_out, V_to_V, SplineDegree); else mri_out = MRIlinearTransformInterp(mri_in, mri_out, V_to_V, InterpMethod); maxV = -10000.0; minV = 10000.0; for (z=0; z < mri_out->depth; z++) for (y=0; y< mri_out->height; y++) for (x=0; x < mri_out->width; x++) { if (MRIFvox(mri_out, x, y, z) > maxV ) maxV = MRIFvox(mri_out, x, y,z) ; if (MRIFvox(mri_out, x, y, z) < minV ) minV = MRIFvox(mri_out, x, y,z) ; } if (autoscale) { noscale = 1; /* compute histogram of output volume */ HISTOGRAM *h, *hsmooth ; float fmin, fmax, val, peak, smooth_peak; int i, nbins, bin; fmin = minV; fmax = maxV; if (fmin < 0) fmin = 0; nbins = 256 ; h = HISTOalloc(nbins) ; hsmooth = HISTOcopy(h, NULL) ; HISTOclear(h, h) ; h->bin_size = (fmax-fmin)/255.0 ; for (i = 0 ; i < nbins ; i++) h->bins[i] = (i+1)*h->bin_size ; for (z=0; z < mri_out->depth; z++) for (y=0; y< mri_out->height; y++) for (x=0; x < mri_out->width; x++) { val = MRIFvox(mri_out, x, y, z); if (val <= 0) continue; bin = nint((val - fmin)/h->bin_size); if (bin >= h->nbins) bin = h->nbins-1; else if (bin < 0) bin = 0; h->counts[bin] += 1.0; } HISTOfillHoles(h) ; HISTOsmooth(h, hsmooth, 5) ; peak = hsmooth->bins[HISTOfindHighestPeakInRegion(h, 1, h->nbins)] ; // smooth_peak = // hsmooth->bins[HISTOfindHighestPeakInRegion(hsmooth, 1, hsmooth->nbins)] ; smooth_peak = hsmooth->bins[HISTOfindLastPeak(hsmooth, 5, 0.8)] ; /* bin = nint((smooth_peak - fmin)/hsmooth->bin_size) ; printf("Highest peak has count = %d\n", (int)hsmooth->counts[bin]); bin = nint((420 - fmin)/hsmooth->bin_size) ; printf("bin at 420 has count = %d\n", (int)hsmooth->counts[bin]); */ scale = 110.0/smooth_peak; printf("peak of output volume is %g, smooth-peak is %g, multiply by %g to scale it to 110\n", peak, smooth_peak, scale); for (z=0; z < mri_out->depth; z++) for (y=0; y< mri_out->height; y++) for (x=0; x < mri_out->width; x++) { val = MRIFvox(mri_out, x, y, z); MRIFvox(mri_out, x, y, z) = val*scale; } } printf("Output volume (before type-conversion) has max = %g, min =%g\n", maxV, minV); /* Finally change type to desired */ if (mri_out->type != out_type) { printf("Change output volume to type %d\n", out_type); /* I need to modify the MIRchangeType function to make sure * it does roundoff instead of simple truncation! */ /* Note if the last flag is set to 1, then it won't do scaling and small float numbers will become zero after convert to BYTE */ if (out_type == 0 && noscale == 1) { //convert data to UCHAR mri_tmp = MRIalloc(mri_out->width, mri_out->height, mri_out->depth, out_type) ; MRIcopyHeader(mri_out, mri_tmp); for (z=0; z < mri_out->depth; z++) for (y=0; y< mri_out->height; y++) for (x=0; x < mri_out->width; x++) { value = floor(MRIgetVoxVal(mri_out, x, y, z, 0) + 0.5); if (value < 0 ) value = 0; if (value > 255) value = 255; MRIvox(mri_tmp,x,y,z) = (unsigned char)value; } } else mri_tmp = MRIchangeType(mri_out, out_type, thred_low, thred_high, noscale); MRIfree(&mri_out); mri_out = mri_tmp; //swap } MRIwrite(mri_out, out_vol) ; MRIfree(&mri_in); MRIfree(&mri_out); if (lta_src) MRIfree(<a_src); if (lta_dst) MRIfree(<a_dst); MatrixFree(&V_to_V); if (!r_to_i_out) MatrixFree(&r_to_i_out); if (!i_to_r_reg) MatrixFree(&i_to_r_reg); return(0) ; /* for ansi */ }
static MRI * MRIremoveWMOutliers(MRI *mri_src, MRI *mri_src_ctrl, MRI *mri_dst_ctrl, int intensity_below) { MRI *mri_bin, *mri_outliers = NULL ; float max, thresh, val; HISTOGRAM *histo, *hsmooth ; int wm_peak, x, y, z, nremoved = 0, whalf = 5, total ; if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON) { MRIwrite(mri_src_ctrl, "sc.mgz") ; } if (mri_dst_ctrl == NULL) { mri_dst_ctrl = MRIcopy(mri_src_ctrl, NULL) ; } mri_bin = MRIbinarize(mri_src_ctrl, NULL, 1, 0, CONTROL_MARKED) ; histo = MRIhistogramLabel(mri_src, mri_bin, 1, 256) ; hsmooth = HISTOcopy(histo, NULL) ; HISTOsmooth(histo, hsmooth, 2) ; if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON) { HISTOplot(histo, "h.plt") ; HISTOplot(hsmooth, "hs.plt") ; } wm_peak = HISTOfindHighestPeakInRegion(hsmooth, 1, hsmooth->nbins-1) ; wm_peak = hsmooth->bins[wm_peak] ; thresh = wm_peak-intensity_below ; HISTOfree(&histo) ; HISTOfree(&hsmooth) ; if (Gdiag & DIAG_WRITE) { mri_outliers = MRIclone(mri_dst_ctrl, NULL) ; } for (total = x = 0 ; x < mri_src->width ; x++) { for (y = 0 ; y < mri_src->height ; y++) { for (z = 0 ; z < mri_src->depth ; z++) { if (x == Gx && y == Gy && z == Gz) { DiagBreak() ; } if (nint(MRIgetVoxVal(mri_dst_ctrl, x, y, z, 0)) == 0) { continue ; } max = MRImaxInLabelInRegion(mri_src, mri_bin, 1, x, y, z, whalf); val = MRIgetVoxVal(mri_src, x, y, z, 0) ; total++ ; if (val+intensity_below < max && val < thresh) { MRIsetVoxVal(mri_dst_ctrl, x, y, z, 0, 0) ; if (mri_outliers) { MRIsetVoxVal(mri_outliers, x, y, z, 0, 128) ; } nremoved++ ; } } } } printf( "%d control points removed (%2.1f%%)\n", nremoved, 100.0*(double)nremoved/(double)total) ; if (mri_outliers) { printf( "writing out.mgz outlier volume\n") ; MRIwrite(mri_outliers, "out.mgz") ; MRIfree(&mri_outliers) ; } if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON) { MRIwrite(mri_dst_ctrl, "dc.mgz") ; } MRIfree(&mri_bin) ; return(mri_dst_ctrl); }
static MRI * MRIremoveWMOutliersAndRetainMedialSurface(MRI *mri_src, MRI *mri_src_ctrl, MRI *mri_dst_ctrl, int intensity_below) { MRI *mri_inside, *mri_bin ; HISTOGRAM *histo, *hsmooth ; int wm_peak, x, y, z, nremoved ; float thresh, hi_thresh ; double val, lmean, max ; if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON) { MRIwrite(mri_src_ctrl, "sc.mgz") ; } if (mri_dst_ctrl != mri_src_ctrl) { mri_dst_ctrl = MRIcopy(mri_src_ctrl, mri_dst_ctrl) ; } mri_inside = MRIerode(mri_dst_ctrl, NULL) ; MRIbinarize(mri_inside, mri_inside, 1, 0, 1) ; histo = MRIhistogramLabel(mri_src, mri_inside, 1, 256) ; hsmooth = HISTOcopy(histo, NULL) ; HISTOsmooth(histo, hsmooth, 2) ; if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON) { HISTOplot(histo, "h.plt") ; HISTOplot(hsmooth, "hs.plt") ; } printf("using wm (%d) threshold %2.1f for removing exterior voxels\n", wm_peak, thresh) ; wm_peak = HISTOfindHighestPeakInRegion(hsmooth, 1, hsmooth->nbins-1) ; wm_peak = hsmooth->bins[wm_peak] ; thresh = wm_peak-intensity_below ; hi_thresh = wm_peak-.5*intensity_below ; printf("using wm (%d) threshold %2.1f for removing exterior voxels\n", wm_peak, thresh) ; // now remove stuff that's on the border and is pretty dark for (nremoved = x = 0 ; x < mri_src->width ; x++) { for (y = 0 ; y < mri_src->height ; y++) { for (z = 0 ; z < mri_src->depth ; z++) { if (x == Gx && y == Gy && z == Gz) { DiagBreak() ; } /* if it's a control point, it's not in the interior of the wm, and it's T1 val is too low */ if (MRIgetVoxVal(mri_dst_ctrl, x, y, z, 0) == 0) { continue ; // not a control point } /* if it's way far from the wm mode then remove it even if it's in the interior */ val = MRIgetVoxVal(mri_src, x, y, z, 0) ; if (val < thresh-5) { MRIsetVoxVal(mri_dst_ctrl, x, y, z, 0, 0) ; nremoved++ ; } if (nint(MRIgetVoxVal(mri_inside, x, y, z, 0)) > 0) // don't process interior voxels further { continue ; // in the interior } if (val < thresh) { MRIsetVoxVal(mri_dst_ctrl, x, y, z, 0, 0) ; nremoved++ ; } else { lmean = MRImeanInLabelInRegion(mri_src, mri_inside, 1, x, y, z, 7); if (val < lmean-10) { MRIsetVoxVal(mri_dst_ctrl, x, y, z, 0, 0) ; nremoved++ ; } } } } } #if 0 for (x = 0 ; x < mri_src->width ; x++) { for (y = 0 ; y < mri_src->height ; y++) { for (z = 0 ; z < mri_src->depth ; z++) { if (x == Gx && y == Gy && z == Gz) { DiagBreak() ; } /* if it's a control point, it's not in the interior of the wm, and it's T1 val is too low */ if (MRIgetVoxVal(mri_dst_ctrl, x, y, z, 0) == 0) { continue ; // not a control point } if (MRIcountNonzeroInNbhd(mri_dst_ctrl,3, x, y, z)<=2) { MRIsetVoxVal(mri_dst_ctrl, x, y, z, 0, 0) ; nremoved++ ; } } } } #endif /* now take out voxels that have too big an intensity diff with surrounding ones */ mri_bin = MRIbinarize(mri_dst_ctrl, NULL, 1, 0, 1) ; for (x = 0 ; x < mri_src->width ; x++) { for (y = 0 ; y < mri_src->height ; y++) { for (z = 0 ; z < mri_src->depth ; z++) { if (x == Gx && y == Gy && z == Gz) { DiagBreak() ; } /* if it's a control point, it's not in the interior of the wm, and it's T1 val is too low */ if (MRIgetVoxVal(mri_dst_ctrl, x, y, z, 0) == 0) { continue ; // not a control point } val = MRIgetVoxVal(mri_src, x, y, z, 0) ; max = MRImaxInLabelInRegion(mri_src, mri_bin, 1, x, y, z, 3); if (val+7 < max && val < hi_thresh) { MRIsetVoxVal(mri_dst_ctrl, x, y, z, 0, 0) ; nremoved++ ; } } } } MRIfree(&mri_bin) ; printf( "%d control points removed\n", nremoved) ; if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON) { MRIwrite(mri_dst_ctrl, "dc.mgz") ; } HISTOfree(&histo) ; HISTOfree(&hsmooth) ; MRIfree(&mri_inside) ; return(mri_dst_ctrl) ; }
static MRI * MRIremoveWMOutliersAndRetainMedialSurface(MRI *mri_src, MRI *mri_src_ctrl, MRI *mri_dst_ctrl, int intensity_below) { MRI *mri_bin, *mri_dist, *mri_dist_sup, *mri_outliers = NULL ; float max, thresh, val; HISTOGRAM *histo, *hsmooth ; int wm_peak, x, y, z, nremoved = 0, whalf = 5 ; if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON) { MRIwrite(mri_src_ctrl, "sc.mgz") ; } mri_bin = MRIbinarize(mri_dst_ctrl, NULL, 1, 0, 1) ; mri_dist = MRIdistanceTransform(mri_bin, NULL, 1, -1, DTRANS_MODE_SIGNED, NULL); MRIscalarMul(mri_dist, mri_dist, -1) ; mri_dist_sup = MRInonMaxSuppress(mri_dist, NULL, 0, 1) ; mri_dst_ctrl = MRIbinarize(mri_dist_sup, mri_dst_ctrl, 1, 0, 1) ; histo = MRIhistogramLabel(mri_src, mri_src_ctrl, 1, 256) ; hsmooth = HISTOcopy(histo, NULL) ; HISTOsmooth(histo, hsmooth, 2) ; if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON) { HISTOplot(histo, "h.plt") ; HISTOplot(hsmooth, "hs.plt") ; } wm_peak = HISTOfindHighestPeakInRegion(hsmooth, 1, hsmooth->nbins-1) ; wm_peak = hsmooth->bins[wm_peak] ; thresh = wm_peak-intensity_below ; HISTOfree(&histo) ; HISTOfree(&hsmooth) ; if (Gdiag & DIAG_WRITE) { mri_outliers = MRIclone(mri_dst_ctrl, NULL) ; } for (x = 0 ; x < mri_src->width ; x++) { for (y = 0 ; y < mri_src->height ; y++) { for (z = 0 ; z < mri_src->depth ; z++) { if (x == Gx && y == Gy && z == Gz) { DiagBreak() ; } if (nint(MRIgetVoxVal(mri_dst_ctrl, x, y, z, 0)) == 0) { continue ; } max = MRImaxInLabelInRegion(mri_src, mri_dst_ctrl, 1, x, y, z, whalf); val = MRIgetVoxVal(mri_src, x, y, z, 0) ; if (val+intensity_below < max && val < thresh) { MRIsetVoxVal(mri_dst_ctrl, x, y, z, 0, 0) ; if (mri_outliers) { MRIsetVoxVal(mri_outliers, x, y, z, 0, 128) ; } nremoved++ ; } } } } printf( "%d control points removed\n", nremoved) ; if (mri_outliers) { printf( "writing out.mgz outlier volume\n") ; MRIwrite(mri_outliers, "out.mgz") ; MRIfree(&mri_outliers) ; } if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON) { MRIwrite(mri_dst_ctrl, "dc.mgz") ; } MRIfree(&mri_bin) ; MRIfree(&mri_dist); MRIfree(&mri_dist_sup); return(mri_dst_ctrl); }