int
main(int argc, char *argv[]) {
  char         **av, surf_fname[100], *template_fname, *out_fname, *surf_dir,
  *hemi, *sphere_name ;
  int          ac, nargs ;
  MRI_SURFACE  *mris ;
  MRI_SP       *mrisp, *mrisp_template ;

  /* rkt: check for and handle version tag */
  nargs = handle_version_option (argc, argv, "$Id: mris_add_template.c,v 1.8 2011/03/02 00:04:26 nicks Exp $", "$Name:  $");
  if (nargs && argc - nargs == 1)
    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 < 5)
    usage_exit() ;

  surf_dir = argv[1] ;
  hemi = argv[2] ;
  sphere_name = argv[3] ;
  out_fname = template_fname = argv[4] ;
  if (argc > 5)
    out_fname = argv[5] ;

  sprintf(surf_fname, "%s/%s.%s", surf_dir, hemi, sphere_name) ;
  fprintf(stderr, "reading new surface %s...\n", surf_fname) ;
  mris = MRISread(surf_fname) ;
  if (!mris)
    ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
              Progname, surf_fname) ;
  MRISsaveVertexPositions(mris, ORIGINAL_VERTICES) ;

  if (!FileExists(template_fname))  /* first time - create it */
  {
    fprintf(stderr, "creating new parameterization...\n") ;
    mrisp_template = MRISPalloc(scale, PARAM_IMAGES);
  } else {
    fprintf(stderr, "reading template parameterization from %s...\n",
            template_fname) ;
    mrisp_template = MRISPread(template_fname) ;
    if (!mrisp_template)
      ErrorExit(ERROR_NOFILE, "%s: could not open template file %s",
                Progname, template_fname) ;
  }
  /*
    first read in inflated surface and use it to build the first template
    set.
    */
  sprintf(surf_fname, "%s/%s.%s", surf_dir, hemi, INFLATED_NAME) ;
  if (MRISreadVertexPositions(mris, surf_fname) != NO_ERROR)
    ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
              Progname, surf_fname) ;

  MRISsetNeighborhoodSize(mris, nbrs) ;
  MRIScomputeMetricProperties(mris) ;
  MRIScomputeSecondFundamentalForm(mris) ;
  MRISuseMeanCurvature(mris) ;
  MRISaverageCurvatures(mris, navgs) ;
  MRISrestoreVertexPositions(mris, ORIGINAL_VERTICES) ;
  MRISnormalizeCurvature(mris, which_norm) ;
  fprintf(stderr, "computing parameterization for surface %s...\n",surf_fname);
  mrisp = MRIStoParameterization(mris, NULL, scale, 0) ;
  MRISPcombine(mrisp, mrisp_template, 0) ;
  MRISPfree(&mrisp) ;

  /*
    now do the same thing with the smoothwm curvatures.
    */
  sprintf(surf_fname, "%s/%s.%s", surf_dir, hemi, SMOOTH_NAME) ;
  if (MRISreadVertexPositions(mris, surf_fname) != NO_ERROR)
    ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
              Progname, surf_fname) ;
  MRIScomputeMetricProperties(mris) ;
  if (curvature_fname[0])
    MRISreadCurvatureFile(mris, curvature_fname) ;
  else {
    MRIScomputeSecondFundamentalForm(mris) ;
    MRISuseMeanCurvature(mris) ;
  }
  MRISaverageCurvatures(mris, navgs) ;
  MRISrestoreVertexPositions(mris, ORIGINAL_VERTICES) ;
  if (curvature_fname[0])
    fprintf(stderr, "computing parameterization for surface %s (%s)...\n",
            surf_fname, curvature_fname);
  else
    fprintf(stderr, "computing parameterization for surface %s...\n",
            surf_fname);
  MRISnormalizeCurvature(mris, which_norm) ;
  mrisp = MRIStoParameterization(mris, NULL, scale, 0) ;
  MRISPcombine(mrisp, mrisp_template, 3) ;

  fprintf(stderr, "writing updated template to %s...\n", out_fname) ;
  MRISPwrite(mrisp_template, out_fname) ;

  MRISPfree(&mrisp) ;
  MRISPfree(&mrisp_template) ;
  MRISfree(&mris) ;
  exit(0) ;
  return(0) ;  /* for ansi */
}
int
main(int argc, char *argv[]) {
  int           nargs, msec, order, i, number, vno, nnum, m, k, b1, b2, cno, flag=0, fno;
  struct timeb  then ;
  MRIS          *mris_in, *mris_out, *mris_high;
  MRI_SP        *mrisp ;
  VERTEX        *vm_out, *vm_high, *v;
  float         s_jkm, area;

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

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

  if (argc < 4)
    ErrorExit(ERROR_BADPARM,
              "usage: %s <input surface> <orig surface> <finest order> <output surface>", Progname);

  TimerStart(&then) ;

  order = atoi (argv[3]);
  fprintf(stdout, "Set %s as the finest scale level\n", argv[3]);
  if (order > 7)
    ErrorExit(ERROR_BADPARM, "the highest order is 7\n");

  /*Spherical Wavelet Analysis*/

  if (ANALYSIS&&!CURV) {
    mris_in = MRISread(argv[1]) ;
    if (!mris_in)
      ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
                Progname, argv[1]) ;
    fprintf(stdout, "Reading input spherical surface from %s\n", argv[1]);
    MRISreadOriginalProperties(mris_in, argv[2]) ;
    fprintf(stdout, "Reading original surface from %s orig area is %f\n", argv[2],mris_in->orig_area);

    mris_out = ReadIcoByOrder(order, 100);
    for (m = 0; m<mris_out->nvertices; m++)
      mris_out->vertices[m].nsize=1;
    mrisp = MRISPalloc(1, 3);
#if 1
    MRIScoordsToParameterization(mris_in, mrisp, 1, ORIGINAL_VERTICES) ;
    MRISPblur(mrisp, mrisp, 1, 0);
    MRISPblur(mrisp, mrisp, 1, 1);
    MRISPblur(mrisp, mrisp, 1, 2);
    MRIScoordsFromParameterization(mrisp, mris_out) ;
#else
    MRISreadOriginalProperties(mris_out, argv[2]) ;
#endif
#if 1 /*just to test if the parameterization is correct */
    MRISsaveVertexPositions(mris_out, TMP_VERTICES) ;
    MRISrestoreVertexPositions(mris_out, ORIGINAL_VERTICES) ;
    MRISupdateSurface(mris_out);
    fprintf(stderr, "original area becomes %f\n", mris_out->total_area);
    center_brain(mris_out, mris_out);
    MRISscaleBrain(mris_out, mris_out, sqrt(100000.0f/mris_out->total_area)) ;
    MRISupdateSurface(mris_out);
    for (fno=0; fno<mris_out->nfaces; fno++)
      area += mris_out->faces[fno].area;
    fprintf(stderr, "original area becomes %f\n", area);
    //MRISwrite(mris_out, "/space/xrt/1/users/btquinn/buckner_paper/010223_61223/surf/lh.sampled") ;
    MRISsaveVertexPositions(mris_out, ORIGINAL_VERTICES) ;
    MRISrestoreVertexPositions(mris_out, TMP_VERTICES) ;
#endif

    /* Initialize Ij,k*/
    for (vno = 0 ; vno<mris_out->nvertices; vno++) {
      vm_out = &mris_out->vertices[vno];
      vm_out->val = 1;
    }

    /*Iteratively compute Ij,k*/
    for (i=order;i>0;i--) {
      mris_high = ReadIcoByOrder(i, 100); //higher order surface
      for (m = 0; m<mris_high->nvertices; m++)
        mris_high->vertices[m].nsize=1;
      MRISsetNeighborhoodSize(mris_high, 3) ;
      number = IcoNVtxsFromOrder(i-1); //the start of m vertices
      for (m = number; m<mris_high->nvertices; m++) {
        vm_out = &mris_out->vertices[m];
        vm_high = &mris_high->vertices[m];
        flag=0;
        for (nnum=0; nnum<vm_high->vnum; nnum++)
          if ( vm_high->v[nnum]<number ) //A(j,m)
          {
            k = vm_high->v[nnum];
            v = &mris_out->vertices[k];
            v->val += 0.5*vm_out->val ;
          }
        for (; nnum<vm_high->v2num; nnum++)
          if ( vm_high->v[nnum]<number ) //B(j,m)
          {
            k = vm_high->v[nnum];
            if (flag==0) b1=k;
            else b2=k;
            flag++;
            v = &mris_out->vertices[k];
            v->val += 0.125*vm_out->val ;
          }
        for (; nnum<vm_high->v3num; nnum++)
          if ( vm_high->v[nnum]<number ) //C(j,m)
          {
            k = vm_high->v[nnum];
            flag=0; //C has to be a second-order neighbor of B
            for (cno=mris_high->vertices[b1].vnum; cno<mris_high->vertices[b1].v2num;cno++)
              if (mris_high->vertices[b1].v[cno]==k) flag=1;
            for (cno=mris_high->vertices[b2].vnum; cno<mris_high->vertices[b2].v2num;cno++)
              if (mris_high->vertices[b2].v[cno]==k) flag=1;
            if (flag) {
              v = &mris_out->vertices[k];
              v->val -= 0.0625*vm_out->val ;
            }
          }
      }
    }


    /*Analysis Stage I:*/
    for (i=order;i>0;i--) {
      mris_high = ReadIcoByOrder(i, 100); //higher order surface
      for (m = 0; m<mris_high->nvertices; m++)
        mris_high->vertices[m].nsize=1;
      MRISsetNeighborhoodSize(mris_high, 3) ;

      number = IcoNVtxsFromOrder(i-1); //the start of m vertices
      /* compute Yj,m for each m vertices */
      for (m = number; m<mris_high->nvertices; m++) {
        vm_out = &mris_out->vertices[m];
        vm_high = &mris_high->vertices[m];
        flag=0;
        for (nnum=0; nnum<vm_high->vnum; nnum++)  //first order neighborhood
          if ( vm_high->v[nnum]<number ) //neighbor A(j,m)
          {
            k = vm_high->v[nnum] ;
            v = &mris_out->vertices[k];
            vm_out->origx -= 0.5*v->origx;
            vm_out->origy -= 0.5*v->origy;
            vm_out->origz -= 0.5*v->origz;
          }
        for (; nnum<vm_high->v2num; nnum++) //second order neighborhood
          if ( vm_high->v[nnum]<number ) //neighbor B(j,m)
          {
            k = vm_high->v[nnum] ;
            if (flag==0) b1=k;
            else b2=k;
            flag++;
            v = &mris_out->vertices[k];
            vm_out->origx -= 0.125*v->origx;
            vm_out->origy -= 0.125*v->origy;
            vm_out->origz -= 0.125*v->origz;
          }
        for (; nnum<vm_high->v3num; nnum++)
          if ( vm_high->v[nnum]<number ) //neighbor C(j,m)
          {
            k = vm_high->v[nnum] ;
            flag=0; //C has to be a second-order neighbor of B
            for (cno=mris_high->vertices[b1].vnum; cno<mris_high->vertices[b1].v2num;cno++)
              if (mris_high->vertices[b1].v[cno]==k) flag=1;
            for (cno=mris_high->vertices[b2].vnum; cno<mris_high->vertices[b2].v2num;cno++)
              if (mris_high->vertices[b2].v[cno]==k) flag=1;
            if (flag) {
              v = &mris_out->vertices[k];
              vm_out->origx += 0.0625*v->origx;
              vm_out->origy += 0.0625*v->origy;
              vm_out->origz += 0.0625*v->origz;
            }
          }
      }


      /*Analysis Stage II: */
      /*Compute Lamda(j,k) using the Yita(j,m)*/
      for (m = number; m<mris_high->nvertices; m++) {
        vm_out = &mris_out->vertices[m];
        vm_high = &mris_high->vertices[m];
        for (nnum=0; nnum<vm_high->vnum; nnum++)
          if ( vm_high->v[nnum]<number ) //A(j,m)
          {
            k = vm_high->v[nnum];
            v = &mris_out->vertices[k];
            s_jkm = vm_out->val/2/v->val;
            v->origx += s_jkm*vm_out->origx;
            v->origy += s_jkm*vm_out->origy;
            v->origz += s_jkm*vm_out->origz;
          }

      }

    }

    MRISsaveVertexPositions(mris_out, TMP_VERTICES) ;
    MRISrestoreVertexPositions(mris_out, ORIGINAL_VERTICES) ;
#if 0
    for (m=0;m<mris_out->nvertices;m++)
      if (mris_out->vertices[m].z>6)
        fprintf(stdout, "%d %f %f %f\n", m,mris_out->vertices[m].x, mris_out->vertices[m].y, mris_out->vertices[m].z);
    //mris_high = ReadIcoByOrder(0, 100);
    //for (m=0;m<mris_high->nvertices;m++)
    //{mris_high->vertices[m].x=mris_out->vertices[m].x;
    //mris_high->vertices[m].y=mris_out->vertices[m].y;
    //mris_high->vertices[m].z=mris_out->vertices[m].z;
    //}
    //MRISwrite(mris_high, "/space/xrt/1/users/btquinn/buckner_paper/010223_61223/surf/lh.sampled") ;
#endif
    fprintf(stdout, "Writing wavelets coefficient of original surface to %s\n", argv[4]);
    MRISwrite(mris_out,argv[4] ) ;
    MRISrestoreVertexPositions(mris_out, TMP_VERTICES) ;
    MRISPfree(&mrisp) ;
    MRISfree(&mris_in) ;
    /*End of Analysis*/
  } else if (ANALYSIS&&CURV) {
    mris_in = MRISread(argv[1]) ;
    if (!mris_in)
      ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
                Progname, argv[1]) ;
    fprintf(stdout, "Reading input spherical surface from %s\n", argv[1]);

    MRISreadCurvatureFile(mris_in, argv[2]) ;
    fprintf(stdout, "Reading input from %s\n", argv[2]);

    mris_out = ReadIcoByOrder(order, 100);
    for (m = 0; m<mris_out->nvertices; m++)
      mris_out->vertices[m].nsize=1;
    //mrisp = MRISPalloc(1, 3);
    mrisp = MRIStoParameterization(mris_in, NULL, 1, 0) ;
    //MRISPblur(mrisp, mrisp, 1, 0);
    MRISfromParameterization(mrisp, mris_out, 0) ;
    //MRISwriteCurvature(mris_out,"/space/xrt/1/users/btquinn/buckner_paper/010223_61223/surf/lh.thickness.sampled");
    /* Initialize Ij,k*/
    for (vno = 0 ; vno<mris_out->nvertices; vno++) {
      vm_out = &mris_out->vertices[vno];
      vm_out->val = 1;
    }

    /*Iteratively compute Ij,k*/
    for (i=order;i>0;i--) {
      mris_high = ReadIcoByOrder(i, 100); //higher order surface
      for (m = 0; m<mris_high->nvertices; m++)
        mris_high->vertices[m].nsize=1;
      MRISsetNeighborhoodSize(mris_high, 3) ;
      number = IcoNVtxsFromOrder(i-1); //the start of m vertices
      for (m = number; m<mris_high->nvertices; m++) {
        vm_out = &mris_out->vertices[m];
        vm_high = &mris_high->vertices[m];
        flag=0;
        for (nnum=0; nnum<vm_high->vnum; nnum++)
          if ( vm_high->v[nnum]<number ) //A(j,m)
          {
            k = vm_high->v[nnum];
            v = &mris_out->vertices[k];
            v->val += 0.5*vm_out->val ;
          }
        for (; nnum<vm_high->v2num; nnum++)
          if ( vm_high->v[nnum]<number ) //B(j,m)
          {
            k = vm_high->v[nnum];
            if (flag==0) b1=k;
            else b2=k;
            flag++;
            v = &mris_out->vertices[k];
            v->val += 0.125*vm_out->val ;
          }
        for (; nnum<vm_high->v3num; nnum++)
          if ( vm_high->v[nnum]<number ) //C(j,m)
          {
            k = vm_high->v[nnum];
            flag=0; //C has to be a second-order neighbor of B
            for (cno=mris_high->vertices[b1].vnum; cno<mris_high->vertices[b1].v2num;cno++)
              if (mris_high->vertices[b1].v[cno]==k) flag=1;
            for (cno=mris_high->vertices[b2].vnum; cno<mris_high->vertices[b2].v2num;cno++)
              if (mris_high->vertices[b2].v[cno]==k) flag=1;
            if (flag) {
              v = &mris_out->vertices[k];
              v->val -= 0.0625*vm_out->val ;
            }
          }
      }
    }


    /*Analysis Stage I:*/
    for (i=order;i>0;i--) {
      mris_high = ReadIcoByOrder(i, 100); //higher order surface
      for (m = 0; m<mris_high->nvertices; m++)
        mris_high->vertices[m].nsize=1;
      MRISsetNeighborhoodSize(mris_high, 3) ;

      number = IcoNVtxsFromOrder(i-1); //the start of m vertices
      /* compute Yj,m for each m vertices */
      for (m = number; m<mris_high->nvertices; m++) {
        vm_out = &mris_out->vertices[m];
        vm_high = &mris_high->vertices[m];
        flag=0;
        for (nnum=0; nnum<vm_high->vnum; nnum++)  //first order neighborhood
          if ( vm_high->v[nnum]<number ) //neighbor A(j,m)
          {
            k = vm_high->v[nnum] ;
            v = &mris_out->vertices[k];
            vm_out->curv -= 0.5*v->curv;
          }
        for (; nnum<vm_high->v2num; nnum++) //second order neighborhood
          if ( vm_high->v[nnum]<number ) //neighbor B(j,m)
          {
            k = vm_high->v[nnum] ;
            if (flag==0) b1=k;
            else b2=k;
            flag++;
            v = &mris_out->vertices[k];
            vm_out->curv -= 0.125*v->curv;
          }
        for (; nnum<vm_high->v3num; nnum++)
          if ( vm_high->v[nnum]<number ) //neighbor C(j,m)
          {
            k = vm_high->v[nnum] ;
            flag=0; //C has to be a second-order neighbor of B
            for (cno=mris_high->vertices[b1].vnum; cno<mris_high->vertices[b1].v2num;cno++)
              if (mris_high->vertices[b1].v[cno]==k) flag=1;
            for (cno=mris_high->vertices[b2].vnum; cno<mris_high->vertices[b2].v2num;cno++)
              if (mris_high->vertices[b2].v[cno]==k) flag=1;
            if (flag) {
              v = &mris_out->vertices[k];
              vm_out->curv += 0.0625*v->curv;
            }
          }
      }


      /*Analysis Stage II: */
      /*Compute Lamda(j,k) using the Yita(j,m)*/
      for (m = number; m<mris_high->nvertices; m++) {
        vm_out = &mris_out->vertices[m];
        vm_high = &mris_high->vertices[m];
        for (nnum=0; nnum<vm_high->vnum; nnum++)
          if ( vm_high->v[nnum]<number ) //A(j,m)
          {
            k = vm_high->v[nnum];
            v = &mris_out->vertices[k];
            s_jkm = vm_out->val/2/v->val;
            v->curv += s_jkm*vm_out->curv;
          }

      }
    }

    fprintf(stdout, "Writing wavelets coefficient of original surface to %s\n", argv[4]);
    MRISwriteCurvature(mris_out,argv[4] ) ;
    MRISPfree(&mrisp) ;
    MRISfree(&mris_in) ;
    /*End of Analysis*/
  } else if (SYNTHESIS) /*Spherical Wavelet Synthesis*/
  {
    mris_out = ReadIcoByOrder(order, 100); //higher order surface
    fprintf(stdout, "Creating a %d order spherical surface\n", order);
    MRISreadOriginalProperties(mris_out, argv[1]) ;
    fprintf(stdout, "Reading wavelet coefficients from %s\n", argv[1]);
    for (m = 0; m<mris_out->nvertices; m++)
      mris_out->vertices[m].nsize=1;
    MRISsetNeighborhoodSize(mris_out, 3) ;

    if (COMPARE) {
      mris_in = MRISread(fname);
      for (i=1; i<IcoNVtxsFromOrder(order-1); i++) {
        if (mris_out->vertices[i].origx==0)
          area =  fabs(mris_out->vertices[i].origx-mris_in->vertices[i].x);
        else area = fabs((mris_out->vertices[i].origx-mris_in->vertices[i].x)/mris_out->vertices[i].origx);
        if ( area>5 ) {
          mris_out->vertices[i].origx = mris_in->vertices[i].x ;
          fprintf(stdout, "%d %f\n", i, area);
        }
        if (mris_out->vertices[i].origy==0)
          area =  fabs(mris_out->vertices[i].origy-mris_in->vertices[i].y);
        else area = fabs((mris_out->vertices[i].origy-mris_in->vertices[i].y)/mris_out->vertices[i].origy);
        if ( area>5 ) {
          mris_out->vertices[i].origy = mris_in->vertices[i].y ;
          fprintf(stdout, "%d %f\n", i, area);
        }
        if (mris_out->vertices[i].origz==0)
          area =  fabs(mris_out->vertices[i].origz-mris_in->vertices[i].z);
        else area = fabs((mris_out->vertices[i].origz-mris_in->vertices[i].z)/mris_out->vertices[i].origz);
        if ( area>5 ) {
          mris_out->vertices[i].origz = mris_in->vertices[i].z ;
          fprintf(stdout, "%d %f\n", i, area);
        }
      }
      MRISfree(&mris_in);
    }

    fprintf(stdout, "Recover the surface using %s order coefficients\n",argv[2]);
    number = IcoNVtxsFromOrder(atoi(argv[2]));
    for (m = number; m<mris_out->nvertices; m++) {
      mris_out->vertices[m].origx = 0;
      mris_out->vertices[m].origy = 0;
      mris_out->vertices[m].origz = 0;
    }

    /*Initialize Ij,k*/
    for (vno = 0; vno<mris_out->nvertices; vno++) {
      vm_out = &mris_out->vertices[vno];
      vm_out->val = 1;
    }

    /*Iteratively compute Ij,k*/
    for (i=order;i>0;i--) {
      mris_high = ReadIcoByOrder(i, 100); //higher order surface
      for (m = 0; m<mris_high->nvertices; m++)
        mris_high->vertices[m].nsize=1;
      MRISsetNeighborhoodSize(mris_high, 3) ;
      number = IcoNVtxsFromOrder(i-1); //the start of m vertices
      for (m = number; m<mris_high->nvertices; m++) {
        vm_out = &mris_out->vertices[m];
        vm_high = &mris_high->vertices[m];
        flag=0;
        for (nnum=0; nnum<vm_high->vnum; nnum++)
          if ( vm_high->v[nnum]<number ) //A(j,m)
          {
            k = vm_high->v[nnum];
            v = &mris_out->vertices[k];
            v->val += 0.5*vm_out->val ;
          }
        for (; nnum<vm_high->v2num; nnum++)
          if ( vm_high->v[nnum]<number ) //B(j,m)
          {
            k = vm_high->v[nnum];
            if (flag==0) b1=k;
            else b2=k;
            flag++;
            v = &mris_out->vertices[k];
            v->val += 0.125*vm_out->val ;
          }
        for (; nnum<vm_high->v3num; nnum++)
          if ( vm_high->v[nnum]<number ) //C(j,m)
          {
            k = vm_high->v[nnum];
            flag=0; //C has to be a second-order neighbor of B
            for (cno=mris_high->vertices[b1].vnum; cno<mris_high->vertices[b1].v2num;cno++)
              if (mris_high->vertices[b1].v[cno]==k) flag=1;
            for (cno=mris_high->vertices[b2].vnum; cno<mris_high->vertices[b2].v2num;cno++)
              if (mris_high->vertices[b2].v[cno]==k) flag=1;
            if (flag) {
              v = &mris_out->vertices[k];
              v->val -= 0.0625*vm_out->val ;
            }
          }
      }
    }


    for (i=1;i<=order;i++) {
      mris_high = ReadIcoByOrder(i, 100); //higher order surface
      for (m = 0; m<mris_high->nvertices; m++)
        mris_high->vertices[m].nsize=1;
      MRISsetNeighborhoodSize(mris_high, 3) ;
      number = IcoNVtxsFromOrder(i-1); //the start of m vertices

      /* Synthesis Stage I */
      /* Compute Lamda(j+1,k) using the Yita(j,m) */
      for (m = number; m<mris_high->nvertices; m++) {
        vm_out = &mris_out->vertices[m];
        vm_high = &mris_high->vertices[m];
        for (nnum=0; nnum<vm_high->vnum; nnum++)
          if ( vm_high->v[nnum]<number ) //A(j,m)
          {
            k = vm_high->v[nnum];
            v = &mris_out->vertices[k];
            s_jkm = vm_out->val/2/v->val;
            v->origx -= s_jkm*vm_out->origx;
            v->origy -= s_jkm*vm_out->origy;
            v->origz -= s_jkm*vm_out->origz;
          }
      }

      /* compute Lamda(j+1,m) for each m vertices */
      for (m = number; m<mris_high->nvertices; m++) {
        vm_out = &mris_out->vertices[m];
        vm_high = &mris_high->vertices[m];
        flag=0;
        for (nnum=0; nnum<vm_high->vnum; nnum++)  //first order neighborhood
          if ( vm_high->v[nnum]<number ) //neighbor A(j,m)
          {
            k = vm_high->v[nnum] ;
            v = &mris_out->vertices[k];
            vm_out->origx += 0.5*v->origx;
            vm_out->origy += 0.5*v->origy;
            vm_out->origz += 0.5*v->origz;
          }
        for (; nnum<vm_high->v2num; nnum++) //second order neighborhood
          if ( vm_high->v[nnum]<number ) //neighbor B(j,m)
          {
            k = vm_high->v[nnum] ;
            if (flag==0) b1=k;
            else b2=k;
            flag++;
            v = &mris_out->vertices[k];
            vm_out->origx += 0.125*v->origx;
            vm_out->origy += 0.125*v->origy;
            vm_out->origz += 0.125*v->origz;
          }
        for (; nnum<vm_high->v3num; nnum++) //third order neighborhood
          if ( vm_high->v[nnum]<number ) //neighbor C(j,m)
          {
            k = vm_high->v[nnum] ;
            flag=0; //C has to be a second-order neighbor of B
            for (cno=mris_high->vertices[b1].vnum; cno<mris_high->vertices[b1].v2num;cno++)
              if (mris_high->vertices[b1].v[cno]==k) flag=1;
            for (cno=mris_high->vertices[b2].vnum; cno<mris_high->vertices[b2].v2num;cno++)
              if (mris_high->vertices[b2].v[cno]==k) flag=1;
            if (flag) {
              v = &mris_out->vertices[k];
              vm_out->origx -= 0.0625*v->origx;
              vm_out->origy -= 0.0625*v->origy;
              vm_out->origz -= 0.0625*v->origz;
            }
          }
      }
    }

    MRISsaveVertexPositions(mris_out, TMP_VERTICES) ;
    MRISrestoreVertexPositions(mris_out, ORIGINAL_VERTICES) ;
    fprintf(stdout, "Writing recovered surface to %s\n", argv[4]);
    MRISwrite(mris_out, argv[4]) ;
#if 0
    mris_high = ReadIcoByOrder(4, 100);
    for (m=0;m<mris_high->nvertices;m++) {
      mris_high->vertices[m].x=mris_out->vertices[m].x;
      mris_high->vertices[m].y=mris_out->vertices[m].y;
      mris_high->vertices[m].z=mris_out->vertices[m].z;
    }
    MRISwrite(mris_high, "/space/xrt/1/users/btquinn/buckner_paper/010223_61223/surf/lh.wavelet.recon") ;
#endif
    MRISrestoreVertexPositions(mris_out, TMP_VERTICES) ;
    /*End of Synthesis*/
  }

  MRISfree(&mris_out);
  MRISfree(&mris_high) ;
  msec = TimerStop(&then) ;
  fprintf(stdout, "spherical wavelet took %2.1f minutes\n", (float)msec/(1000.0f*60.0f));
  exit(0) ;
  return(0) ;
}
int
main(int argc, char *argv[])
{
  char         **av, surf_fname[STRLEN], *template_fname, *hemi, *sphere_name,
  *cp, *subject, fname[STRLEN] ;
  int          ac, nargs, ino, sno, nbad = 0, failed, n,nfields;
  VERTEX *v;
  VALS_VP *vp;
  MRI_SURFACE  *mris ;
  MRI_SP       *mrisp, /* *mrisp_aligned,*/ *mrisp_template ;
  INTEGRATION_PARMS parms ;

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

  memset(&parms, 0, sizeof(parms)) ;
  Progname = argv[0] ;
  ErrorInit(NULL, NULL, NULL) ;
  DiagInit(NULL, NULL, NULL) ;
  /* setting default values for vectorial registration */
  setParms(&parms);

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

  if (argc < 5) usage_exit() ;

  /* multiframe registration */
  if (multiframes) parms.flags |= IP_USE_MULTIFRAMES;

  if (!strlen(subjects_dir))  /* not specified on command line*/
  {
    cp = getenv("SUBJECTS_DIR") ;
    if (!cp)
      ErrorExit(ERROR_BADPARM,
                "%s: SUBJECTS_DIR not defined in environment.\n",
                Progname) ;
    strcpy(subjects_dir, cp) ;
  }
  hemi = argv[1] ;
  sphere_name = argv[2] ;
  template_fname = argv[argc-1] ;
  if (1 || !FileExists(template_fname))  /* first time - create it */
  {
    fprintf(stderr, "creating new parameterization...\n") ;
    if (multiframes)
    {
      mrisp_template = MRISPalloc(scale, atlas_size * IMAGES_PER_SURFACE );
      /*    if (no_rot)  /\* don't do rigid alignment *\/ */
      /*     mrisp_aligned = NULL ; */
      /*    else */
      /*     mrisp_aligned = MRISPalloc(scale, PARAM_FRAMES);  */
    }
    else
    {
      mrisp_template = MRISPalloc(scale, PARAM_IMAGES);
      /*    if (no_rot)  /\* don't do rigid alignment *\/ */
      /*     mrisp_aligned = NULL ; */
      /*    else */
      /*     mrisp_aligned = MRISPalloc(scale, PARAM_IMAGES);  */
    }

  }
  else
  {
    fprintf(stderr, "reading template parameterization from %s...\n",
            template_fname) ;
    /* mrisp_aligned = NULL ; */
    mrisp_template = MRISPread(template_fname) ;
    if (!mrisp_template)
      ErrorExit(ERROR_NOFILE, "%s: could not open template file %s",
                Progname, template_fname) ;
  }

  argv += 3 ;
  argc -= 3 ;
  for (ino = 0 ; ino < argc-1 ; ino++)
  {
    failed = 0 ;
    subject = argv[ino] ;
    fprintf(stderr, "\nprocessing subject %s (%d of %d)\n", subject,
            ino+1, argc-1) ;
    sprintf(surf_fname, "%s/%s/surf/%s.%s",
            subjects_dir, subject, hemi, sphere_name) ;
    fprintf(stderr, "reading spherical surface %s...\n", surf_fname) ;
    mris = MRISread(surf_fname) ;
    if (!mris)
    {
      nbad++ ;
      ErrorPrintf(ERROR_NOFILE, "%s: could not read surface file %s",
                  Progname, surf_fname) ;
      exit(1) ;
    }
    if (annot_name)
    {
      if (MRISreadAnnotation(mris, annot_name) != NO_ERROR)
        ErrorExit(ERROR_BADPARM,
                  "%s: could not read annot file %s",
                  Progname, annot_name) ;
      MRISripMedialWall(mris) ;
    }

    MRISsaveVertexPositions(mris, CANONICAL_VERTICES) ;
    MRIScomputeMetricProperties(mris) ;
    MRISstoreMetricProperties(mris) ;

    if (Gdiag & DIAG_WRITE)
    {
      char *cp1 ;

      FileNameOnly(template_fname, fname) ;
      cp = strchr(fname, '.') ;
      if (cp)
      {
        cp1 = strrchr(fname, '.') ;
        if (cp1 && cp1 != cp)
          strncpy(parms.base_name, cp+1, cp1-cp-1) ;
        else
          strcpy(parms.base_name, cp+1) ;
      }
      else
        strcpy(parms.base_name, "template") ;
      sprintf(fname, "%s.%s.out", hemi, parms.base_name);
      parms.fp = fopen(fname, "w") ;
      printf("writing output to '%s'\n", fname) ;
    }

    /* multiframe registration */
    if (multiframes)
    {
      nfields=parms.nfields;

      for ( n = 0; n < mris->nvertices ; n++) /* allocate the VALS_VP
                                                                 structure */
      {
        v=&mris->vertices[n];
        vp=calloc(1,sizeof(VALS_VP));
        vp->nvals=nfields;
        vp->orig_vals=(float*)malloc(nfields*sizeof(float)); /* before
                                                                blurring */
        vp->vals=(float*)malloc(nfields*sizeof(float));     /* values used by
                                                               MRISintegrate */
        v->vp=(void*)vp;
      }

      /* load the different fields */
      for (n = 0 ; n < parms.nfields ; n++)
      {
        if (parms.fields[n].name != NULL)
        {
          sprintf(surf_fname, "%s/%s/%s/%s.%s", subjects_dir,
                  subject, overlay_dir, hemi, parms.fields[n].name) ;
          printf("reading overlay file %s...\n", surf_fname) ;
          if (MRISreadValues(mris, surf_fname) != NO_ERROR)
            ErrorExit(ERROR_BADPARM, "%s: could not read overlay file %s",
                      Progname, surf_fname) ;
          MRIScopyValuesToCurvature(mris) ;
        }
        else if (ReturnFieldName(parms.fields[n].field))
        {
          /* read in precomputed curvature file */
          sprintf(surf_fname, "%s/%s/surf/%s.%s", subjects_dir,
                  subject, hemi, ReturnFieldName(parms.fields[n].field)) ;
          // fprintf(stderr,"\nreading field %d from %s(type=%d,frame=%d)\n",parms.fields[n].field,surf_fname,parms.fields[n].type,parms.fields[n].frame);
          if (MRISreadCurvatureFile(mris, surf_fname) != NO_ERROR)
          {
            fprintf(stderr,"\n\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
            fprintf(stderr, "%s: could not read curvature file '%s'\n",
                    Progname, surf_fname) ;
            failed = 1;
            break;
          }
        }
        else
        {                       /* compute curvature of surface */
          sprintf(surf_fname, "%s/%s/surf/%s.%s", subjects_dir,
                  subject, hemi, surface_names[parms.fields[n].field]) ;
          /*if(parms.fields[n].field==0)
           sprintf(fname, "inflated") ;
           else
           sprintf(fname, "smoothwm") ;*/
          //fprintf(stderr,"\ngenerating field %d(type=%d,frame=%d) (from %s)\n",parms.fields[n].field,parms.fields[n].type,parms.fields[n].frame,surf_fname);
          //     MRISsaveVertexPositions(mris, TMP_VERTICES) ;
          if (MRISreadVertexPositions(mris, surf_fname) != NO_ERROR)
          {
            fprintf(stderr,"\n\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
            ErrorPrintf(ERROR_NOFILE, "%s: could not read surface file %s",
                        Progname, surf_fname) ;
            fprintf(stderr,"setting up correlation coefficient to zero\n");
            parms.fields[n].l_corr=parms.fields[n].l_pcorr=0.0;
            failed=1;
            break;
          }

          if (nbrs > 1) MRISsetNeighborhoodSize(mris, nbrs) ;
          MRIScomputeMetricProperties(mris) ;
          MRIScomputeSecondFundamentalForm(mris) ;
          MRISuseMeanCurvature(mris) ;
          MRISaverageCurvatures(mris, navgs) ;
          MRISrestoreVertexPositions(mris, CANONICAL_VERTICES) ;
        }
        /*    if(parms.fields[n].field!=SULC_CORR_FRAME)*/
        MRISnormalizeField(mris,parms.fields[n].type,
                           parms.fields[n].which_norm); /* normalize values */
        MRISsetCurvaturesToOrigValues(mris,n);
        MRISsetCurvaturesToValues(mris,n);
      }

      if (failed)
      {
        fprintf(stderr,"\n\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
        fprintf(stderr,"Subject %s Failed",subject);
        fprintf(stderr,"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n");
        /* free cal structure*/
        for ( n = 0; n < mris->nvertices ; n++)
        {
          v=&mris->vertices[n];
          vp=(VALS_VP*)v->vp;
          free(vp->orig_vals);
          free(vp->vals);
          free(vp);
          v->vp=NULL;
        }
        /* free surface */
        MRISfree(&mris);
        /* go onto the next subject */
        continue;
      }
    }

    if (multiframes && (!no_rot))
    { /* rigid body alignment */
      parms.frame_no = 3 ;  /* don't use single field correlation functions */
      parms.l_corr = parms.l_pcorr = 0.0f ;

      parms.mrisp = MRIStoParameterization(mris, NULL, scale, 0) ;
      parms.mrisp_template = mrisp_template ;

      MRISrigidBodyAlignVectorGlobal(mris, &parms, 1.0, 64.0, 8) ;
      if (Gdiag & DIAG_WRITE) MRISwrite(mris, "sphere.rot.global") ;
      MRISrigidBodyAlignVectorLocal(mris, &parms) ;
      if (Gdiag & DIAG_WRITE) MRISwrite(mris, "sphere.rot.local") ;
      MRISPfree(&parms.mrisp) ;
      MRISsaveVertexPositions(mris, CANONICAL_VERTICES) ;
    };
    if ((!multiframes) && (!no_rot) && ino > 0)
    { /* rigid body alignment */
      sprintf(surf_fname, "%s/%s/surf/%s.%s",
              subjects_dir, subject, hemi, "sulc") ;
      if (MRISreadCurvatureFile(mris, surf_fname) != NO_ERROR)
      {
        ErrorPrintf(Gerror, "%s: could not read curvature file '%s'\n",
                    Progname, surf_fname) ;
        nbad++ ;
        MRISfree(&mris) ;
        continue ;
      }
      parms.frame_no = 3 ; /* use sulc for rigid registration */
      parms.mrisp = MRIStoParameterization(mris, NULL, scale, 0) ;
      parms.mrisp_template = mrisp_template ;
      parms.l_corr = 1.0f ;

      MRISrigidBodyAlignGlobal(mris, &parms, 1.0, 64.0, 8) ;
      if (Gdiag & DIAG_WRITE)
        MRISwrite(mris, "sphere.rot.global") ;
      MRISrigidBodyAlignLocal(mris, &parms) ;
      if (Gdiag & DIAG_WRITE)
        MRISwrite(mris, "sphere.rot.local") ;
      MRISPfree(&parms.mrisp) ;
      MRISsaveVertexPositions(mris, CANONICAL_VERTICES) ;
    }

    if (multiframes)
    {
      for (n = 0; n < parms.nfields ; n++)
      {
        MRISsetOrigValuesToCurvatures(mris,n);
        MRISaverageCurvatures(mris, parms.fields[n].navgs) ;
        mrisp = MRIStoParameterization(mris, NULL, scale, 0) ;
        MRISPcombine(mrisp,
                     mrisp_template,
                     parms.fields[n].frame * IMAGES_PER_SURFACE) ;
        MRISPfree(&mrisp) ;
      }
      /* free the VALS_VP structure */
      for ( n = 0; n < mris->nvertices ; n++)
      {
        v=&mris->vertices[n];
        vp=(VALS_VP*)v->vp;
        free(vp->orig_vals);
        free(vp->vals);
        free(vp);
        v->vp=NULL;
      }
      MRISfree(&mris) ;
    }
    else
    {
      for (sno = 0; sno < SURFACES ; sno++)
      {
        if (curvature_names[sno])  /* read in precomputed curvature file */
        {
          sprintf(surf_fname, "%s/%s/surf/%s.%s",
                  subjects_dir, subject, hemi, curvature_names[sno]) ;
          if (MRISreadCurvatureFile(mris, surf_fname) != NO_ERROR)
          {
            nbad++ ;
            ErrorPrintf(Gerror, "%s: could not read curvature file '%s'\n",
                        Progname, surf_fname) ;
            failed = 1 ;
            break ;
          }
          /* the two next lines were not in the original code */
          MRISaverageCurvatures(mris, navgs) ;
          MRISnormalizeCurvature(mris, which_norm) ;
        } else                       /* compute curvature of surface */
        {
          sprintf(surf_fname, "%s/%s/surf/%s.%s",
                  subjects_dir, subject, hemi, surface_names[sno]) ;
          if (MRISreadVertexPositions(mris, surf_fname) != NO_ERROR)
          {
            ErrorPrintf(ERROR_NOFILE, "%s: could not read surface file %s",
                        Progname, surf_fname) ;
            nbad++ ;
            failed = 1 ;
            break ;
          }

          if (nbrs > 1)
            MRISsetNeighborhoodSize(mris, nbrs) ;
          MRIScomputeMetricProperties(mris) ;
          MRIScomputeSecondFundamentalForm(mris) ;
          MRISuseMeanCurvature(mris) ;
          MRISaverageCurvatures(mris, navgs) ;
          MRISrestoreVertexPositions(mris, CANONICAL_VERTICES) ;
          MRISnormalizeCurvature(mris, which_norm) ;
        }
        fprintf(stderr, "computing parameterization for surface %s...\n",
                surf_fname);
        if (failed)
        {
          continue ;
          MRISfree(&mris) ;
        }
        mrisp = MRIStoParameterization(mris, NULL, scale, 0) ;
        MRISPcombine(mrisp, mrisp_template, sno*3) ;
        MRISPfree(&mrisp) ;
      }
      MRISfree(&mris) ;
    }
  }

#if 0
  if (mrisp_aligned)  /* new parameterization - use rigid alignment */
  {
    MRI_SP *mrisp_tmp ;

    if (Gdiag & DIAG_WRITE)
    {
      char *cp1 ;

      FileNameOnly(template_fname, fname) ;
      cp = strchr(fname, '.') ;
      if (cp)
      {
        cp1 = strrchr(fname, '.') ;
        if (cp1 && cp1 != cp)
          strncpy(parms.base_name, cp+1, cp1-cp-1) ;
        else
          strcpy(parms.base_name, cp+1) ;
      }
      else
        strcpy(parms.base_name, "template") ;
      sprintf(fname, "%s.%s.out", hemi, parms.base_name);
      parms.fp = fopen(fname, "w") ;
      printf("writing output to '%s'\n", fname) ;
    }
    for (ino = 0 ; ino < argc-1 ; ino++)
    {
      subject = argv[ino] ;
      if (Gdiag & DIAG_WRITE)
        fprintf(parms.fp, "processing subject %s\n", subject) ;
      fprintf(stderr, "processing subject %s\n", subject) ;
      sprintf(surf_fname, "%s/%s/surf/%s.%s",
              subjects_dir, subject, hemi, sphere_name) ;
      fprintf(stderr, "reading spherical surface %s...\n", surf_fname) ;
      mris = MRISread(surf_fname) ;
      if (!mris)
        ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
                  Progname, surf_fname) ;
      MRIScomputeMetricProperties(mris) ;
      MRISstoreMetricProperties(mris) ;
      MRISsaveVertexPositions(mris, ORIGINAL_VERTICES) ;
      sprintf(surf_fname, "%s/%s/surf/%s.%s",
              subjects_dir, subject, hemi, "sulc") ;
      if (MRISreadCurvatureFile(mris, surf_fname) != NO_ERROR)
        ErrorExit(Gerror, "%s: could not read curvature file '%s'\n",
                  Progname, surf_fname) ;
      parms.frame_no = 3 ;
      parms.mrisp = MRIStoParameterization(mris, NULL, scale, 0) ;
      parms.mrisp_template = mrisp_template ;
      parms.l_corr = 1.0f ;

      MRISrigidBodyAlignGlobal(mris, &parms, 1.0, 32.0, 8) ;
      if (Gdiag & DIAG_WRITE)
        MRISwrite(mris, "sphere.rot.global") ;
      MRISrigidBodyAlignLocal(mris, &parms) ;
      if (Gdiag & DIAG_WRITE)
        MRISwrite(mris, "sphere.rot.local") ;
      MRISPfree(&parms.mrisp) ;

#if 0
      /* write out rotated surface */
      sprintf(surf_fname, "%s.rot", mris->fname) ;
      fprintf(stderr, "writing out rigidly aligned surface to '%s'\n",
              surf_fname) ;
      MRISwrite(mris, surf_fname) ;
#endif

      /* now generate new parameterization using the optimal alignment */
      for (sno = 0; sno < SURFACES ; sno++)
      {
        if (curvature_names[sno])  /* read in precomputed curvature file */
        {
          sprintf(surf_fname, "%s/%s/surf/%s.%s",
                  subjects_dir, subject, hemi, curvature_names[sno]) ;
          if (MRISreadCurvatureFile(mris, surf_fname) != NO_ERROR)
            ErrorExit(Gerror, "%s: could not read curvature file '%s'\n",
                      Progname, surf_fname) ;
        } else                       /* compute curvature of surface */
        {
          sprintf(surf_fname, "%s/%s/surf/%s.%s",
                  subjects_dir, subject, hemi, surface_names[sno]) ;
          if (MRISreadVertexPositions(mris, surf_fname) != NO_ERROR)
            ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
                      Progname, surf_fname) ;

          if (nbrs > 1)
            MRISsetNeighborhoodSize(mris, nbrs) ;
          MRIScomputeMetricProperties(mris) ;
          MRIScomputeSecondFundamentalForm(mris) ;
          MRISuseMeanCurvature(mris) ;
          MRISaverageCurvatures(mris, navgs) ;
          MRISrestoreVertexPositions(mris, ORIGINAL_VERTICES) ;
          MRISnormalizeCurvature(mris) ;
        }
        fprintf(stderr, "computing parameterization for surface %s...\n",
                surf_fname);
        mrisp = MRIStoParameterization(mris, NULL, scale, 0) ;
        MRISPcombine(mrisp, mrisp_aligned, sno*3) ;
        MRISPfree(&mrisp) ;
      }
      MRISfree(&mris) ;
    }

    if (Gdiag & DIAG_WRITE)
      fclose(parms.fp) ;

    mrisp_tmp = mrisp_aligned ;
    mrisp_aligned = mrisp_template ;
    mrisp_template = mrisp_tmp ;
    MRISPfree(&mrisp_aligned) ;
  }
#endif
  fprintf(stderr,
          "writing updated template with %d subjects to %s...\n",
          argc-1-nbad, template_fname) ;
  MRISPwrite(mrisp_template, template_fname) ;
  MRISPfree(&mrisp_template) ;
  exit(0) ;
  return(0) ;  /* for ansi */
}
int
main(int argc, char *argv[]) {
  MRI_SURFACE  *mris ;
  char         **av, *curv_name, *surf_name, *hemi, fname[STRLEN],
  *cp, *subject_name, subjects_dir[STRLEN],
  **c1_subjects, **c2_subjects ;
  int          ac, nargs, n, num_class1, num_class2, i, nvertices,
  avgs, max_snr_avgs, nlabels = 0, done ;
  float        **c1_thickness, **c2_thickness, *curvs, *total_mean,
  *c1_mean, *c2_mean,
  *class_mean, *c1_var, *c2_var, *class_var,*pvals,
  **c1_avg_thickness,
  *vbest_snr, *vbest_avgs, *vtotal_var, *vsnr, **c2_avg_thickness,
  *vbest_pvalues, current_min_label_area, current_fthresh ;
  MRI_SP       *mrisp ;
  LABEL        *area, **labels = NULL ;
  FILE         *fp = NULL ;
  double       snr, max_snr ;
  struct timeb start ;
  int          msec, minutes, seconds ;
  double       **c1_label_thickness, **c2_label_thickness ;
  int          *sorted_indices = NULL, vno ;
  float        *test_thickness, *test_avg_thickness ;
  double       label_avg ;

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

  if (write_flag && DIAG_VERBOSE_ON)
    fp = fopen("scalespace.dat", "w") ;

  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 ;
  }

  TimerStart(&start) ;

  /* subject_name hemi surface curvature */
  if (argc < 7)
    usage_exit() ;
  if (output_subject == NULL)
    ErrorExit(ERROR_BADPARM,
              "output subject must be specified with -o <subject name>");

  cp = getenv("SUBJECTS_DIR") ;
  if (!cp)
    ErrorExit(ERROR_BADPARM, "%s: SUBJECTS_DIR not defined in environment",
              Progname) ;

  strcpy(subjects_dir, cp) ;

  hemi = argv[1] ;
  surf_name = argv[2] ;
  curv_name = argv[3] ;

#define ARGV_OFFSET 4

  /* first determine the number of subjects in each class */
  num_class1 = 0 ;
  n = ARGV_OFFSET ;
  do {
    num_class1++ ;
    n++ ;
    if (argv[n] == NULL || n >= argc)
      ErrorExit(ERROR_BADPARM, "%s: must spectify ':' between class lists",
                Progname) ;
  } while (argv[n][0] != ':') ;

  /* find  # of vertices in output subject surface */
  sprintf(fname, "%s/%s/surf/%s.%s",
          subjects_dir,output_subject,hemi,surf_name);
  mris = MRISread(fname) ;
  if (!mris)
    ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
              Progname, fname) ;
  nvertices = mris->nvertices ;
  MRISfree(&mris) ;

  total_mean = (float *)calloc(nvertices, sizeof(float)) ;
  if (!total_mean)
    ErrorExit(ERROR_NOMEMORY,
              "%s: could not allocate mean list of %d curvatures",
              Progname, n, nvertices) ;
  c1_mean = (float *)calloc(nvertices, sizeof(float)) ;
  if (!c1_mean)
    ErrorExit(ERROR_NOMEMORY,
              "%s: could not allocate c1 mean list of %d curvatures",
              Progname, n, nvertices) ;
  pvals = (float *)calloc(nvertices, sizeof(float)) ;
  if (!pvals)
    ErrorExit(ERROR_NOMEMORY,
              "%s: could not allocate pvals",
              Progname, n, nvertices) ;
  c2_mean = (float *)calloc(nvertices, sizeof(float)) ;
  if (!c2_mean)
    ErrorExit(ERROR_NOMEMORY,
              "%s: could not allocate c2 mean list of %d curvatures",
              Progname, n, nvertices) ;

  c1_var = (float *)calloc(nvertices, sizeof(float)) ;
  if (!c1_var)
    ErrorExit(ERROR_NOMEMORY,
              "%s: could not allocate c1 var list of %d curvatures",
              Progname, n, nvertices) ;
  c2_var = (float *)calloc(nvertices, sizeof(float)) ;
  if (!c2_var)
    ErrorExit(ERROR_NOMEMORY,
              "%s: could not allocate c2 var list of %d curvatures",
              Progname, n, nvertices) ;

  num_class2 = 0 ;
  n++ ; /* skip ':' */
  if (n >= argc)
    ErrorExit(ERROR_BADPARM, "%s: class2 list empty", Progname) ;
  do {
    num_class2++ ;
    n++ ;
    if (n >= argc)
      break ;
  } while (argv[n] != NULL) ;

  fprintf(stderr, "%d subjects in class 1, %d subjects in class 2\n",
          num_class1, num_class2) ;

  c1_subjects = (char **)calloc(num_class1, sizeof(char *)) ;
  c1_thickness = (float **)calloc(num_class1, sizeof(char *)) ;
  c1_avg_thickness = (float **)calloc(num_class1, sizeof(char *)) ;
  c2_subjects = (char **)calloc(num_class2, sizeof(char *)) ;
  c2_thickness = (float **)calloc(num_class2, sizeof(char *)) ;
  c2_avg_thickness = (float **)calloc(num_class2, sizeof(char *)) ;
  for (n = 0 ; n < num_class1 ; n++) {
    c1_subjects[n] = argv[ARGV_OFFSET+n] ;
    c1_thickness[n] = (float *)calloc(nvertices, sizeof(float)) ;
    c1_avg_thickness[n] = (float *)calloc(nvertices, sizeof(float)) ;
    if (!c1_thickness[n] || !c1_avg_thickness[n])
      ErrorExit(ERROR_NOMEMORY,
                "%s: could not allocate %dth list of %d curvatures",
                Progname, n, nvertices) ;

    strcpy(c1_subjects[n], argv[ARGV_OFFSET+n]) ;
    /*    fprintf(stderr, "class1[%d] - %s\n", n, c1_subjects[n]) ;*/
  }
  i = n+1+ARGV_OFFSET ;  /* starting index */
  for (n = 0 ; n < num_class2 ; n++) {
    c2_subjects[n] = argv[i+n] ;
    c2_thickness[n] = (float *)calloc(nvertices, sizeof(float)) ;
    c2_avg_thickness[n] = (float *)calloc(nvertices, sizeof(float)) ;
    if (!c2_thickness[n] || !c2_avg_thickness[n])
      ErrorExit(ERROR_NOMEMORY,
                "%s: could not allocate %dth list of %d curvatures",
                Progname, n, nvertices) ;
    strcpy(c2_subjects[n], argv[i+n]) ;
    /*    fprintf(stderr, "class2[%d] - %s\n", n, c2_subjects[n]) ;*/
  }

  if (label_name) {
    area = LabelRead(output_subject, label_name) ;
    if (!area)
      ErrorExit(ERROR_NOFILE, "%s: could not read label %s", Progname,
                label_name) ;
  } else
    area = NULL ;

  if (read_dir) {
    sprintf(fname, "%s/%s/surf/%s.%s",
            subjects_dir,output_subject,hemi,surf_name);
    mris = MRISread(fname) ;
    if (!mris)
      ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
                Progname, fname) ;
    MRISsaveVertexPositions(mris, CANONICAL_VERTICES) ;

    /* real all the curvatures in for group1 */
    for (n = 0 ; n < num_class1+num_class2 ; n++) {
      /* transform each subject's curvature into the output subject's space */
      subject_name = n < num_class1 ? c1_subjects[n]:c2_subjects[n-num_class1];
      fprintf(stderr, "reading subject %d of %d: %s\n",
              n+1, num_class1+num_class2, subject_name) ;
      sprintf(fname, "%s/%s.%s", read_dir,hemi,subject_name);
      if (MRISreadValues(mris, fname) != NO_ERROR)
        ErrorExit(Gerror,
                  "%s: could not read curvature file %s",Progname,fname);
      if (area)
        MRISmaskNotLabel(mris, area) ;
      curvs = (n < num_class1) ? c1_thickness[n] : c2_thickness[n-num_class1] ;
      class_mean = (n < num_class1) ? c1_mean : c2_mean ;
      class_var = (n < num_class1) ? c1_var : c2_var ;
      MRISexportValVector(mris, curvs) ;
      cvector_accumulate(curvs, total_mean, nvertices) ;
      cvector_accumulate(curvs, class_mean, nvertices) ;
      cvector_accumulate_square(curvs, class_var, nvertices) ;
    }
  } else {

    /* real all the curvatures in for group1 */
    for (n = 0 ; n < num_class1+num_class2 ; n++) {
      /* transform each subject's curvature into the output subject's space */
      subject_name = n < num_class1 ? c1_subjects[n]:c2_subjects[n-num_class1];
      fprintf(stderr, "reading subject %d of %d: %s\n",
              n+1, num_class1+num_class2, subject_name) ;
      sprintf(fname, "%s/%s/surf/%s.%s",
              subjects_dir,subject_name,hemi,surf_name);
      mris = MRISread(fname) ;
      if (!mris)
        ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
                  Progname, fname) ;
      MRISsaveVertexPositions(mris, CANONICAL_VERTICES) ;
      if (strchr(curv_name, '/') != NULL)
        strcpy(fname, curv_name) ;  /* full path specified */
      else
        sprintf(fname,"%s/%s/surf/%s.%s",
                subjects_dir,subject_name,hemi,curv_name);
      if (MRISreadCurvatureFile(mris, fname) != NO_ERROR)
        ErrorExit(Gerror,"%s: could no read curvature file %s",Progname,fname);
      mrisp = MRIStoParameterization(mris, NULL, 1, 0) ;
      MRISfree(&mris) ;

      sprintf(fname, "%s/%s/surf/%s.%s",
              subjects_dir,output_subject,hemi,surf_name);
      mris = MRISread(fname) ;
      if (!mris)
        ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
                  Progname, fname) ;
      MRISfromParameterization(mrisp, mris, 0) ;
      if (area)
        MRISmaskNotLabel(mris, area) ;
      curvs = (n < num_class1) ? c1_thickness[n] : c2_thickness[n-num_class1] ;
      class_mean = (n < num_class1) ? c1_mean : c2_mean ;
      class_var = (n < num_class1) ? c1_var : c2_var ;
      MRISextractCurvatureVector(mris, curvs) ;
      cvector_accumulate(curvs, total_mean, nvertices) ;
      cvector_accumulate(curvs, class_mean, nvertices) ;
      cvector_accumulate_square(curvs, class_var, nvertices) ;
      MRISPfree(&mrisp) ;
      MRISfree(&mris) ;
    }
  }

  /* compute within-group means, and total mean */
  cvector_normalize(total_mean, num_class1+num_class2, nvertices) ;
  cvector_normalize(c1_mean, num_class1, nvertices) ;
  cvector_normalize(c2_mean, num_class2, nvertices) ;
  cvector_compute_variance(c1_var, c1_mean, num_class1, nvertices) ;
  cvector_compute_variance(c2_var, c2_mean, num_class2, nvertices) ;
  cvector_compute_t_test(c1_mean, c1_var, c2_mean, c2_var,
                         num_class1, num_class2, pvals, nvertices) ;

  sprintf(fname, "%s/%s/surf/%s.%s",
          subjects_dir,output_subject,hemi,surf_name);
  fprintf(stderr, "reading output surface %s...\n", fname) ;
  mris = MRISread(fname) ;
  if (!mris)
    ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
              Progname, fname) ;

  if (area)
    MRISripNotLabel(mris, area) ;
  vbest_snr = cvector_alloc(nvertices) ;
  vbest_pvalues = cvector_alloc(nvertices) ;
  vbest_avgs = cvector_alloc(nvertices) ;
  vtotal_var = cvector_alloc(nvertices) ;
  vsnr = cvector_alloc(nvertices) ;

  if (read_dir == NULL)  /* recompute everything */
  {
    if (use_buggy_snr)
      cvector_multiply_variances(c1_var, c2_var, num_class1, num_class2,
                                 vtotal_var, nvertices) ;
    else
      cvector_add_variances(c1_var, c2_var, num_class1, num_class2,
                            vtotal_var, nvertices) ;
    if (use_no_distribution)
      snr = cvector_compute_dist_free_snr(c1_thickness, num_class1,
                                          c2_thickness, num_class2,
                                          c1_mean, c2_mean,
                                          vsnr, nvertices, &i);
    else
      snr = cvector_compute_snr(c1_mean, c2_mean, vtotal_var, vsnr, nvertices,
                                &i, 0.0f);
    fprintf(stderr,
            "raw SNR %2.2f, n=%2.4f, d=%2.4f, vno=%d\n",
            sqrt(snr), c1_mean[i]-c2_mean[i], sqrt(vtotal_var[i]), i) ;
    max_snr = snr ;
    max_snr_avgs = 0 ;
    cvector_track_best_snr(vsnr, vbest_snr, vbest_avgs, 0, nvertices) ;

    for (n = 0 ; n < num_class1 ; n++)
      cvector_copy(c1_thickness[n], c1_avg_thickness[n], nvertices) ;
    for (n = 0 ; n < num_class2 ; n++)
      cvector_copy(c2_thickness[n], c2_avg_thickness[n], nvertices) ;

    /* now incrementally average the data, keeping track of the best
       snr at each location, and at what scale it occurred. vbest_avgs
       and vbest_snr will contain the scale and the snr at that scale.
    */
    for (avgs = 1 ; avgs <= max_avgs ; avgs++) {
      /* c?_avg_thickness is the thickness at the current scale */
      if (!(avgs % 50))
        fprintf(stderr, "testing %d averages...\n", avgs) ;
      cvector_clear(c1_mean, nvertices) ;
      cvector_clear(c2_mean, nvertices) ;
      cvector_clear(c1_var, nvertices) ;
      cvector_clear(c2_var, nvertices) ;
      cvector_clear(total_mean, nvertices) ;
      for (n = 0 ; n < num_class1 ; n++) {
        MRISimportCurvatureVector(mris, c1_avg_thickness[n]) ;
        MRISaverageCurvatures(mris, 1) ;
        MRISextractCurvatureVector(mris, c1_avg_thickness[n]) ;
        cvector_accumulate(c1_avg_thickness[n], total_mean, nvertices) ;
        cvector_accumulate(c1_avg_thickness[n], c1_mean, nvertices) ;
        cvector_accumulate_square(c1_avg_thickness[n], c1_var, nvertices) ;
      }
      for (n = 0 ; n < num_class2 ; n++) {
        MRISimportCurvatureVector(mris, c2_avg_thickness[n]) ;
        MRISaverageCurvatures(mris, 1) ;
        MRISextractCurvatureVector(mris, c2_avg_thickness[n]) ;
        cvector_accumulate(c2_avg_thickness[n], total_mean, nvertices) ;
        cvector_accumulate(c2_avg_thickness[n], c2_mean, nvertices) ;
        cvector_accumulate_square(c2_avg_thickness[n], c2_var, nvertices) ;
      }
      cvector_normalize(total_mean, num_class1+num_class2, nvertices) ;
      cvector_normalize(c1_mean, num_class1, nvertices) ;
      cvector_normalize(c2_mean, num_class2, nvertices) ;
      cvector_compute_variance(c1_var, c1_mean, num_class1, nvertices) ;
      cvector_compute_variance(c2_var, c2_mean, num_class2, nvertices) ;
      if (use_buggy_snr)
        cvector_multiply_variances(c1_var, c2_var, num_class1, num_class2,
                                   vtotal_var, nvertices) ;
      else
        cvector_add_variances(c1_var, c2_var, num_class1, num_class2,
                              vtotal_var, nvertices) ;
      if (use_no_distribution)
        snr =
          cvector_compute_dist_free_snr(c1_avg_thickness,num_class1,
                                        c2_avg_thickness, num_class2, c1_mean,
                                        c2_mean, vsnr, nvertices, &i);
      else
        snr =
          cvector_compute_snr(c1_mean, c2_mean, vtotal_var, vsnr, nvertices,&i,
                              bonferroni ? log((double)avgs) : 0.0f);
      if (write_flag && DIAG_VERBOSE_ON) {
        fprintf(fp, "%d %2.1f  %2.2f %2.2f %2.2f ",
                avgs, sqrt((float)avgs), sqrt(snr), c1_mean[i]-c2_mean[i],
                sqrt(vtotal_var[i])) ;
        fflush(fp) ;
        for (n = 0 ; n < num_class1 ; n++)
          fprintf(fp, "%2.2f ", c1_avg_thickness[n][i]) ;
        for (n = 0 ; n < num_class2 ; n++)
          fprintf(fp, "%2.2f ", c2_avg_thickness[n][i]) ;
        fprintf(fp, "\n") ;
        fclose(fp) ;
      }
      if (snr > max_snr) {
        fprintf(stderr,
                "new max SNR found at avgs=%d (%2.1f mm)=%2.1f, n=%2.4f, "
                "d=%2.4f, vno=%d\n",
                avgs, sqrt((float)avgs), sqrt(snr), c1_mean[i]-c2_mean[i],
                sqrt(vtotal_var[i]), i) ;
        max_snr = snr ;
        max_snr_avgs = avgs ;
      }
      cvector_track_best_snr(vsnr, vbest_snr, vbest_avgs, avgs, nvertices) ;
    }
    if (compute_stats)
      cvector_compute_t(vbest_snr, vbest_pvalues,num_class1+num_class2,
                        nvertices) ;
    printf("max snr=%2.2f at %d averages\n", max_snr, max_snr_avgs) ;
    if (write_flag) {
      MRISimportValVector(mris, vbest_snr) ;
      sprintf(fname, "./%s.%s_best_snr", hemi,prefix) ;
      MRISwriteValues(mris, fname) ;
      MRISimportValVector(mris, vbest_avgs) ;
      sprintf(fname, "./%s.%s_best_avgs", hemi, prefix) ;
      MRISwriteValues(mris, fname) ;
      if (compute_stats) {
        MRISimportValVector(mris, vbest_pvalues) ;
        sprintf(fname, "./%s.%s_best_pval", hemi,prefix) ;
        MRISwriteValues(mris, fname) ;
      }
    }
  }
  else  /* read from directory containing precomputed optimal values */
  {
    sprintf(fname, "%s/%s.%s_best_snr", read_dir, hemi, prefix) ;
    if (MRISreadValues(mris, fname) != NO_ERROR)
      ErrorExit(Gerror, "%s: MRISreadValues(%s) failed",Progname,fname) ;
    MRISexportValVector(mris, vbest_snr) ;

    sprintf(fname, "%s/%s.%s_best_avgs", read_dir, hemi, prefix) ;
    if (MRISreadValues(mris, fname) != NO_ERROR)
      ErrorExit(Gerror, "%s: MRISreadValues(%s) failed",Progname,fname) ;
    MRISexportValVector(mris, vbest_avgs) ;
  }

  if (write_dir) {
    sprintf(fname, "%s/%s.%s_best_snr", write_dir, hemi,prefix) ;
    MRISimportValVector(mris, vbest_snr) ;
    if (MRISwriteValues(mris, fname) != NO_ERROR)
      ErrorExit(Gerror, "%s: MRISwriteValues(%s) failed",Progname,fname) ;

    sprintf(fname, "%s/%s.%s_best_avgs", write_dir, hemi, prefix) ;
    MRISimportValVector(mris, vbest_avgs) ;
    if (MRISwriteValues(mris, fname) != NO_ERROR)
      ErrorExit(Gerror, "%s: MRISwriteValues(%s) failed",Progname,fname) ;
  }

  if (nsort < -1)
    nsort = mris->nvertices ;

  if (nsort <= 0) {
    nlabels = 0 ;
    current_min_label_area = min_label_area ;
    for (done = 0, current_fthresh = fthresh ;
         !FZERO(current_fthresh) && !done ;
         current_fthresh *= 0.95) {
      int   npos_labels, nneg_labels ;
      LABEL **pos_labels, **neg_labels ;

      for (current_min_label_area = min_label_area ;
           current_min_label_area > 0.5 ;
           current_min_label_area *= 0.75) {
        MRISclearMarks(mris) ;
        sprintf(fname, "%s-%s_thickness", hemi, prefix ? prefix : "") ;
        mark_thresholded_vertices(mris, vbest_snr, vbest_avgs,current_fthresh);
        segment_and_write_labels(output_subject, fname, mris,
                                 &pos_labels, &npos_labels, 0,
                                 current_min_label_area) ;
        MRISclearMarks(mris) ;
        mark_thresholded_vertices(mris, vbest_snr,vbest_avgs,-current_fthresh);
        segment_and_write_labels(output_subject, fname, mris, &neg_labels,
                                 &nneg_labels, npos_labels,
                                 current_min_label_area) ;

        nlabels = nneg_labels + npos_labels ;
        if (nlabels) {
          labels = (LABEL **)calloc(nlabels, sizeof(LABEL *)) ;
          for (i = 0 ; i < npos_labels ; i++)
            labels[i] = pos_labels[i] ;
          for (i = 0 ; i < nneg_labels ; i++)
            labels[i+npos_labels] = neg_labels[i] ;
          free(pos_labels) ;
          free(neg_labels) ;
        }
        done = (nlabels >= min_labels) ;
        if (done)  /* found enough points */
          break ;

        /* couldn't find enough  points - free stuff and try again */
        for (i = 0 ; i < nlabels ; i++)
          LabelFree(&labels[i]) ;
        if (nlabels)
          free(labels) ;
#if 0
        fprintf(stderr,"%d labels found (min %d), reducing constraints...\n",
                nlabels, min_labels) ;
#endif
      }
    }

    printf("%d labels found with F > %2.1f and area > %2.0f\n",
           nlabels, current_fthresh, current_min_label_area) ;
    for (i = 0 ; i < nlabels ; i++)
      fprintf(stderr, "label %d: %d points, %2.1f mm\n",
              i, labels[i]->n_points, LabelArea(labels[i], mris)) ;
  }

  /* read or compute thickness at optimal scale and put it into
     c?_avg_thickness.
  */
  if (!read_dir) {
    fprintf(stderr, "extracting thickness at optimal scale...\n") ;

    /* now build feature vectors for each subject */
    extract_thickness_at_best_scale(mris, c1_avg_thickness, vbest_avgs,
                                    c1_thickness, nvertices, num_class1);
    fprintf(stderr, "extracting thickness for class 2...\n") ;
    extract_thickness_at_best_scale(mris, c2_avg_thickness, vbest_avgs,
                                    c2_thickness, nvertices, num_class2);
  } else  /* read in precomputed optimal thicknesses */
  {
    char fname[STRLEN] ;

    fprintf(stderr, "reading precomputed thickness vectors\n") ;
    for (n = 0 ; n < num_class1 ; n++) {
      sprintf(fname, "%s/%s.%s", read_dir, hemi, argv[ARGV_OFFSET+n]) ;
      fprintf(stderr, "reading thickness vector from %s...\n", fname) ;
      if (MRISreadValues(mris, fname) != NO_ERROR)
        ErrorExit(Gerror, "%s: could not read thickness file %s",
                  Progname,fname) ;
      MRISexportValVector(mris, c1_avg_thickness[n]) ;
    }
    for (n = 0 ; n < num_class2 ; n++) {
      sprintf(fname, "%s/%s.%s", read_dir, hemi,
              argv[n+num_class1+1+ARGV_OFFSET]) ;
      fprintf(stderr, "reading curvature vector from %s...\n", fname) ;
      if (MRISreadValues(mris, fname) != NO_ERROR)
        ErrorExit(Gerror, "%s: could not read thickness file %s",
                  Progname,fname) ;
      MRISexportValVector(mris, c2_avg_thickness[n]) ;
    }
  }

  if (write_dir)   /* write out optimal thicknesses */
  {
    char fname[STRLEN] ;

    for (n = 0 ; n < num_class1 ; n++) {
      sprintf(fname, "%s/%s.%s", write_dir, hemi, argv[ARGV_OFFSET+n]) ;
      fprintf(stderr, "writing curvature vector to %s...\n", fname) ;
      MRISimportValVector(mris, c1_avg_thickness[n]) ;
      MRISwriteValues(mris, fname) ;
    }
    for (n = 0 ; n < num_class2 ; n++) {
      sprintf(fname, "%s/%s.%s", write_dir, hemi,
              argv[n+num_class1+1+ARGV_OFFSET]) ;
      fprintf(stderr, "writing curvature vector to %s...\n", fname) ;
      MRISimportValVector(mris, c2_avg_thickness[n]) ;
      MRISwriteValues(mris, fname) ;
    }
  }


  /* should free c?_thickness here */

  if (nsort <= 0) {
    /* We have the thickness values at the most powerful scale stored for
       each subject in the c1_avg_thickness and c2_avg_thickness vectors.
       Now collapse them across each label and build  feature vector for
       classification.
    */
    c1_label_thickness = (double **)calloc(num_class1, sizeof(double *)) ;
    c2_label_thickness = (double **)calloc(num_class2, sizeof(double *)) ;
    for (n = 0 ; n < num_class1 ; n++)
      c1_label_thickness[n] = (double *)calloc(nlabels, sizeof(double)) ;
    for (n = 0 ; n < num_class2 ; n++)
      c2_label_thickness[n] = (double *)calloc(nlabels, sizeof(double)) ;

    fprintf(stderr, "collapsing thicknesses within labels for class 1\n") ;
    for (n = 0 ; n < num_class1 ; n++)
      for (i = 0 ; i < nlabels ; i++)
        c1_label_thickness[n][i] =
          cvector_average_in_label(c1_avg_thickness[n], labels[i], nvertices) ;
    fprintf(stderr, "collapsing thicknesses within labels for class 2\n") ;
    for (n = 0 ; n < num_class2 ; n++)
      for (i = 0 ; i < nlabels ; i++)
        c2_label_thickness[n][i] =
          cvector_average_in_label(c2_avg_thickness[n], labels[i], nvertices) ;
    sprintf(fname, "%s_%s_class1.dat", hemi,prefix) ;
    fprintf(stderr, "writing class 1 info to %s...\n", fname) ;
    fp = fopen(fname, "w") ;
    for (i = 0 ; i < nlabels ; i++)  /* for each row */
    {
      for (n = 0 ; n < num_class1 ; n++)  /* for each column */
        fprintf(fp, "%2.2f  ", c1_label_thickness[n][i]) ;
      fprintf(fp, "\n") ;
    }
    fclose(fp) ;

    sprintf(fname, "%s_%s_class2.dat", hemi,prefix) ;
    fprintf(stderr, "writing class 2 info to %s...\n", fname) ;
    fp = fopen(fname, "w") ;
    for (i = 0 ; i < nlabels ; i++) {
      for (n = 0 ; n < num_class2 ; n++)
        fprintf(fp, "%2.2f  ", c2_label_thickness[n][i]) ;
      fprintf(fp, "\n") ;
    }
    fclose(fp) ;
  } else {
    sorted_indices = cvector_sort(vbest_snr, nvertices) ;
    vno = sorted_indices[0] ;
    write_vertex_data("c1.dat", vno, c1_avg_thickness,num_class1);
    write_vertex_data("c2.dat", vno, c2_avg_thickness,num_class2);
    printf("sorting complete\n") ;

    /* re-write class means at these locations */
    sprintf(fname, "%s_%s_class1.dat", hemi,prefix) ;
    fprintf(stderr, "writing class 1 info to %s...\n", fname) ;
    fp = fopen(fname, "w") ;
    for (i = 0 ; i < nsort ; i++) {
      for (n = 0 ; n < num_class1 ; n++)
        fprintf(fp, "%2.2f  ", c1_avg_thickness[n][sorted_indices[i]]) ;
      fprintf(fp, "\n") ;
    }
    fclose(fp) ;
    sprintf(fname, "%s_%s_class2.dat", hemi,prefix) ;
    fprintf(stderr, "writing class 2 info to %s...\n", fname) ;
    fp = fopen(fname, "w") ;
    for (i = 0 ; i < nsort ; i++) {
      for (n = 0 ; n < num_class2 ; n++)
        fprintf(fp, "%2.2f  ", c2_avg_thickness[n][sorted_indices[i]]) ;
      fprintf(fp, "\n") ;
    }
    fclose(fp) ;
  }

  if (test_subject) {
    test_thickness = cvector_alloc(nvertices) ;
    test_avg_thickness = cvector_alloc(nvertices) ;
    MRISfree(&mris) ;
    fprintf(stderr, "reading subject %s\n", test_subject) ;
    sprintf(fname, "%s/%s/surf/%s.%s",
            subjects_dir,test_subject,hemi,surf_name);
    mris = MRISread(fname) ;
    if (!mris)
      ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
                Progname, fname) ;
    MRISsaveVertexPositions(mris, CANONICAL_VERTICES) ;
    if (strchr(curv_name, '/') != NULL)
      strcpy(fname, curv_name) ;  /* full path specified */
    else
      sprintf(fname,"%s/%s/surf/%s.%s",
              subjects_dir,test_subject,hemi,curv_name);
    if (MRISreadCurvatureFile(mris, fname) != NO_ERROR)
      ErrorExit(Gerror,"%s: could no read curvature file %s",Progname,fname);
    mrisp = MRIStoParameterization(mris, NULL, 1, 0) ;
    MRISfree(&mris) ;

    sprintf(fname, "%s/%s/surf/%s.%s",
            subjects_dir,output_subject,hemi,surf_name);
    mris = MRISread(fname) ;
    if (!mris)
      ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
                Progname, fname) ;
    MRISfromParameterization(mrisp, mris, 0) ;
    if (area)
      MRISmaskNotLabel(mris, area) ;
    MRISextractCurvatureVector(mris, test_thickness) ;
    for (avgs = 0 ; avgs <= max_avgs ; avgs++) {
      cvector_extract_best_avg(vbest_avgs, test_thickness,test_avg_thickness,
                               avgs-1, nvertices) ;
      MRISimportCurvatureVector(mris, test_thickness) ;
      MRISaverageCurvatures(mris, 1) ;
      MRISextractCurvatureVector(mris, test_thickness) ;
    }

    if (nsort <= 0) {
      sprintf(fname, "%s_%s.dat", hemi,test_subject) ;
      fprintf(stderr, "writing test subject feature vector to %s...\n",
              fname) ;
      fp = fopen(fname, "w") ;
      for (i = 0 ; i < nlabels ; i++)  /* for each row */
      {
        label_avg =
          cvector_average_in_label(test_avg_thickness, labels[i], nvertices) ;
        fprintf(fp, "%2.2f\n", label_avg) ;
      }
      fclose(fp) ;
    } else   /* use sorting instead of connected areas */
    {
      double classification, offset, w ;
      int    total_correct, total_wrong, first_wrong, vno ;


      sprintf(fname, "%s_%s.dat", hemi,test_subject) ;
      fprintf(stderr, "writing test subject feature vector to %s...\n",
              fname) ;
      fp = fopen(fname, "w") ;

      first_wrong = -1 ;
      total_wrong = total_correct = 0 ;
      for (i = 0 ; i < nsort ; i++) {
        vno = sorted_indices[i] ;
        fprintf(fp, "%2.2f\n ", test_avg_thickness[sorted_indices[i]]) ;
        offset = (c1_mean[vno]+c2_mean[vno])/2.0 ;
        w = (c1_mean[vno]-c2_mean[vno]) ;
        classification = (test_avg_thickness[vno] - offset) * w ;

        if (((classification < 0) && (true_class == 1)) ||
            ((classification > 0) && (true_class == 2))) {
          total_wrong++ ;
          if (first_wrong < 0)
            first_wrong = i ;
        } else
          total_correct++ ;
      }
      fclose(fp) ;
      fprintf(stderr, "%d of %d correct = %2.1f%% (first wrong %d (%d)),"
              "min snr=%2.1f\n",
              total_correct, total_correct+total_wrong,
              100.0*total_correct / (total_correct+total_wrong),
              first_wrong, first_wrong >= 0 ? sorted_indices[first_wrong]:-1,
              vbest_snr[sorted_indices[nsort-1]]) ;

      if (first_wrong >= 0) {
        write_vertex_data("c1w.dat", sorted_indices[first_wrong],
                          c1_avg_thickness,num_class1);
        write_vertex_data("c2w.dat", sorted_indices[first_wrong],
                          c2_avg_thickness,num_class2);
      }
    }
  }

  msec = TimerStop(&start) ;
  free(total_mean);
  free(c1_mean) ;
  free(c2_mean) ;
  free(c1_var);
  free(c2_var);
  seconds = nint((float)msec/1000.0f) ;
  minutes = seconds / 60 ;
  seconds = seconds % 60 ;
  fprintf(stderr, "classification took %d minutes and %d seconds.\n",
          minutes, seconds) ;
  exit(0) ;
  return(0) ;  /* for ansi */
}
Beispiel #5
0
int
main(int argc, char *argv[])
{
  char **av, *surf_fname, *template_fname, *out_fname, fname[STRLEN],*cp;
  int ac, nargs,err, msec ;
  MRI_SURFACE  *mris ;
  MRI_SP       *mrisp_template ;

  char cmdline[CMD_LINE_LEN] ;
  struct  timeb start ;

  make_cmd_version_string
  (argc, argv,
   "$Id: mris_register.c,v 1.59 2011/03/02 00:04:33 nicks Exp $",
   "$Name: stable5 $",
   cmdline);

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

  TimerStart(&start) ;
  Progname = argv[0] ;
  ErrorInit(NULL, NULL, NULL) ;
  DiagInit(NULL, NULL, NULL) ;

  memset(&parms, 0, sizeof(parms)) ;
  parms.projection = PROJECT_SPHERE ;
  parms.flags |= IP_USE_CURVATURE ;
  parms.tol = 0.5 ;    // was 1e-0*2.5
  parms.min_averages = 0 ;
  parms.l_area = 0.0 ;
  parms.l_parea = 0.1f ;  // used to be 0.2
  parms.l_dist = 5.0 ; // used to be 0.5, and before that 0.1
  parms.l_corr = 1.0f ;
  parms.l_nlarea = 1 ;
  parms.l_pcorr = 0.0f ;
  parms.niterations = 25 ;
  parms.n_averages = 1024 ;   // used to be 256
  parms.write_iterations = 100 ;
  parms.dt_increase = 1.01 /* DT_INCREASE */;
  parms.dt_decrease = 0.99 /* DT_DECREASE*/ ;
  parms.error_ratio = 1.03 /*ERROR_RATIO */;
  parms.dt_increase = 1.0 ;
  parms.dt_decrease = 1.0 ;
  parms.l_external = 10000 ;   /* in case manual label is specified */
  parms.error_ratio = 1.1 /*ERROR_RATIO */;
  parms.integration_type = INTEGRATE_ADAPTIVE ;
  parms.integration_type = INTEGRATE_MOMENTUM /*INTEGRATE_LINE_MINIMIZE*/ ;
  parms.integration_type = INTEGRATE_LINE_MINIMIZE ;
  parms.dt = 0.9 ;
  parms.momentum = 0.95 ;
  parms.desired_rms_height = -1.0 ;
  parms.nbhd_size = -10 ;
  parms.max_nbrs = 10 ;

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

  if (nsigmas > 0)
  {
    MRISsetRegistrationSigmas(sigmas, nsigmas) ;
  }
  parms.which_norm = which_norm ;
  if (argc < 4)
  {
    usage_exit() ;
  }

  printf("%s\n", vcid) ;
  printf("  %s\n",MRISurfSrcVersion());
  fflush(stdout);

  surf_fname = argv[1] ;
  template_fname = argv[2] ;
  out_fname = argv[3] ;

  if (parms.base_name[0] == 0)
  {
    FileNameOnly(out_fname, fname) ;
    cp = strchr(fname, '.') ;
    if (cp)
    {
      strcpy(parms.base_name, cp+1) ;
    }
    else
    {
      strcpy(parms.base_name, "sphere") ;
    }
  }

  fprintf(stderr, "reading surface from %s...\n", surf_fname) ;
  mris = MRISread(surf_fname) ;
  if (!mris)
    ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
              Progname, surf_fname) ;

  if (parms.var_smoothness)
  {
    parms.vsmoothness = (float *)calloc(mris->nvertices, sizeof(float)) ;
    if (parms.vsmoothness == NULL)
    {
      ErrorExit(ERROR_NOMEMORY, "%s: could not allocate vsmoothness array",
                Progname) ;
    }
    parms.dist_error = (float *)calloc(mris->nvertices, sizeof(float)) ;
    if (parms.dist_error == NULL)
    {
      ErrorExit(ERROR_NOMEMORY, "%s: could not allocate dist_error array",
                Progname) ;
    }
    parms.area_error = (float *)calloc(mris->nvertices, sizeof(float)) ;
    if (parms.area_error == NULL)
    {
      ErrorExit(ERROR_NOMEMORY, "%s: could not allocate area_error array",
                Progname) ;
    }
    parms.geometry_error = (float *)calloc(mris->nvertices, sizeof(float)) ;
    if (parms.geometry_error == NULL)
    {
      ErrorExit(ERROR_NOMEMORY, "%s: could not allocate geometry_error array",
                Progname) ;
    }
  }

  MRISresetNeighborhoodSize(mris, 1) ;
  if (annot_name)
  {
    if (MRISreadAnnotation(mris, annot_name) != NO_ERROR)
      ErrorExit(ERROR_BADPARM,
                "%s: could not read annot file %s",
                Progname, annot_name) ;
    MRISripMedialWall(mris) ;
  }

  MRISsaveVertexPositions(mris, TMP2_VERTICES) ;
  MRISaddCommandLine(mris, cmdline) ;
  if (!FZERO(dalpha) || !FZERO(dbeta) || !FZERO(dgamma))
    MRISrotate(mris, mris, RADIANS(dalpha), RADIANS(dbeta),
               RADIANS(dgamma)) ;

  if (curvature_fname[0])
  {
    fprintf(stderr, "reading source curvature from %s\n",curvature_fname) ;
    MRISreadCurvatureFile(mris, curvature_fname) ;
  }
  if (single_surf)
  {
    char        fname[STRLEN], *cp, surf_dir[STRLEN], hemi[10]  ;
    MRI_SURFACE *mris_template ;
    int         sno, tnbrs=3 ;

    FileNamePath(template_fname, surf_dir) ;
    cp = strrchr(template_fname, '/') ;
    if (cp == NULL) // no path - start from beginning of file name
    {
      cp = template_fname ;
    }
    cp = strchr(cp, '.') ;
    if (cp == NULL)
      ErrorExit(ERROR_NOFILE,
                "%s: could no scan hemi from %s",
                Progname, template_fname) ;
    strncpy(hemi, cp-2, 2) ;
    hemi[2] = 0 ;
    fprintf(stderr, "reading spherical surface %s...\n", template_fname) ;
    mris_template = MRISread(template_fname) ;
    if (mris_template == NULL)
    {
      ErrorExit(ERROR_NOFILE, "") ;
    }
#if 0
    if (reverse_flag)
    {
      MRISreverse(mris_template, REVERSE_X, 1) ;
    }
#endif
    MRISsaveVertexPositions(mris_template, CANONICAL_VERTICES) ;
    MRIScomputeMetricProperties(mris_template) ;
    MRISstoreMetricProperties(mris_template) ;

    if (noverlays > 0)
    {
      mrisp_template = MRISPalloc(scale, IMAGES_PER_SURFACE*noverlays);
      for (sno = 0; sno < noverlays ; sno++)
      {
        sprintf(fname, "%s/../label/%s.%s", surf_dir, hemi, overlays[sno]) ;
        if (MRISreadValues(mris_template, fname)  != NO_ERROR)
          ErrorExit(ERROR_NOFILE,
                    "%s: could not read overlay from %s",
                    Progname, fname) ;
        MRIScopyValuesToCurvature(mris_template) ;
        MRISaverageCurvatures(mris_template, navgs) ;
        MRISnormalizeCurvature(mris_template, which_norm) ;
        fprintf(stderr,
                "computing parameterization for overlay %s...\n",
                fname);
        MRIStoParameterization(mris_template, mrisp_template, scale, sno*3) ;
        MRISPsetFrameVal(mrisp_template, sno*3+1, 1.0) ;
      }
    }
    else
    {
      mrisp_template = MRISPalloc(scale, PARAM_IMAGES);
      for (sno = 0; sno < SURFACES ; sno++)
      {
        if (curvature_names[sno])  /* read in precomputed curvature file */
        {
          sprintf(fname, "%s/%s.%s", surf_dir, hemi, curvature_names[sno]) ;
          if (MRISreadCurvatureFile(mris_template, fname) != NO_ERROR)
            ErrorExit(Gerror,
                      "%s: could not read curvature file '%s'\n",
                      Progname, fname) ;

          /* the two next lines were not in the original code */
          MRISaverageCurvatures(mris_template, navgs) ;
          MRISnormalizeCurvature(mris_template, which_norm) ;
        }
        else                         /* compute curvature of surface */
        {
          sprintf(fname, "%s/%s.%s", surf_dir, hemi, surface_names[sno]) ;
          if (MRISreadVertexPositions(mris_template, fname) != NO_ERROR)
            ErrorExit(ERROR_NOFILE,
                      "%s: could not read surface file %s",
                      Progname, fname) ;

          if (tnbrs > 1)
          {
            MRISresetNeighborhoodSize(mris_template, tnbrs) ;
          }
          MRIScomputeMetricProperties(mris_template) ;
          MRIScomputeSecondFundamentalForm(mris_template) ;
          MRISuseMeanCurvature(mris_template) ;
          MRISaverageCurvatures(mris_template, navgs) ;
          MRISrestoreVertexPositions(mris_template, CANONICAL_VERTICES) ;
          MRISnormalizeCurvature(mris_template, which_norm) ;
        }
        fprintf(stderr,
                "computing parameterization for surface %s...\n",
                fname);
        MRIStoParameterization(mris_template, mrisp_template, scale, sno*3) ;
        MRISPsetFrameVal(mrisp_template, sno*3+1, 1.0) ;
      }
    }
  }
  else
  {
    fprintf(stderr, "reading template parameterization from %s...\n",
            template_fname) ;
    mrisp_template = MRISPread(template_fname) ;
    if (!mrisp_template)
      ErrorExit(ERROR_NOFILE, "%s: could not open template file %s",
                Progname, template_fname) ;
    if (noverlays > 0)
    {
      if (mrisp_template->Ip->num_frame != IMAGES_PER_SURFACE*noverlays)
        ErrorExit(ERROR_BADPARM,
                  "template frames (%d) doesn't match input (%d x %d) = %d\n",
                  mrisp_template->Ip->num_frame, IMAGES_PER_SURFACE,noverlays,
                  IMAGES_PER_SURFACE*noverlays) ;
    }
  }
  if (use_defaults)
  {
    if (*IMAGEFseq_pix(mrisp_template->Ip, 0, 0, 2) <= 1.0)  /* 1st time */
    {
      parms.l_dist = 5.0 ;
      parms.l_corr = 1.0 ;
      parms.l_parea = 0.2 ;
    }
    else   /* subsequent alignments */
    {
      parms.l_dist = 5.0 ;
      parms.l_corr = 1.0 ;
      parms.l_parea = 0.2 ;
    }
  }

  if (nbrs > 1)
  {
    MRISresetNeighborhoodSize(mris, nbrs) ;
  }
  MRISprojectOntoSphere(mris, mris, DEFAULT_RADIUS) ;
  mris->status = MRIS_PARAMETERIZED_SPHERE ;
  MRIScomputeMetricProperties(mris) ;
  if (!FZERO(parms.l_dist))
  {
    MRISscaleDistances(mris, scale) ;
  }
#if 0
  MRISsaveVertexPositions(mris, ORIGINAL_VERTICES) ;
  MRISzeroNegativeAreas(mris) ;
  MRISstoreMetricProperties(mris) ;
#endif
  MRISstoreMeanCurvature(mris) ;  /* use curvature from file */
  MRISsetOriginalFileName(orig_name) ;
  if (inflated_name)
  {
    MRISsetInflatedFileName(inflated_name) ;
  }
  err = MRISreadOriginalProperties(mris, orig_name) ;
  if (err != 0)
  {
    printf("ERROR %d from MRISreadOriginalProperties().\n",err);
    exit(1);
  }

  if (MRISreadCanonicalCoordinates(mris, canon_name) != NO_ERROR)
    ErrorExit(ERROR_BADFILE, "%s: could not read canon surface %s",
              Progname, canon_name) ;

  if (reverse_flag)
  {
    MRISreverse(mris, REVERSE_X, 1) ;
    MRISsaveVertexPositions(mris, TMP_VERTICES) ;
    MRISrestoreVertexPositions(mris, CANONICAL_VERTICES) ;
    MRISreverse(mris, REVERSE_X, 0) ;
    MRISsaveVertexPositions(mris, CANONICAL_VERTICES) ;
    MRISrestoreVertexPositions(mris, TMP_VERTICES) ;
    MRIScomputeMetricProperties(mris) ;
  }
#if 0
  MRISsaveVertexPositions
  (mris, CANONICAL_VERTICES) ;  // uniform spherical positions
#endif
  if (starting_reg_fname)
    if (MRISreadVertexPositions(mris, starting_reg_fname) != NO_ERROR)
    {
      exit(Gerror) ;
    }

  if (multiframes)
  {
    if (use_initial_registration)
      MRISvectorRegister(mris, mrisp_template, &parms, max_passes,
                         min_degrees, max_degrees, nangles) ;
    parms.l_corr=parms.l_pcorr=0.0f;
#if 0
    parms.l_dist = 0.0 ;
    parms.l_corr = 0.0 ;
    parms.l_parea = 0.0 ;
    parms.l_area = 0.0 ;
    parms.l_parea = 0.0f ;
    parms.l_dist = 0.0 ;
    parms.l_corr = 0.0f ;
    parms.l_nlarea = 0.0f ;
    parms.l_pcorr = 0.0f ;
#endif
    MRISvectorRegister(mris,
                       mrisp_template,
                       &parms,
                       max_passes,
                       min_degrees,
                       max_degrees,
                       nangles) ;
  }
  else
  {
    double l_dist = parms.l_dist ;
    if (multi_scale > 0)
    {
      int i ;

      parms.l_dist = l_dist * pow(5.0, (multi_scale-1.0)) ;
      parms.flags |= IPFLAG_NOSCALE_TOL ;
      parms.flags &= ~IP_USE_CURVATURE ;
      for (i = 0 ; i < multi_scale ; i++)
      {
        printf("*************** round %d, l_dist = %2.3f **************\n", i,
               parms.l_dist) ;
        MRISregister(mris, mrisp_template,
                     &parms, max_passes,
                     min_degrees, max_degrees, nangles) ;
        parms.flags |= IP_NO_RIGID_ALIGN ;
        parms.flags &= ~IP_USE_INFLATED ;
        parms.l_dist /= 5 ;
      }

      if (parms.nbhd_size < 0)
      {
        parms.nbhd_size *= -1 ;
        printf("**** starting 2nd epoch, with long-range distances *****\n");
        parms.l_dist = l_dist * pow(5.0, (multi_scale-2.0)) ;
        for (i = 1 ; i < multi_scale ; i++)
        {
          printf("*********** round %d, l_dist = %2.3f *************\n", i,
                 parms.l_dist) ;
          MRISregister(mris, mrisp_template,
                       &parms, max_passes,
                       min_degrees, max_degrees, nangles) ;
          parms.l_dist /= 5 ;
        }
      }
      printf("****** final curvature registration ***************\n") ;
      if (parms.nbhd_size > 0)
      {
        parms.nbhd_size *= -1 ;  // disable long-range stuff
      }
      parms.l_dist *= 5 ;
      parms.flags |= (IP_USE_CURVATURE | IP_NO_SULC);
      MRISregister(mris, mrisp_template,
                   &parms, max_passes,
                   min_degrees, max_degrees, nangles) ;
    }
    else
      MRISregister(mris, mrisp_template,
                   &parms, max_passes,
                   min_degrees, max_degrees, nangles) ;

  }
  if (remove_negative)
  {
    parms.niterations = 1000 ;
    MRISremoveOverlapWithSmoothing(mris,&parms) ;
  }
  fprintf(stderr, "writing registered surface to %s...\n", out_fname) ;
  MRISwrite(mris, out_fname) ;
  if (jacobian_fname)
  {
    MRIScomputeMetricProperties(mris) ;
    compute_area_ratios(mris) ;  /* will put results in v->curv */
#if 0
    MRISwriteArea(mris, jacobian_fname) ;
#else
    MRISwriteCurvature(mris, jacobian_fname) ;
#endif
  }

  msec = TimerStop(&start) ;
  if (Gdiag & DIAG_SHOW)
    printf("registration took %2.2f hours\n",
           (float)msec/(1000.0f*60.0f*60.0f));
  MRISPfree(&mrisp_template) ;
  MRISfree(&mris) ;
  exit(0) ;
  return(0) ;  /* for ansi */
}
int
main(int argc, char *argv[]) {
  char         **av, fname[STRLEN], *input_name, *subject_name, *cp,*hemi,
  *svm_name, *surf_name, *output_subject_name ;
  int          ac, nargs, vno ;
  int          msec, minutes, seconds ;
  struct timeb start ;
  MRI_SURFACE  *mris ;
  SVM          *svm ;
  double       classification ;
  float        *inputs ;
  MRI_SP       *mrisp ;

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

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

  TimerStart(&start) ;

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

  if (!strlen(subjects_dir)) /* hasn't been set on command line */
  {
    cp = getenv("SUBJECTS_DIR") ;
    if (!cp)
      ErrorExit(ERROR_BADPARM, "%s: SUBJECTS_DIR not defined in environment",
                Progname);
    strcpy(subjects_dir, cp) ;
  }
  if (argc < 7)
    usage_exit(1) ;

  subject_name = argv[1] ;
  hemi = argv[2] ;
  surf_name = argv[3] ;
  input_name = argv[4] ;
  output_subject_name = argv[5] ;
  svm_name = argv[6] ;

  printf("reading svm from %s...\n", svm_name) ;
  svm = SVMread(svm_name) ;
  if (!svm)
    ErrorExit(ERROR_NOFILE, "%s: could not read classifier from %s",
              Progname, svm_name) ;
  if (log_fname != NULL)
    printf("logging results to %s, true_class = %s\n",
           log_fname, true_class > 0 ? svm->class1_name : svm->class2_name) ;

  sprintf(fname, "%s/%s/surf/%s.%s", subjects_dir,subject_name,hemi,surf_name);
  printf("reading surface from %s...\n", fname) ;
  mris = MRISread(fname) ;
  if (!mris)
    ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s for %s",
              Progname, fname, subject_name) ;
  MRISsaveVertexPositions(mris, CANONICAL_VERTICES) ;

  if (MRISreadCurvature(mris, input_name) != NO_ERROR)
    ErrorExit(ERROR_BADPARM, "%s: could not read curvature from %s", input_name) ;

    if (nannotations > 0)
    {
      int vno, a, found ;
      VERTEX *v ;
      
      if (MRISreadAnnotation(mris, annot_name) != NO_ERROR)
        ErrorExit(ERROR_NOFILE, 
                  "%s: could not read annot file %s for subject %s",
                  Progname, annot_name, subject_name) ;
      for (a = 0 ; a < nannotations ; a++)
      {
        int index ;
        
        CTABfindName(mris->ct, anames[a], &index) ;
        CTABannotationAtIndex(mris->ct, index, &annotations[a]) ;
        printf("mapping annot %s to %d\n",
               anames[a], annotations[a]) ;
      }
      // rip all vertices that don't have one of the specified annotations
      for (vno = 0 ; vno < mris->nvertices ; vno++)
      {
        v = &mris->vertices[vno] ;
        if (v->ripflag)
          continue ;
        found = 0 ;
        for (a = 0 ; a < nannotations ; a++)
          if (v->annotation == annotations[a])
            found = 1 ;
        if (found == 0)
          v->ripflag = 1 ;
      }
    }
  if (navgs > 0)
    MRISaverageCurvatures(mris, navgs) ;

  mrisp = MRIStoParameterization(mris, NULL, 1, 0) ;
  MRISfree(&mris) ;

  /* read in output surface */
  sprintf(fname, "%s/%s/surf/%s.%s", subjects_dir,output_subject_name,hemi,surf_name);
  printf("reading output surface from %s...\n", fname) ;
  mris = MRISread(fname) ;
  if (!mris)
    ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s for %s",
              Progname, fname, output_subject_name) ;
  MRISsaveVertexPositions(mris, CANONICAL_VERTICES) ;
  MRISfromParameterization(mrisp, mris, 0) ;

  if (label_name) {
    area = LabelRead(output_subject_name, label_name) ;
    if (!area)
      ErrorExit(ERROR_NOFILE, "%s: could not read label %s", Progname,
                label_name) ;
    MRISmaskNotLabel(mris, area) ;
  } else
    area = NULL ;
  if (mris->nvertices != svm->ninputs)
    ErrorExit(ERROR_BADPARM, "%s: svm input (%d) does not match # of "
              "surface vertices (%d)",
              Progname, svm->ninputs, mris->nvertices);

  inputs = (float *)calloc(mris->nvertices, sizeof(float)) ;
  if (!inputs)
    ErrorExit(ERROR_NOMEMORY, "%s: could not allocate %d input vector",
              Progname, mris->nvertices) ;
  for (vno = 0 ; vno < mris->nvertices ; vno++)
    inputs[vno] = mris->vertices[vno].curv ;
  classification = SVMclassify(svm, inputs) ;
  printf("classification %f, class = %s",classification,
         classification > 0 ? svm->class1_name : svm->class2_name) ;
  if (true_class != 0)
    printf(", %s", true_class*classification>0 ? "CORRECT" : "INCORRECT") ;
  printf("\n") ;

  if (log_fname) {
    FILE *fp ;
    fp = fopen(log_fname, "a") ;
    if (!fp)
      ErrorExit(ERROR_BADPARM, "%s: could not open log file %s", log_fname) ;
    fprintf(fp, "%-30.30s %s %d %f %f\n",
            subject_name, hemi, (true_class*classification)>0, classification,
            true_class) ;
    fclose(fp) ;
  }
  free(inputs) ;
  MRISfree(&mris) ;
  SVMfree(&svm) ;
  msec = TimerStop(&start) ;
  seconds = nint((float)msec/1000.0f) ;
  minutes = seconds / 60 ;
  seconds = seconds % 60 ;
  printf("classification took %d minutes and %d seconds.\n", minutes, seconds) ;
  exit(0) ;
  return(0) ;
}