示例#1
0
/*!
  \fn int CCSegment(MRI *seg, int segid, int segidunknown)
  Constraints a sementation ID to consist of voxels that
  are spatially contiguous (6 face neighbors, not edge
  or corner). The voxels in the largest cluster are not
  changed. The voxels in the other clusters are set to
  segidunknown.
*/
int CCSegment(MRI *seg, int segid, int segidunknown)
{
    MRI_SEGMENTATION *sgmnt;
    int k,kmax,index,c,r,s;

    sgmnt = MRIsegment(seg,segid-.5,segid+.5);
    printf("  Found %d clusters\n",sgmnt->nsegments);

    kmax = 0;
    for (k=0; k < sgmnt->nsegments; k++)
        if (sgmnt->segments[k].nvoxels > sgmnt->segments[kmax].nvoxels)
        {
            kmax = k;
        }

    for (k=0; k < sgmnt->nsegments; k++)
    {
        printf("     %d k %f\n",k,sgmnt->segments[k].area);
        if (k==kmax)
        {
            continue;
        }
        for (index = 0; index < sgmnt->segments[k].nvoxels; index++)
        {
            c = sgmnt->segments[k].voxels[index].x;
            r = sgmnt->segments[k].voxels[index].y;
            s = sgmnt->segments[k].voxels[index].z;
            MRIsetVoxVal(seg,c,r,s,0,segidunknown);
        }
    }
    MRIsegmentFree(&sgmnt);
    return(0);
}
示例#2
0
int
main(int argc, char *argv[])
{
  double           thresh ;
  MRI              *mri, *mri_abs ;
  char             *out_stem, fname[STRLEN] ;
  MRI_SEGMENTATION *mriseg ;
  int              s ;
  LABEL            *area ;

  Progname = argv[0] ;
  ErrorInit(NULL, NULL, NULL) ;
  DiagInit(NULL, NULL, NULL) ;
  mri = MRIread(argv[1]) ;
  if (mri == NULL)
    ErrorExit(ERROR_NOFILE, "%s: could not load MRI from %s\n", Progname, argv[1]) ;

  if (use_abs)
    mri_abs = MRIabs(mri, NULL) ;
  else
    mri_abs = MRIcopy(mri, NULL) ;

  thresh = atof(argv[2]) ;
  out_stem = argv[3] ;

  mriseg = MRIsegment(mri, thresh, 1e10) ;
  MRIremoveSmallSegments(mriseg, size_thresh) ;
  printf("segmenting volume at threshold %2.1f yields %d segments\n", thresh, mriseg->nsegments) ;

  for (s = 0 ; s < mriseg->nsegments ; s++)
  {
    area = MRIsegmentToLabel(mriseg, mri_abs, s) ;
    sprintf(fname, "%s.%3.3d.label", out_stem, s) ;
    LabelWrite(area, fname) ;
    
  }
  return(0) ;
}
示例#3
0
MRI *
MRIfillBasalGanglia(MRI *mri_src, MRI *mri_dst)
{
    float  low_thresh, hi_thresh ;
    int    total_filled, depth, height, width, x, y, z,
           xi, yi, zi, xk, yk, zk, fill, val0, val, i ;
    MRI    *mri_bg ;
    Real   tx, ty, tz ;
    MRI_SEGMENTATION  *mriseg ;
    MRI_SEGMENT       *mseg ;
    float  dx_left, dx_right, dy, dz, dist_left, dist_right ;

    if (!mri_dst)
    {
        mri_dst = MRIcopy(mri_src, NULL) ;
    }
    mri_bg = MRIclone(mri_src, NULL) ;

    width = mri_src->width ;
    height = mri_src->height ;
    depth = mri_src->depth ;
    low_thresh = 85 ;
    hi_thresh =  105 ;
    total_filled = 0 ;
    for (z = 0 ; z < depth ; z++)
    {
        for (y = 0 ; y < height ; y++)
        {
            for (x = 0 ; x < width ; x++)
            {
                if (x == 152 && y == 117 && z == 132)  /* 93 */
                {
                    DiagBreak() ;
                }
                val0 = MRIgetVoxVal(mri_src, x, y, z, 0) ;
#if 0
                if (val0 >= low_thresh && val0 <= hi_thresh &&
                        MRIvox(mri_dst,x,y,z) < WM_MIN_VAL)
#else
                if (val0 >= 85 && val0 <= 105)
#endif
                {
#undef WHALF
#undef WSIZE
#define WSIZE   7
#define WHALF  ((WSIZE-1)/2)
                    fill = 1 ;
                    for (zk = -WHALF ; fill && zk <= WHALF ; zk++)
                    {
                        zi = mri_src->zi[z+zk] ;
                        for (yk = -WHALF ; fill && yk <= WHALF ; yk++)
                        {
                            yi = mri_src->yi[y+yk] ;
                            for (xk = -WHALF ; fill && xk <= WHALF ; xk++)
                            {
                                xi = mri_src->xi[x+xk] ;
                                val = MRIgetVoxVal(mri_src, xi, yi, zi, 0) ;
                                if (val < 85 || val > 110)
                                {
                                    fill = 0 ;  /* not homogeneous enough */
                                }
                            }
                        }
                    }
                }
                else
                {
                    fill = 0 ;
                }
                if (fill)
                {
                    total_filled++ ;
                }
                if (fill)
                {
                    MRIsetVoxVal(mri_bg, x, y, z, 0, BASAL_GANGLIA_FILL) ;
                }
            }
        }
    }

    MRIclose(mri_bg, mri_bg) ;  /* remove small holes */

    /* segment into connected components */
    mriseg = MRIsegment(mri_bg, 1, 255) ;
    fprintf(stderr, "segmenting thick gray regions: %d %d mm segments found\n",
            mriseg->nsegments, WSIZE) ;

    /* dilate into regions that are not on */
    for (i = 0 ; i < 2*WSIZE ; i++)
    {
        MRIsegmentDilateThreshold(mriseg, mri_src, mri_src, 80, 100) ;
    }

    /* fill basal ganglia components */
    MRIclear(mri_bg) ;
    for (total_filled = i = 0 ; i < mriseg->nsegments ; i++)
    {
#define TAL_BG_LEFT_X    -30
#define TAL_BG_RIGHT_X   30
#define TAL_BG_Y         5
#define TAL_BG_Z         5
#define MAX_DIST         25

        mseg = &mriseg->segments[i] ;
        MRIvoxelToTalairach(mri_src, mseg->cx, mseg->cy, mseg->cz,&tx, &ty,&tz);
        dx_left = tx - TAL_BG_LEFT_X ;
        dx_right = tx - TAL_BG_RIGHT_X ;
        dy = ty - TAL_BG_Y ;
        dz = tz - TAL_BG_Z ;
        dist_left = sqrt(dx_left*dx_left+dy*dy+dz*dz) ;
        dist_right = sqrt(dx_right*dx_right+dy*dy+dz*dz) ;
        if (dist_left > MAX_DIST && dist_right > MAX_DIST)
        {
            continue ;
        }
        fprintf(stderr, "filling segment %d with %d voxels\n\tc = "
                "(%2.1f,%2.1f,%2.1f) tal (%2.1f,%2.1f,%2.1f), dist %2.1f,%2.1f\n",
                i, mseg->nvoxels, mseg->cx, mseg->cy, mseg->cz,
                tx, ty, tz, dist_left, dist_right) ;
        MRIsegmentToImage(mri_src, mri_bg, mriseg, i) ;
        total_filled += mseg->nvoxels ;
    }

#if 1
    /*  MRIremoveIslands(mri_bg, mri_bg, 3, .56) ;*/
    MRIbinarize(mri_bg, mri_bg, WM_MIN_VAL, 0, BASAL_GANGLIA_FILL) ;
#endif
    MRIsegmentFree(&mriseg) ;

    MRIunion(mri_dst, mri_bg, mri_dst) ;
    MRIfree(&mri_bg) ;
    if (Gdiag & DIAG_SHOW)
    {
        fprintf(stderr, "%d basal ganglia points filled\n", total_filled);
    }

    return(mri_dst) ;
}
示例#4
0
MRI *
MRIfillVentricles(MRI *mri_src, MRI *mri_dst)
{
    int     width, height, depth, x, y, z, xk, yk, xi, yi, nfilled, total, s ;
    MRI     *mri_filled, *mri_ventricles = NULL ;
    MRI_SEGMENTATION *mriseg ;
    MRI_SEGMENT      *mseg ;
    Real    xt, yt, zt ;

    if (!mri_dst)
    {
        mri_dst = MRIclone(mri_src, NULL) ;
    }

    width = mri_src->width ;
    height = mri_src->height ;
    depth = mri_src->depth ;

    MRIcopy(mri_src, mri_dst) ;
    mri_filled = MRIcopy(mri_src, NULL) ;

    MRIreplaceValues(mri_filled, mri_filled, VENTRICLE_FILL,
                     VENTRICLE_FILL-1) ;

    /* first fill each coronal slice starting from a background seed */
    for (z = 0 ; z < depth ; z++)
    {
        total = 0 ;
        do
        {
            nfilled = 0 ;
            MRIsetVoxVal(mri_filled, 0, 0, z, 0, VENTRICLE_FILL) ;
            for (y = 0 ; y < height ; y++)
            {
                for (x = 0 ; x < width ; x++)
                {
                    if (MRIgetVoxVal(mri_filled, x, y, z, 0) == VENTRICLE_FILL)
                    {
                        for (yk = -1 ; yk <= 1 ; yk++)
                        {
                            yi = mri_src->yi[y+yk] ;
                            for (xk = -1 ; xk <= 1 ; xk++)
                            {
                                xi = mri_src->xi[x+xk] ;
                                if (!MRIgetVoxVal(mri_filled, xi, yi, z, 0))
                                {
                                    nfilled++ ;
                                    MRIsetVoxVal(mri_filled, xi, yi, z, 0, VENTRICLE_FILL) ;
                                }
                            }
                        }
                    }
                }
            }
            total += nfilled ;
        }
        while (nfilled > 0) ;
    }

    MRIcomplement(mri_filled, mri_filled) ;
    MRIreplaceValues(mri_filled, mri_filled, 1, VENTRICLE_FILL) ;
    mriseg = MRIsegment(mri_filled, 1, 255) ;
    fprintf(stderr, "%d segments found...\n", mriseg->nsegments) ;
    if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON)
    {
        MRIwrite(mri_filled, "exterior_filled.mgh") ;
    }
    for (s = 0 ; s < mriseg->nsegments ; s++)
    {
        mseg = &mriseg->segments[s] ;
        if (mseg->nvoxels < 100 ||
                mseg->z1-mseg->z0 < 7)
        {
            continue ;
        }
        MRIvoxelToTalairach(mri_src, mseg->cx, mseg->cy, mseg->cz, &xt, &yt, &zt);
        fprintf(stderr, "added segment %d, nvox=%d, bbox [%d:%d, %d:%d, %d:%d]\n"
                "\tc = %2.1f, %2.1f, %2.1f (tal = %2.1f, %2.1f, %2.1f)\n",
                s, mseg->nvoxels, mseg->x0, mseg->x1, mseg->y0,mseg->y1,mseg->z0,
                mseg->z1, mseg->cx, mseg->cy, mseg->cz, xt, yt, zt) ;
        mri_ventricles = MRIsegmentToImage(mri_filled, mri_ventricles, mriseg, s) ;
    }

    MRIfree(&mri_filled) ;
    MRIsegmentFree(&mriseg) ;

    /* remove voxels close to the midline so that the cc can still be found */
    for (z = 0 ; z < depth ; z++)
    {
        for (y = 0 ; y < height ; y++)
        {
            for (x = 0 ; x < width ; x++)
            {
                MRIvoxelToTalairach(mri_src, x, y, z, &xt, &yt, &zt);
                if (fabs(xt) < 5)
                {
                    MRIsetVoxVal(mri_ventricles, x, y, z, 0, 0) ;
                }
            }
        }
    }

    if (Gdiag & DIAG_WRITE && DIAG_VERBOSE_ON)
    {
        MRIwrite(mri_ventricles, "ventricles.mgh") ;
    }
    MRIunion(mri_ventricles, mri_dst, mri_dst) ;

    MRIfree(&mri_ventricles) ;
    return(mri_dst) ;
}
int
main(int argc, char *argv[]) {
  char          **av, fname[STRLEN], *T1_fname, *PD_fname, *output_dir, *mdir ;
  int           ac, nargs, msec, s ;
  MRI_SURFACE   *mris ;
  MRI           *mri_flash1, *mri_flash2, *mri_masked, *mri_masked_smooth, *mri_kernel,
  *mri_mean, *mri_dif, *mri_binary, *mri_distance ;
  MRI *mri_smooth, *mri_grad, *mri_inner ;
  struct timeb  then ;
  double        l_spring ;
  MRI_SEGMENTATION *mriseg ;


  /* rkt: check for and handle version tag */
  nargs = handle_version_option (argc, argv, "$Id: mris_AA_shrinkwrap.c,v 1.5 2011/03/02 00:04:34 nicks Exp $", "$Name: stable5 $");
  if (nargs && argc - nargs == 1)
    exit (0);
  argc -= nargs;

  Gdiag |= DIAG_SHOW ;
  Progname = argv[0] ;
  ErrorInit(NULL, NULL, NULL) ;
  DiagInit(NULL, NULL, NULL) ;

  memset(&parms, 0, sizeof(parms)) ;

  parms.projection = NO_PROJECTION ;
  parms.tol = 0.05 ;
  parms.check_tol = 1 ;
  parms.ignore_energy = 1 ;
  parms.dt = 0.5f ;
  parms.base_dt = BASE_DT_SCALE*parms.dt ;

  parms.l_spring_norm = 1 ;
  parms.l_shrinkwrap = 0 ;
  parms.l_intensity = 1 ;

  parms.niterations = 0 ;
  parms.write_iterations = 0 /*WRITE_ITERATIONS */;
  parms.integration_type = INTEGRATE_MOMENTUM ;
  parms.momentum = 0.0 /*0.8*/ ;
  parms.l_intensity = 1 ;
  parms.dt_increase = 1.0 /* DT_INCREASE */;
  parms.dt_decrease = 0.50 /* DT_DECREASE*/ ;
  parms.error_ratio = 50.0 /*ERROR_RATIO */;
  /*  parms.integration_type = INTEGRATE_LINE_MINIMIZE ;*/
  parms.l_surf_repulse = 0.0 ;
  parms.l_repulse = 0 /*1*/ ;

  ac = argc ;
  av = argv ;
  for ( ; argc > 1 && ISOPTION(*argv[1]) ; argc--, argv++) {
    nargs = get_option(argc, argv) ;
    argc -= nargs ;
    argv += nargs ;
  }

  mdir = getenv("FREESURFER_HOME") ;
  if (!mdir)
    ErrorExit(ERROR_BADPARM, "FREESURFER_HOME not defined in environment") ;

  if (argc < 4)
    usage_exit() ;

  /* set default parameters for white and gray matter surfaces */
  parms.niterations = 1000 ;
  if (parms.momentum < 0.0)
    parms.momentum = 0.0 /*0.75*/ ;

  TimerStart(&then) ;
  T1_fname = argv[1] ;
  PD_fname = argv[2] ;
  output_dir = argv[3] ;
  fprintf(stderr, "reading volume %s...\n", T1_fname) ;
  mri_flash1 = MRIread(T1_fname) ;
  if (!mri_flash1)
    ErrorExit(ERROR_NOFILE, "%s: could not read input volume %s", Progname, T1_fname) ;

  mri_flash2 = MRIread(PD_fname) ;
  if (!mri_flash2)
    ErrorExit(ERROR_NOFILE, "%s: could not read input volume %s", Progname, T1_fname) ;

  //  setMRIforSurface(mri_flash1);
  sprintf(fname, "%s/lib/bem/ic%d.tri", mdir, ic_init) ;
  mris = MRISread(fname) ;
  if (!mris)
    ErrorExit(ERROR_NOFILE, "%s: could not read icosahedron %s", Progname, fname) ;

  mri_mean = MRImean(mri_flash1, NULL, 5) ;
  MRIwrite(mri_mean, "mean.mgz") ;

  mri_dif = MRIabsdiff(mri_flash1, mri_flash2, NULL) ;
  MRIwrite(mri_dif, "dif.mgz") ;

  mriseg = MRIsegment(mri_mean, 30, 100000) ;
  s = MRIsegmentMax(mriseg) ;
  mri_masked = MRIsegmentToImage(mri_flash1, NULL, mriseg, s) ;
  MRIwrite(mri_masked, "mask.mgz") ;
  MRIsegmentFree(&mriseg) ;

  // MRIthresholdMask(mri_dif, mri_masked, mri_dif, 1, 0) ;
  // MRIwrite(mri_dif, "dif_masked.mgz") ;


  mri_kernel = MRIgaussian1d(2, 0) ;
  mri_smooth = MRIconvolveGaussian(mri_dif, NULL, mri_kernel) ;
  MRIwrite(mri_smooth, "smooth.mgz") ;
  MRIScopyVolGeomFromMRI(mris, mri_smooth) ;
  mris->useRealRAS = 1 ;

  initialize_surface_position(mris, mri_dif, 1, &parms) ;
  MRISwrite(mris, "init") ;
  MRISrepositionToInnerSkull(mris, mri_smooth, &parms) ;

  exit(0) ;
  mri_grad = MRIsobel(mri_smooth, NULL, NULL) ;
  MRIwrite(mri_grad, "grad.mgz") ;
  mri_inner = MRIfindInnerBoundary(mri_dif, mri_grad, NULL, 5.0) ;
  MRIwrite(mri_inner, "inner.mgz") ;
  MRIbinarize(mri_inner, mri_inner, 10, 0, 128) ;

  MRISpositionOptimalSphere(mris, mri_inner, 6) ;
  MRISwrite(mris, "optimal") ;
  exit(0) ;
  parms.sigma = 4 / mri_flash1->xsize ;
  // mri_dist = create_distance_map(mri_masked, NULL, BORDER_VAL, OUTSIDE_BORDER_STEP) ;
  MRISsetVals(mris,parms.sigma) ;
  MRIScopyValToVal2(mris) ;
  MRISsetVals(mris, 0) ;
  sprintf(parms.base_name, "%s_inner_skull%s%s", "test", output_suffix, suffix) ;
  parms.mri_brain = mri_masked ;
  l_spring = parms.l_spring_norm ;
  mri_kernel = MRIgaussian1d(parms.sigma, 0) ;


  mri_binary = MRIbinarize(mri_dif, mri_binary, 40, 0, 128) ;
  MRIwrite(mri_binary, "bin.mgz") ;
  mri_distance = MRIdistanceTransform(mri_binary, NULL, 128, 100, DTRANS_MODE_SIGNED, NULL) ;
  MRIwrite(mri_distance, "dist.mgz") ;
  mri_masked_smooth = MRIconvolveGaussian(mri_distance, NULL, mri_kernel) ;
  MRIfree(&mri_kernel) ;
  MRIwrite(mri_masked_smooth, "dif_smooth.mgz") ;

  MRISwrite(mris, "inner_skull.tri") ;

  msec = TimerStop(&then) ;
  fprintf(stderr,"positioning took %2.1f minutes\n", (float)msec/(60*1000.0f));
  exit(0) ;
  return(0) ;  /* for ansi */
}
示例#6
0
文件: fcd.c 项目: vgurev/freesurfer
static int
augment_thicknesses(FCD_DATA *fcd, 
                    MRI *mri_pvals,
                    double min_dist,
                    double max_dist,
                    double thresh)
{
  int         h, vno ;
  VERTEX      *v ;
  MRI_SURFACE *mris ;
  MRI         *mri_thickness ;
  double      nx, ny, nz, x0, y0, z0, d, x, y, z, val ;
  MRI_SEGMENTATION *mriseg ;

  mriseg = MRIsegment(mri_pvals, thresh, 1e10) ;
  MRIeraseSmallSegments(mriseg, mri_pvals, 20) ;
  MRIremoveSmallSegments(mriseg, 100) ;
  if (Gdiag & DIAG_WRITE)
  {
    MRIwrite(mri_pvals, "pvals.mgz") ;
  }
  MRIsegmentFree(&mriseg) ;

  for (h = 0 ; h <= 1 ; h++)  // do each hemi
  {
    if (h == 0)  // left hemi
    {
      mri_thickness = fcd->lh_thickness_on_lh ;
      mris = fcd->mris_lh ;
    }
    else   // right hemi
    {
      mri_thickness = fcd->rh_thickness_on_rh ;
      mris = fcd->mris_rh ;
    }
    for (vno = 0 ; vno < mris->nvertices ; vno++)
    {
      if (vno == Gdiag_no)
      {
        DiagBreak() ;
      }
      v = &mris->vertices[vno] ;
      if (v->ripflag)
      {
        continue ;
      }
      MRISvertexNormalInVoxelCoords(mris, mri_pvals, vno, &nx, &ny, &nz) ;
      MRISvertexToVoxel(mris, v, mri_pvals, &x0, &y0, &z0) ;

      for (d = 0 ; d <= max_dist ; d += 0.5)
      {
        x = x0+d*nx ;
        y = y0+d*ny ;
        z = z0+d*nz ;
        MRIsampleVolume(mri_pvals, x, y, z, &val) ;
        if (val < thresh)
        {
          break ;
        }
      }
	
      if (d > min_dist)   // a string of unlikely values
      {
        val = MRIgetVoxVal(mri_thickness, vno, 0, 0, 0) ;
        MRIsetVoxVal(mri_thickness, vno, 0, 0, 0, val+d) ;
      }
    }
  }
  return(NO_ERROR) ;
}
示例#7
0
文件: fcd.c 项目: vgurev/freesurfer
int
FCDcomputeThicknessLabels(FCD_DATA *fcd,
                          double thickness_thresh,
                          double sigma,
                          int size_thresh)
{
  MRI    *mri_lh, *mri_rh, *mri_lh_diff, *mri_rh_diff ;
  int    niter, vno, s ;
  MRI_SEGMENTATION *mriseg ;

  fcdFreeLabels(fcd) ;  // free old ones if they exist
  niter = SIGMA_TO_SURFACE_SMOOTH_STEPS(sigma) ;

  // do LH
  mri_lh = MRIclone(fcd->lh_thickness_on_lh, NULL) ;
  mri_rh = MRIclone(fcd->lh_thickness_on_lh, NULL) ;

  exec_progress_callback(1, 8, 0, 1) ;
  MRISwriteFrameToValues(fcd->mris_lh, fcd->lh_thickness_on_lh, 0) ;
  MRISaverageVals(fcd->mris_lh, niter) ;
  MRISreadFrameFromValues(fcd->mris_lh, mri_lh, 0) ;

  exec_progress_callback(2, 8, 0, 1) ;
  MRISwriteFrameToValues(fcd->mris_lh, fcd->rh_thickness_on_lh, 0) ;
  MRISaverageVals(fcd->mris_lh, niter) ;
  MRISreadFrameFromValues(fcd->mris_lh, mri_rh, 0) ;
  mri_lh_diff = MRIsubtract(mri_lh, mri_rh, NULL) ;  // lh minus rh on lh
  MRIfree(&mri_lh);
  MRIfree(&mri_rh) ;

  // do RH
  mri_lh = MRIclone(fcd->lh_thickness_on_rh, NULL) ;
  mri_rh = MRIclone(fcd->lh_thickness_on_rh, NULL) ;

  exec_progress_callback(3, 8, 0, 1) ;
  MRISwriteFrameToValues(fcd->mris_rh, fcd->lh_thickness_on_rh, 0) ;
  MRISaverageVals(fcd->mris_rh, niter) ;
  MRISreadFrameFromValues(fcd->mris_rh, mri_lh, 0) ;

  exec_progress_callback(4, 8, 0, 1) ;
  MRISwriteFrameToValues(fcd->mris_rh, fcd->rh_thickness_on_rh, 0) ;
  MRISaverageVals(fcd->mris_rh, niter) ;
  MRISreadFrameFromValues(fcd->mris_rh, mri_rh, 0) ;
  mri_rh_diff = MRIsubtract(mri_rh, mri_lh, NULL) ;  // lh minus rh on rh
  MRIfree(&mri_lh);
  MRIfree(&mri_rh) ;

  MRIclear(fcd->mri_thickness_increase) ;
  MRIclear(fcd->mri_thickness_decrease) ;
  exec_progress_callback(5, 8, 0, 1) ;

  // process left hemisphere
#if 1
#ifdef HAVE_OPENMP
#pragma omp parallel for shared(fcd, mri_lh_diff, Gdiag_no, thickness_thresh) schedule(static,1)
#endif
#endif
  for (vno = 0 ; vno < fcd->mris_lh->nvertices ; vno++)
  {
    double d ;
    float val, val2, thickness;
    int base_label ;
    VERTEX *v ;

    v = &fcd->mris_lh->vertices[vno] ;
    if (v->ripflag)
    {
      continue ;
    }
    thickness = MRIgetVoxVal(fcd->lh_thickness_on_lh, vno, 0, 0, 0) ;
    if (vno == Gdiag_no)
    {
      DiagBreak() ;
    }
    val = MRIgetVoxVal(mri_lh_diff, vno, 0, 0, 0) ;
    if (fabs(val) < thickness_thresh)
    {
      continue ;
    }

    for (d = 0, base_label = 0 ; d < thickness ; d += 0.25)
    {
      double xv, yv, zv;
      double xs = v->x+d*v->nx ;
      double ys = v->y+d*v->ny ;
      double zs = v->z+d*v->nz ;
      MRISsurfaceRASToVoxel(fcd->mris_lh, 
                            fcd->mri_thickness_increase, 
                            xs, ys, zs, 
                            &xv, &yv, &zv) ;
      int xvi = nint(xv) ;
      int yvi = nint(yv) ;
      int zvi = nint(zv) ;
      int label = MRIgetVoxVal(fcd->mri_aparc, xvi, yvi, zvi, 0) ;
      if (IS_WM(label) == 0 && 
          label >= MIN_CORTICAL_PARCELLATION && 
          label != ctx_lh_unknown)
      {
        if (label != base_label)
        {
          if (base_label)
          {
            break ;
          }
        }
        else
        {
          base_label = label ;
        }
        if (val >= 0)
        {
          val2 = MRIgetVoxVal(fcd->mri_thickness_increase, xvi, yvi, zvi, 0) ;
          // check another thread already populated this voxel
          if (val > val2)
          {
            MRIsetVoxVal(fcd->mri_thickness_increase, xvi, yvi, zvi, 0, val) ;
          }
        }
        else
        {
          val2 = MRIgetVoxVal(fcd->mri_thickness_decrease, xvi, yvi, zvi, 0) ;
          // check if another thread already populated this voxel
          if (val < val2)
          {
            MRIsetVoxVal(fcd->mri_thickness_decrease, xvi, yvi, zvi, 0, val) ;
          }
        }
      }
    }
  }

  exec_progress_callback(6, 8, 0, 1) ;

  // now do right hemisphere
#if 1
#ifdef HAVE_OPENMP
  #pragma omp parallel for shared(fcd, mri_rh_diff, Gdiag_no, thickness_thresh) schedule(static,1)
#endif
#endif
  for (vno = 0 ; vno < fcd->mris_rh->nvertices ; vno++)
  {
    double d  ;
    float val, val2, thickness;
    int base_label ;
    VERTEX *v ;

    v = &fcd->mris_rh->vertices[vno] ;
    if (v->ripflag)
    {
      continue ;
    }
    if (vno == Gdiag_no)
    {
      DiagBreak() ;
    }
    val = MRIgetVoxVal(mri_rh_diff, vno, 0, 0, 0) ;
    if (fabs(val) < thickness_thresh)
    {
      continue ;
    }
    thickness = MRIgetVoxVal(fcd->rh_thickness_on_rh, vno, 0, 0, 0) ;

    for (d = 0, base_label = 0; d < thickness ; d += 0.25)
    {
      double xv, yv, zv;
      double xs = v->x+d*v->nx ;
      double ys = v->y+d*v->ny ;
      double zs = v->z+d*v->nz ;
      MRISsurfaceRASToVoxel(fcd->mris_rh, 
                            fcd->mri_thickness_increase,
                            xs, ys, zs,
                            &xv, &yv, &zv) ;
      int xvi = nint(xv) ;
      int yvi = nint(yv) ;
      int zvi = nint(zv) ;
      int label = MRIgetVoxVal(fcd->mri_aparc, xvi, yvi, zvi, 0) ;
      if (IS_WM(label) == 0 && 
          label >= MIN_CORTICAL_PARCELLATION && 
          label != ctx_rh_unknown)
      {
        if (label != base_label)
        {
          if (base_label)
          {
            break ;
          }
        }
        else
        {
          base_label = label ;
        }

        if (val >= 0)
        {
          val2 = MRIgetVoxVal(fcd->mri_thickness_increase, xvi, yvi, zvi, 0) ;
          if (val > val2)
          {
            MRIsetVoxVal(fcd->mri_thickness_increase, xvi, yvi, zvi, 0, val) ;
          }
        }
        else
        {
          val2 = MRIgetVoxVal(fcd->mri_thickness_decrease, xvi, yvi, zvi, 0) ;
          if (val < val2)
          {
            MRIsetVoxVal(fcd->mri_thickness_decrease, xvi, yvi, zvi, 0, val) ;
          }
        }
      }
    }
  }

  exec_progress_callback(7, 8, 0, 1) ;
  mriseg = MRIsegment(fcd->mri_thickness_increase, thickness_thresh, 1e10) ;
  MRIeraseSmallSegments(mriseg, fcd->mri_thickness_increase, thickness_thresh) ;
  MRIsegmentFree(&mriseg) ;
  MRIclose(fcd->mri_thickness_increase, fcd->mri_thickness_increase) ;
  mriseg = MRIsegment(fcd->mri_thickness_increase, thickness_thresh, 1e10) ;
  MRIremoveSmallSegments(mriseg, size_thresh) ;
  printf("segmenting volume at threshold %2.1f with %d "
         "smoothing iters yields %d segments\n",
         thickness_thresh, niter,mriseg->nsegments) ;
  fflush(stdout) ;

  exec_progress_callback(8, 8, 0, 1) ;
  fcd->nlabels = mriseg->nsegments ;
  for (s = 0 ; s < mriseg->nsegments ; s++)
  {
    int label ;

    fcd->labels[s] = MRIsegmentToLabel(mriseg, fcd->mri_thickness_increase, s) ;
    label = most_frequent_label(fcd->mri_aparc, &mriseg->segments[s]) ;
    strcpy(fcd->labels[s]->name, cma_label_to_name(label)) ;
  }
  sort_labels(fcd) ;

  MRIadd(fcd->mri_thickness_increase, fcd->mri_thickness_decrease, fcd->mri_thickness_difference);

  for (s = 0 ; s < mriseg->nsegments ; s++)
  {
    printf("%s: %2.3fmm\n", fcd->label_names[s], fcd->labels[s]->avg_stat) ;
    fflush(stdout) ;
  }
  MRIfree(&mri_lh_diff) ;
  MRIfree(&mri_rh_diff) ;
  MRIsegmentFree(&mriseg) ;

  return(fcd->nlabels) ;
}