int
main(int argc, char *argv[])
{
  char        **av, *in_vol, *out_vol;
  int         ac, nargs;

  MRI         *mri_in, *mri_out, *mri_tmp ;
  LTA         *lta = 0;
  MATRIX *i_to_r_src = 0; /* src geometry of the input LTA */
  MATRIX *V_to_V = 0; /* Final voxel-to-voxel transform */
  MATRIX *r_to_i_dst = 0; /* dst geometry of the input LTA */
  MATRIX *m_tmp = 0;
  MATRIX *i_to_r_reg = 0; /* i_to_r of the volume after registration */
  MATRIX *r_to_i_out = 0; /* r_to_i of the final output volume */
  VOL_GEOM vgm_in;
  int x, y, z;
  double maxV, minV, value;
  //  MATRIX *i_to_r, *r_to_i;

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

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

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

  if (argc < 3)
    usage_exit(0) ;

  in_vol = argv[1] ;
  out_vol = argv[2] ;

  printf("reading volume from %s...\n", in_vol) ;
  mri_in = MRIread(in_vol) ;
  if (!mri_in)
    ErrorExit(ERROR_NOFILE, "%s: could not read MRI volume %s", Progname,
              in_vol) ;

  /* Convert mri_in to float type */
  /* double would be more accurate */
  if (mri_in->type != MRI_FLOAT)
  {
    printf("Input volume type is %d\n", mri_in->type);
    printf("Change input volume to float type for convenience and accuracy");
    mri_tmp = MRIchangeType(mri_in, MRI_FLOAT, 0, 1.0, 1);
    MRIfree(&mri_in);
    mri_in = mri_tmp; //swap
  }

  /* Get input volume geometry, which is needed to compute i_to_r
   * and r_to_i of input volume. Note that i_to_r and r_to_i assumed
   * a certain prespecified c_r, c_a, c_s
   */
  getVolGeom(mri_in, &vgm_in);

  maxV = -10000.0;
  minV = 10000.0;
  for (z=0; z < mri_in->depth; z++)
    for (y=0; y< mri_in->height; y++)
      for (x=0; x < mri_in->width; x++)
      {
        if (MRIFvox(mri_in, x, y, z) > maxV )
          maxV = MRIFvox(mri_in, x, y,z) ;
        if (MRIFvox(mri_in, x, y, z) < minV )
          minV = MRIFvox(mri_in, x, y,z) ;
      }

  printf("Input volume has max = %g, min =%g\n", maxV, minV);

  printf("Scale input volume by %g \n", scale);

  maxV = -10000.0;
  minV = 10000.0;
  for (z=0; z < mri_in->depth; z++)
    for (y=0; y< mri_in->height; y++)
      for (x=0; x < mri_in->width; x++)
      {
        MRIFvox(mri_in, x, y, z) *= scale;
        if (MRIFvox(mri_in, x, y, z) > maxV )
          maxV = MRIFvox(mri_in, x, y,z) ;
        if (MRIFvox(mri_in, x, y, z) < minV )
          minV = MRIFvox(mri_in, x, y,z) ;
      }

  printf("Input volume after scaling has max = %g, min =%g\n", maxV, minV);

  /* Try to compute the Voxel_to_Voxel transform from the input volume
   * and the registration target/reference volume!
   * If no registration is involved, vox_to_vox is simply identity
   */
  /* Things become more complicated when allowing inverse transform */
  if (transform_flag)
  {
    int transform_type;

    printf("INFO: Applying transformation from file %s...\n",
           transform_fname);
    transform_type =  TransformFileNameType(transform_fname);

    /* Read in LTA transform file name */
    if (transform_type == MNI_TRANSFORM_TYPE ||
        transform_type == TRANSFORM_ARRAY_TYPE ||
        transform_type == REGISTER_DAT ||
        transform_type == FSLREG_TYPE
       )
    {

      printf("Reading transform ...\n");
      lta = LTAreadEx(transform_fname) ;

      if (!lta)
        ErrorExit(ERROR_NOFILE, "%s: could not read transform file %s",
                  Progname, transform_fname) ;

      if (transform_type == FSLREG_TYPE)
      {
        if (lta_src == 0 || lta_dst == 0)
        {
          fprintf(stderr, "ERROR: fslmat does not have information on the src and dst volumes\n");
          fprintf(stderr, "ERROR: you must give options '-src' and '-dst' to specify the src and dst volume infos for the registration\n");
        }


        LTAmodifySrcDstGeom(lta, lta_src, lta_dst); // add src and dst information
        //The following is necessary to interpret FSLMAT correctly!!!
        LTAchangeType(lta, LINEAR_VOX_TO_VOX);
      }
      if (lta->xforms[0].src.valid == 0)
      {
        if (lta_src == 0)
        {
          fprintf(stderr, "The transform does not have the valid src volume info.\n");
          fprintf(stderr, "Either you give src volume info by option -src or\n");
          fprintf(stderr, "make the transform to have the valid src info.\n");
          ErrorExit(ERROR_BAD_PARM, "Bailing out...\n");
        }
        else
        {
          LTAmodifySrcDstGeom(lta, lta_src, NULL); // add src information
        }
      }
      if (lta->xforms[0].dst.valid == 0)
      {
        if (lta_dst == 0)
        {
          fprintf(stderr, "The transform does not have the valid dst volume info.\n");
          fprintf(stderr, "Either you give src volume info by option -dst or\n");
          fprintf(stderr, "make the transform to have the valid dst info.\n");
          fprintf(stderr, "If the dst was average_305, then you can set\n");
          fprintf(stderr, "environmental variable USE_AVERAGE305 true\n");
          fprintf(stderr, "instead.\n");
          ErrorExit(ERROR_BAD_PARM, "Bailing out...\n");
        }
        else
        {
          LTAmodifySrcDstGeom(lta, NULL, lta_dst); // add  dst information
        }
      }


      // The following procedure aims to apply an LTA computed from COR format to a volume in non-COR format, or vice versa, as long as they share the same RAS
      // first change to LINEAR RAS_TO_RAS using old info
      if (lta->type != LINEAR_RAS_TO_RAS)
      {
        LTAchangeType(lta, LINEAR_RAS_TO_RAS);
      }

      // now possiblly reset the src and dst
      if (lta_src != NULL)
      {
        //always trust the user
        LTAmodifySrcDstGeom(lta, lta_src, NULL);
      }
      if (lta_dst != NULL)
      {
        //always trust the user
        LTAmodifySrcDstGeom(lta, NULL, lta_dst);
      }

      if (lta->type == LINEAR_RAS_TO_RAS)
      {
        /* Convert it to VOX_TO_VOX */
        /* VOXELsrc_to_VOXELdst = R2Vdst*R2Rlta*V2Rsrc */
        /* Note whether the input should be identical to src or dst here depends
         * on whether the LTA here is the direct or inverse transform
         */
        i_to_r_src = vg_i_to_r(&lta->xforms[0].src);
        r_to_i_dst = vg_r_to_i(&lta->xforms[0].dst);

        if (!r_to_i_dst || !i_to_r_src)
          ErrorExit(ERROR_BADFILE, "%s: failed to extract volume geometries from input LTA file",Progname);
        m_tmp = MatrixMultiply(lta->xforms[0].m_L, i_to_r_src, NULL);
        V_to_V = MatrixMultiply(r_to_i_dst, m_tmp, NULL);
        MatrixFree(&m_tmp);

        MatrixFree(&i_to_r_src);
        MatrixFree(&r_to_i_dst);
      }
    }
    else
    {
      fprintf(stderr, "unknown transform type in file %s\n",
              transform_fname);
      exit(1);
    }

    if (invert_flag)
    {
      /* Geometry of input volume should match that of the dst of the LTA */
      if (MYvg_isEqual(&lta->xforms[0].dst, &vgm_in) == 0)
      {
        ErrorExit(ERROR_BADFILE, "%s: dst volume of lta doesn't match that of input volume",Progname);
      }

      i_to_r_reg = vg_i_to_r(&lta->xforms[0].src);

      if (!i_to_r_reg)
        ErrorExit(ERROR_BADFILE, "%s: failed to extract i_to_r of registered volume from LTA",Progname);

      m_tmp =  MatrixInverse(V_to_V, NULL);
      if (!m_tmp)
        ErrorExit(ERROR_BADPARM, "%s: transform is singular!", Progname);

      MatrixFree(&V_to_V);
      V_to_V = m_tmp;
    }
    else
    {
      /* Geometry of input volume should match that of the src of the LTA */
      if (MYvg_isEqual(&lta->xforms[0].src, &vgm_in) == 0)
      {
        ErrorExit(ERROR_BADFILE, "%s: src volume of lta doesn't match that of input volume",Progname);
      }

      i_to_r_reg = vg_i_to_r(&lta->xforms[0].dst);

      if (!i_to_r_reg)
        ErrorExit(ERROR_BADFILE, "%s: failed to extract i_to_r of registered volume from LTA",Progname);
    }

  }
  else
  {
    /* No registration transform need be applied */
    V_to_V = MatrixIdentity(4, NULL);
    i_to_r_reg = extract_i_to_r(mri_in);
    if (!i_to_r_reg)
      ErrorExit(ERROR_BADFILE, "%s: failed to extract i_to_r from input volume",Progname);
  }

  /* Now need to find the vox-to-vox transformation between registered volume
   * (or input volume itself if no registration involved) and the output
   * volume, either in COR format or as the out-like volume
   */
  /* Given a volume with a certain i_to_r, we need to compute the necessary
   * vox-to-voxel transform to change its i_to_r to like another volume.
   * The vox-to-vox is equal to R2V(r_to_i)_likevol*i_to_r_current_vol.
   */
  if (out_like_fname)
  {
    mri_tmp = MRIread(out_like_fname) ;
    if (!mri_tmp)
      ErrorExit(ERROR_NOFILE, "%s: could not read template volume from %s",out_like_fname) ;

    /* out_type = mri_tmp->type; */

    /* specify the out-type to float initially so as not to lose accuracy
     * during reslicing, will change type to correct type later.
     */
    mri_out = MRIalloc(mri_tmp->width, mri_tmp->height, mri_tmp->depth, MRI_FLOAT) ;

    MRIcopyHeader(mri_tmp, mri_out) ;
    MRIfree(&mri_tmp);
  }
  else  /* assume output is in COR format */
  {
    mri_out = MRIalloc(256, 256, 256, MRI_FLOAT) ;
    /* out_type = MRI_UCHAR; */

    /* Who says MRIlinearTransformInterp will change the header??
     * I don't think so!
     */
    //E/ set xyzc_ras to coronal ones.. - these'll get zorched
    //by MRIlinearTransformInterp() - copy again later - is there
    //any use in having them here now?  yes, so we can pass mri_out
    //to the ras2vox fns.


    mri_out->imnr0 = 1; /* what's this? */
    mri_out->imnr1 = 256; /* what's this? */
    mri_out->thick = 1.0;
    mri_out->ps = 1.0; /* what's this? */
    mri_out->xsize = mri_out->ysize = mri_out->zsize = 1.0;
    mri_out->xstart = mri_out->ystart = mri_out->zstart = -128.0;
    mri_out->xend = mri_out->yend = mri_out->zend = 128.0;
    mri_out->x_r =-1;
    mri_out->y_r = 0;
    mri_out->z_r = 0;
    mri_out->x_a = 0;
    mri_out->y_a = 0;
    mri_out->z_a = 1;
    mri_out->x_s = 0;
    mri_out->y_s =-1;
    mri_out->z_s = 0;

    /* In this case, the RAS itself is not fully determined, i.e., c_ras.
     * It's quite arbitrary, different values just change the final
     * sitting of the volume inside the RAS system.
     */
    /* NO! The C_RAS has to be set correctly, depending which target
     * volume the previous Vox_to_Vox transformation assumes!
     * When a registration is involved, the target volume is either
     * the src of LTA (direct) or the dst (inverse transform). When
     * just change format, the target volume is the input itself!!
     */
    if (transform_flag)
    {
      if (invert_flag)
      {
        mri_out->c_r = lta->xforms[0].src.c_r;
        mri_out->c_a = lta->xforms[0].src.c_a;
        mri_out->c_s = lta->xforms[0].src.c_s;

      }
      else
      {
        mri_out->c_r = lta->xforms[0].dst.c_r;
        mri_out->c_a = lta->xforms[0].dst.c_a;
        mri_out->c_s = lta->xforms[0].dst.c_s;
      }
    }
    else
    {
      mri_out->c_r = mri_in->c_r;
      mri_out->c_a = mri_in->c_a;
      mri_out->c_s = mri_in->c_s;
    }

    mri_out->ras_good_flag=1; /* What does this flag mean ? */

    /* since output is just transformed input */
    MRIcopyPulseParameters(mri_in, mri_out) ;

  }

  /* Compute the final input-to-output VOX_to_VOX transformation matrix */
  r_to_i_out = extract_r_to_i(mri_out);

  m_tmp = MatrixMultiply(r_to_i_out, i_to_r_reg, NULL);
  V_to_V = MatrixMultiply(m_tmp, V_to_V, V_to_V);
  MatrixFree(&m_tmp);

  printf("InterpMethod = %d\n", InterpMethod);

  /* Modify the MyMRIlinearTr... if I want to implement my cubic-B-spline
   * interpolation method. Otherwise, unnecessary
   */
  /* mri_out = MyMRIlinearTransformInterp(mri_in, mri_out, V_to_V, InterpMethod); */
  if (InterpMethod == SAMPLE_BSPLINE)
    mri_out = MRIlinearTransformInterpBSpline(mri_in, mri_out, V_to_V,
              SplineDegree);
  else
    mri_out = MRIlinearTransformInterp(mri_in, mri_out, V_to_V, InterpMethod);

  maxV = -10000.0;
  minV = 10000.0;
  for (z=0; z < mri_out->depth; z++)
    for (y=0; y< mri_out->height; y++)
      for (x=0; x < mri_out->width; x++)
      {
        if (MRIFvox(mri_out, x, y, z) > maxV )
          maxV = MRIFvox(mri_out, x, y,z) ;
        if (MRIFvox(mri_out, x, y, z) < minV )
          minV = MRIFvox(mri_out, x, y,z) ;
      }

  if (autoscale)
  {
    noscale = 1;

    /* compute histogram of output volume */
    HISTOGRAM *h, *hsmooth ;
    float fmin, fmax, val, peak, smooth_peak;
    int i, nbins, bin;

    fmin = minV;
    fmax = maxV;
    if (fmin < 0) fmin = 0;
    nbins = 256 ;
    h = HISTOalloc(nbins) ;
    hsmooth = HISTOcopy(h, NULL) ;
    HISTOclear(h, h) ;
    h->bin_size = (fmax-fmin)/255.0 ;

    for (i = 0 ; i < nbins ; i++)
      h->bins[i] = (i+1)*h->bin_size ;

    for (z=0; z < mri_out->depth; z++)
      for (y=0; y< mri_out->height; y++)
        for (x=0; x < mri_out->width; x++)
        {
          val = MRIFvox(mri_out, x, y, z);
          if (val <= 0) continue;

          bin = nint((val - fmin)/h->bin_size);
          if (bin >= h->nbins)
            bin = h->nbins-1;
          else if (bin < 0)
            bin = 0;

          h->counts[bin] += 1.0;
        }
    HISTOfillHoles(h) ;
    HISTOsmooth(h, hsmooth, 5)  ;
    peak =
      hsmooth->bins[HISTOfindHighestPeakInRegion(h, 1, h->nbins)] ;
    //   smooth_peak =
    //  hsmooth->bins[HISTOfindHighestPeakInRegion(hsmooth, 1, hsmooth->nbins)] ;

    smooth_peak =
      hsmooth->bins[HISTOfindLastPeak(hsmooth, 5, 0.8)] ;

    /*
      bin = nint((smooth_peak - fmin)/hsmooth->bin_size) ;

      printf("Highest peak has count = %d\n", (int)hsmooth->counts[bin]);

      bin = nint((420 - fmin)/hsmooth->bin_size) ;

      printf("bin at 420 has count = %d\n", (int)hsmooth->counts[bin]);
    */

    scale =  110.0/smooth_peak;
    printf("peak of output volume is %g, smooth-peak is %g, multiply by %g to scale it to 110\n", peak, smooth_peak, scale);
    for (z=0; z < mri_out->depth; z++)
      for (y=0; y< mri_out->height; y++)
        for (x=0; x < mri_out->width; x++)
        {
          val = MRIFvox(mri_out, x, y, z);
          MRIFvox(mri_out, x, y, z) = val*scale;
        }

  }


  printf("Output volume (before type-conversion) has max = %g, min =%g\n", maxV, minV);

  /* Finally change type to desired */
  if (mri_out->type != out_type)
  {
    printf("Change output volume to type %d\n", out_type);
    /* I need to modify the MIRchangeType function to make sure
     * it does roundoff instead of simple truncation!
     */
    /* Note if the last flag is set to 1, then it won't do scaling
       and small float numbers will become zero after convert to
       BYTE
    */
    if (out_type == 0 && noscale == 1)
    {
      //convert data to UCHAR
      mri_tmp = MRIalloc(mri_out->width, mri_out->height, mri_out->depth, out_type) ;
      MRIcopyHeader(mri_out, mri_tmp);
      for (z=0; z < mri_out->depth; z++)
        for (y=0; y< mri_out->height; y++)
          for (x=0; x < mri_out->width; x++)
          {
            value = floor(MRIgetVoxVal(mri_out, x, y, z, 0) + 0.5);
            if (value < 0 ) value = 0;
            if (value > 255) value = 255;
            MRIvox(mri_tmp,x,y,z) = (unsigned char)value;
          }
    }
    else
      mri_tmp = MRIchangeType(mri_out, out_type, thred_low, thred_high, noscale);

    MRIfree(&mri_out);
    mri_out = mri_tmp; //swap
  }

  MRIwrite(mri_out, out_vol) ;

  MRIfree(&mri_in);
  MRIfree(&mri_out);

  if (lta_src)
    MRIfree(&lta_src);
  if (lta_dst)
    MRIfree(&lta_dst);

  MatrixFree(&V_to_V);

  if (!r_to_i_out)
    MatrixFree(&r_to_i_out);

  if (!i_to_r_reg)
    MatrixFree(&i_to_r_reg);

  return(0) ;  /* for ansi */
}
int
main(int argc, char *argv[]) {
  char         **av, *avg_surf_name, *canon_surf_name, fname[STRLEN],
  *mdir, ico_fname[STRLEN], *hemi, *out_sname ;
  int          ac, nargs, i, vno, n ;
  VERTEX       *v ;
  MRI_SURFACE  *mris_ico ;
  MRI_SP       *mrisp_total ;
  LTA          *lta ;
  VOL_GEOM     vg;
  float        average_surface_area = 0.0 ;
  MATRIX *XFM=NULL;
  GCA_MORPH *gcam=NULL;

  memset((void *) &vg, 0, sizeof (VOL_GEOM));

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

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

  mdir = getenv("FREESURFER_HOME") ;
  if (!mdir)
    ErrorExit(ERROR_BADPARM, 
              "%s: no FREESURFER_HOME in environment.\n",Progname);
  ac = argc ;
  av = argv ;
  for ( ; argc > 1 && ISOPTION(*argv[1]) ; argc--, argv++) {
    nargs = get_option(argc, argv) ;
    argc -= nargs ;
    argv += nargs ;
  }
  if (sdir == NULL) {
    sdir =  getenv("SUBJECTS_DIR");
    if (!sdir)
      ErrorExit(ERROR_BADPARM, 
                "%s: no SUBJECTS_DIR in environment.\n",Progname);
  }
  if (sdirout == NULL) sdirout = sdir;
  if (argc < 6) usage_exit() ;

  hemi = argv[1] ;
  avg_surf_name = argv[2] ;
  canon_surf_name = argv[3] ;
  out_sname = argv[4] ;

  printf("---------------------------------------------------\n");
  printf("hemi            = %s\n",hemi);
  printf("avg_surf_name   = %s\n",avg_surf_name);
  printf("canon_surf_name = %s\n",canon_surf_name);
  printf("out_sname       = %s\n",out_sname);
  printf("xform           = %s\n",xform_name);
  printf("---------------------------------------------------\n");
  printf("\n\n");
  fflush(stdout);

#define SCALE 1
  mrisp_total = MRISPalloc(SCALE, 3) ;
  for (n = 0, i = 5 ; i < argc ; i++) {
    MRI *mri;
    MRI_SURFACE *mris;
    MRI_SP *mrisp;

    printf("\n---------------------------------------------------\n");
    printf("#@# processing subject %d/%d %s...\n", i-4,argc-5,argv[i]) ;
    fflush(stdout);

    // read sphere.reg
    sprintf(fname, "%s/%s/surf/%s.%s", sdir, argv[i], hemi, canon_surf_name) ;
    printf("  Reading %s\n",fname);
    fflush(stdout);
    mris = MRISread(fname) ;
    if (!mris) {
      ErrorExit(ERROR_NOFILE, "%s: could not read surface file %s",
                Progname, fname) ;
      exit(1);
    }
    // get "pial" surface vertex into ->origx, origy, origz
    if (MRISreadOriginalProperties(mris, orig_name) != NO_ERROR)
      ErrorExit(ERROR_BADFILE,"%s: could not read orig file for %s.\n",
                Progname, argv[1]);
    // read transform
    if (0) {
      sprintf(fname, "%s/%s/mri/transforms/%s", sdir, argv[i], xform_name) ;
      lta = LTAreadEx(fname) ;
      if (!lta)
        ErrorExit(ERROR_BADPARM, 
                  "%s: could not read transform from %s", Progname, fname) ;
    }

    // read T1 volume
    sprintf(fname, "%s/%s/mri/T1.mgz", sdir, argv[i]) ;
    if (fio_FileExistsReadable(fname)) mri = MRIreadHeader(fname,MRI_MGH_FILE);
    else {
      sprintf(fname, "%s/%s/mri/T1", sdir, argv[i]) ;
      mri = MRIreadHeader(fname, MRI_UCHAR); // MRI_CORONAL_SLICE_DIRECTORY) ;
    }
    printf("  Read %s\n",fname);
    fflush(stdout);

    if (!mri)
      ErrorExit(ERROR_BADPARM, 
                "%s: could not read reference MRI volume from %s",
                Progname, fname) ;

    // save current vertex position into ->cx
    MRISsaveVertexPositions(mris, CANONICAL_VERTICES) ;
    // get the vertex position from ->origx, ... 
    // (get the "pial" vertex position)
    MRISrestoreVertexPositions(mris, ORIGINAL_VERTICES) ;
    MRIScomputeMetricProperties(mris) ;
    printf("  Surface area: %2.1f cm^2\n", mris->total_area/100) ;
    fflush(stdout);
    average_surface_area += mris->total_area ;

    // this means that we transform "pial" surface

    if (xform_name)
    {
      if (!strcmp(xform_name,"talairach.xfm")) {
        printf("  Applying linear transform\n");
        fflush(stdout);
        XFM = DevolveXFMWithSubjectsDir(argv[i], NULL, "talairach.xfm", sdir);
        if (XFM == NULL) exit(1);
        MRISmatrixMultiply(mris, XFM);
        MatrixFree(&XFM);
      } else if (!strcmp(xform_name,"talairach.m3z")) {
        printf("  Applying GCA Morph\n");
        fflush(stdout);
        sprintf(fname, "%s/%s/mri/transforms/talairach.m3z", sdir, argv[i]) ;
        gcam = GCAMreadAndInvert(fname);
        if (gcam == NULL) exit(1);
        GCAMmorphSurf(mris, gcam);
        GCAMfree(&gcam);
      } else {
        printf("ERROR: don't know what to do with %s\n",xform_name);
        exit(1);
      }
    }

    // save transformed position in ->orig 
    // (store "pial" vertices position in orig)
    MRIScomputeMetricProperties(mris) ;
    MRISsaveVertexPositions(mris, ORIGINAL_VERTICES) ;
    // get the vertex position from ->cx 
    // (note that this is not transformed)  sphere.reg vertices
    MRISrestoreVertexPositions(mris, CANONICAL_VERTICES) ;
    // mris contains sphere.reg in vertex and pial vertices in orig
    // map to a theta-phi space and accumulate values
    mrisp = MRIScoordsToParameterization(mris, NULL, SCALE, ORIGINAL_VERTICES) ;
    MRISPaccumulate(mrisp, mrisp_total, 0) ;
    MRISPaccumulate(mrisp, mrisp_total, 1) ;
    MRISPaccumulate(mrisp, mrisp_total, 2) ;
    MRISPfree(&mrisp) ;
    MRISfree(&mris) ;
    MRIfree(&mri) ;
    //LTAfree(&lta) ;
    fflush(stdout);
    n++ ;
  }
  printf("Finished loading all data\n");
  average_surface_area /= (float)n ;
  printf("Avg surf area = %g cm\n",average_surface_area/100.0);
  fflush(stdout);

  // mrisp_total lost info on the modified surface
  sprintf(ico_fname, "%s/lib/bem/ic%d.tri", mdir, ico_no) ;
  printf("Reading icosahedron from %s...\n", ico_fname) ;
  mris_ico = ICOread(ico_fname) ;
  if (!mris_ico)
    ErrorExit(ERROR_NOFILE, "%s: could not read icosahedron file %s\n",
              Progname,ico_fname) ;
  MRISscaleBrain(mris_ico, mris_ico,
                 DEFAULT_RADIUS/MRISaverageRadius(mris_ico)) ;
  // save current ico position to ->cx, cy, cz
  MRISsaveVertexPositions(mris_ico, CANONICAL_VERTICES) ;
  // using mrisp_total to calculate position into ->origx, origy, origz 
  // (orig is the "pial" vertices)
  MRIScoordsFromParameterization(mrisp_total, mris_ico, ORIGINAL_VERTICES) ;
  // copy geometry info
  memcpy((void *) &mris_ico->vg, (void *) &vg, sizeof (VOL_GEOM));

  if (Gdiag_no >= 0 && Gdiag_no < mris_ico->nvertices) {
    int n ;
    VERTEX *vn ;

    v = &mris_ico->vertices[Gdiag_no] ;
    printf( "v %d: x = (%2.2f, %2.2f, %2.2f)\n",
            Gdiag_no, v->origx, v->origy, v->origz) ;
    for (n = 0 ; n < v->vnum ; n++) {
      vn = &mris_ico->vertices[v->v[n]] ;
      printf( "v %d: x = (%2.2f, %2.2f, %2.2f)\n",
              v->v[n], vn->origx, vn->origy, vn->origz) ;
    }
  }
  // write *h.sphere.reg
  sprintf(fname, "%s/%s/surf/%s.%s", 
          sdirout, out_sname, hemi, canon_surf_name) ;
  if (Gdiag & DIAG_SHOW)
    printf("writing average canonical surface to %s\n", fname);
  MRISwrite(mris_ico, fname) ;

  // get "pial vertices" from orig
  MRISrestoreVertexPositions(mris_ico, ORIG_VERTICES);
  for (vno = 0 ; vno < mris_ico->nvertices ; vno++) {
    v = &mris_ico->vertices[vno] ;
    // n = number of subjects
    v->x /= (float)n ;
    v->y /= (float)n ;
    v->z /= (float)n ;
  }
  if (normalize_area) {
    MRIScomputeMetricProperties(mris_ico) ;
    printf("setting group surface area to be %2.1f cm^2 (scale=%2.2f)\n",
           average_surface_area/100.0,
           sqrt(average_surface_area/mris_ico->total_area)) ;

#if 0
    MRISscaleBrain(mris_ico, mris_ico,
                   sqrt(average_surface_area/mris_ico->total_area)) ;
#else
    mris_ico->group_avg_surface_area = average_surface_area ;
#endif
    MRIScomputeMetricProperties(mris_ico) ;
  }

  sprintf(fname, "%s/%s/surf/%s.%s", sdirout,out_sname, hemi, avg_surf_name) ;
  printf("writing average %s surface to %s\n", avg_surf_name, fname);
  MRISwrite(mris_ico,  fname) ;

  if (0) {
    char path[STRLEN] ;
    LTA  *lta ;

    FileNamePath(fname, path) ;
    lta = LTAalloc(1, NULL) ;
    // write to a different location
    sprintf(fname, "%s/../mri/transforms/%s", path,xform_name) ;
    LTAwriteEx(lta, fname) ;
    LTAfree(&lta) ;
  }

  MRISfree(&mris_ico) ;
  MRISPfree(&mrisp_total) ;

  printf("mris_make_average_surface done\n");

  exit(0) ;
  return(0) ;  /* for ansi */
}
int
main(int argc, char *argv[]) {
  char   **av, *cp ;
  int    ac, nargs, i, dof, no_transform, which, sno = 0, nsubjects = 0 ;
  MRI    *mri=0, *mri_mean = NULL, *mri_std=0, *mri_T1=0,*mri_binary=0,*mri_dof=NULL,
                             *mri_priors = NULL ;
  char   *subject_name, *out_fname, fname[STRLEN] ;
  /*  LTA    *lta;*/
  MRI *mri_tmp=0 ;

  /* rkt: check for and handle version tag */
  nargs = handle_version_option (argc, argv, "$Id: mri_make_template.c,v 1.26 2011/03/02 00:04:22 nicks Exp $", "$Name: stable5 $");
  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 (!strlen(subjects_dir)) {
    cp = getenv("SUBJECTS_DIR") ;
    if (!cp)
      ErrorExit(ERROR_BADPARM,"%s: SUBJECTS_DIR not defined in environment.\n",
                Progname) ;
    strcpy(subjects_dir, cp) ;
  }

  if (argc < 3)  usage_exit(1) ;

  out_fname = argv[argc-1] ;

  no_transform = first_transform ;
  if (binary_name)   /* generate binarized volume with priors and */
  {                  /* separate means and variances */
    for (which = BUILD_PRIORS ; which <= OFF_STATS ; which++) {
      /* for each subject specified on cmd line */
      for (dof = 0, i = 1 ; i < argc-1 ; i++) {
        if (*argv[i] == '-')   /* don't do transform for next subject */
        { no_transform = 1 ;
          continue ;
        }
        dof++ ;
        subject_name = argv[i] ;
        if (which != BUILD_PRIORS) {
          sprintf(fname, "%s/%s/mri/%s", subjects_dir, subject_name, T1_name);
          fprintf(stderr, "%d of %d: reading %s...\n", i, argc-2, fname) ;
          mri_T1 = MRIread(fname) ;
          if (!mri_T1)
            ErrorExit(ERROR_NOFILE,"%s: could not open volume %s",
                      Progname,fname);
        }

        sprintf(fname, "%s/%s/mri/%s",subjects_dir,subject_name,binary_name);
        fprintf(stderr, "%d of %d: reading %s...\n", i, argc-2, fname) ;
        mri_binary = MRIread(fname) ;
        if (!mri_binary)
          ErrorExit(ERROR_NOFILE,"%s: could not open volume %s",
                    Progname,fname);

        /* only count voxels which are mostly labeled */
        MRIbinarize(mri_binary, mri_binary, WM_MIN_VAL, 0, 100) ;
        if (transform_fname && no_transform-- <= 0) {
          sprintf(fname, "%s/%s/mri/transforms/%s",
                  subjects_dir, subject_name, transform_fname) ;

          fprintf(stderr, "reading transform %s...\n", fname) ;
          ////////////////////////////////////////////////////////
#if 1
          {
            TRANSFORM *transform ;
            transform = TransformRead(fname) ;
            if (transform == NULL)
              ErrorExit(ERROR_NOFILE, "%s: could not open transform file %s\n",Progname, fname) ;
            mri_tmp = TransformApply(transform, mri_T1, NULL) ;
            TransformFree(&transform) ;
          }
#else
          lta = LTAreadEx(fname);
          if (lta == NULL)
            ErrorExit(ERROR_NOFILE,
                      "%s: could not open transform file %s\n",
                      Progname, fname) ;
          /* LTAtransform() runs either MRIapplyRASlinearTransform()
          for RAS2RAS or MRIlinearTransform() for Vox2Vox. */
          /* MRIlinearTransform() calls MRIlinearTransformInterp() */
          mri_tmp = LTAtransform(mri_T1, NULL, lta);
          MRIfree(&mri_T1) ;
          mri_T1 = mri_tmp ;
          LTAfree(&lta);
          lta = NULL;
#endif
          if (DIAG_VERBOSE_ON)
            fprintf(stderr, "transform application complete.\n") ;
        }
        if (which == BUILD_PRIORS) {
          mri_priors =
            MRIupdatePriors(mri_binary, mri_priors) ;
        } else {
          if (!mri_mean) {
            mri_dof = MRIalloc(mri_T1->width, mri_T1->height, mri_T1->depth,
                               MRI_UCHAR) ;
            mri_mean =
              MRIalloc(mri_T1->width, mri_T1->height,mri_T1->depth,MRI_FLOAT);
            mri_std =
              MRIalloc(mri_T1->width,mri_T1->height,mri_T1->depth,MRI_FLOAT);
            if (!mri_mean || !mri_std)
              ErrorExit(ERROR_NOMEMORY, "%s: could not allocate templates.\n",
                        Progname) ;
          }

          if (DIAG_VERBOSE_ON)
            fprintf(stderr, "updating mean and variance estimates...\n") ;
          if (which == ON_STATS) {
            MRIaccumulateMaskedMeansAndVariances(mri_T1, mri_binary, mri_dof,
                                                 90, 100, mri_mean, mri_std) ;
            fprintf(stderr, "T1 = %d, binary = %d, mean = %2.1f\n",
                    (int)MRIgetVoxVal(mri_T1, 141,100,127,0),
                    MRIvox(mri_binary, 141,100,127),
                    MRIFvox(mri_mean, 141,100,127)) ;
          } else  /* computing means and vars for off */
            MRIaccumulateMaskedMeansAndVariances(mri_T1, mri_binary, mri_dof,
                                                 0, WM_MIN_VAL-1,
                                                 mri_mean, mri_std) ;
          MRIfree(&mri_T1) ;
        }
        MRIfree(&mri_binary) ;
      }

      if (which == BUILD_PRIORS) {
        mri = MRIcomputePriors(mri_priors, dof, NULL) ;
        MRIfree(&mri_priors) ;
        fprintf(stderr, "writing priors to %s...\n", out_fname) ;
      } else {
        MRIcomputeMaskedMeansAndStds(mri_mean, mri_std, mri_dof) ;
        mri_mean->dof = dof ;

        fprintf(stderr, "writing T1 means with %d dof to %s...\n", mri_mean->dof,
                out_fname) ;
        if (!which)
          MRIwrite(mri_mean, out_fname) ;
        else
          MRIappend(mri_mean, out_fname) ;
        MRIfree(&mri_mean) ;
        fprintf(stderr, "writing T1 variances to %s...\n", out_fname);
        if (dof <= 1)
          MRIreplaceValues(mri_std, mri_std, 0, 1) ;
        mri = mri_std ;
      }

      if (!which)
        MRIwrite(mri, out_fname) ;
      else
        MRIappend(mri, out_fname) ;
      MRIfree(&mri) ;
    }
  }
  else {
    /* for each subject specified on cmd line */

    if (xform_mean_fname) {
      m_xform_mean = MatrixAlloc(4,4,MATRIX_REAL) ;
      /* m_xform_covariance = MatrixAlloc(12,12,MATRIX_REAL) ;*/
    }

    dof = 0;
    for (i = 1 ; i < argc-1 ; i++) {

      if (*argv[i] == '-') {
        /* don't do transform for next subject */
        no_transform = 1 ;
        continue ;
      }
      dof++ ;

      subject_name = argv[i] ;
      sprintf(fname, "%s/%s/mri/%s", subjects_dir, subject_name, T1_name);
      fprintf(stderr, "%d of %d: reading %s...\n", i, argc-2, fname) ;
      mri_T1 = MRIread(fname) ;
      if (!mri_T1)
        ErrorExit(ERROR_NOFILE,"%s: could not open volume %s",Progname,fname);
      check_mri(mri_T1) ;

      if (binarize)
        MRIbinarize(mri_T1, mri_T1, binarize, 0, 1) ;
      if (erode) {
        int i ;
        printf("eroding input %d times\n", erode) ;
        for (i = 0 ; i < erode ; i++)
          MRIerode(mri_T1, mri_T1) ;
      }
      if (open) {
        int i ;
        printf("opening input %d times\n", open) ;
        for (i = 0 ; i < open ; i++)
          MRIerode(mri_T1, mri_T1) ;
        for (i = 0 ; i < open ; i++)
          MRIdilate(mri_T1, mri_T1) ;
      }

      check_mri(mri_T1) ;
      if (transform_fname) {

        sprintf(fname, "%s/%s/mri/transforms/%s",
                subjects_dir, subject_name, transform_fname) ;

        fprintf(stderr, "reading transform %s...\n", fname) ;
        ////////////////////////////////////////////////////////
#if 1
        {
          TRANSFORM *transform ;
          transform = TransformRead(fname) ;
          if (transform == NULL)
            ErrorExit(ERROR_NOFILE, "%s: could not open transform file %s\n",Progname, fname) ;
          mri_tmp = TransformApply(transform, mri_T1, NULL) ;
          if (DIAG_VERBOSE_ON)
            MRIwrite(mri_tmp, "t1.mgz") ;
          TransformFree(&transform) ;
        }
#else
        lta = LTAreadEx(fname);
        if (lta == NULL)
          ErrorExit(ERROR_NOFILE,
                    "%s: could not open transform file %s\n",
                    Progname, fname) ;
        printf("transform matrix -----------------------\n");
        MatrixPrint(stdout,lta->xforms[0].m_L);
        /* LTAtransform() runs either MRIapplyRASlinearTransform()
        for RAS2RAS or MRIlinearTransform() for Vox2Vox. */
        /* MRIlinearTransform() calls MRIlinearTransformInterp() */
        mri_tmp = LTAtransform(mri_T1, NULL, lta);
        printf("----- -----------------------\n");
        LTAfree(&lta);
#endif
        MRIfree(&mri_T1);
        mri_T1 = mri_tmp ; // reassign pointers
        if (DIAG_VERBOSE_ON)
          fprintf(stderr, "transform application complete.\n") ;
      }

      if (!mri_mean) {
        mri_mean =
          MRIalloc(mri_T1->width, mri_T1->height, mri_T1->depth, MRI_FLOAT) ;
        mri_std =
          MRIalloc(mri_T1->width, mri_T1->height, mri_T1->depth, MRI_FLOAT) ;
        if (!mri_mean || !mri_std)
          ErrorExit(ERROR_NOMEMORY, "%s: could not allocate templates.\n",
                    Progname) ;
        // if(transform_fname == NULL){
        if (DIAG_VERBOSE_ON)
          printf("Copying geometry\n");
        MRIcopyHeader(mri_T1,mri_mean);
        MRIcopyHeader(mri_T1,mri_std);
        // }
      }

      check_mri(mri_mean) ;
      if (!stats_only) {
        if (DIAG_VERBOSE_ON)
          fprintf(stderr, "updating mean and variance estimates...\n") ;
        MRIaccumulateMeansAndVariances(mri_T1, mri_mean, mri_std) ;
      }

      check_mri(mri_mean) ;
      if (DIAG_VERBOSE_ON)
        MRIwrite(mri_mean, "t2.mgz") ;
      MRIfree(&mri_T1) ;
      no_transform = 0;
    } /* end loop over subjects */

    if (xform_mean_fname) {
      FILE   *fp ;
      VECTOR *v = NULL, *vT = NULL ;
      MATRIX *m_vvT = NULL ;
      int    rows, cols ;

      nsubjects = sno ;

      fp = fopen(xform_covariance_fname, "w") ;
      if (!fp)
        ErrorExit(ERROR_NOFILE, "%s: could not open covariance file %s",
                  Progname, xform_covariance_fname) ;
      fprintf(fp, "nsubjects=%d\n", nsubjects) ;

      MatrixScalarMul(m_xform_mean, 1.0/(double)nsubjects, m_xform_mean) ;
      printf("means:\n") ;
      MatrixPrint(stdout, m_xform_mean) ;
      MatrixAsciiWrite(xform_mean_fname, m_xform_mean) ;

      /* subtract the mean from each transform */
      rows = m_xform_mean->rows ;
      cols = m_xform_mean->cols ;
      for (sno = 0 ; sno < nsubjects ; sno++) {
        MatrixSubtract(m_xforms[sno], m_xform_mean, m_xforms[sno]) ;
        v = MatrixReshape(m_xforms[sno], v, rows*cols, 1) ;
        vT = MatrixTranspose(v, vT) ;
        m_vvT = MatrixMultiply(v, vT, m_vvT) ;
        if (!m_xform_covariance)
          m_xform_covariance =
            MatrixAlloc(m_vvT->rows, m_vvT->cols,MATRIX_REAL) ;
        MatrixAdd(m_vvT, m_xform_covariance, m_xform_covariance) ;
        MatrixAsciiWriteInto(fp, m_xforms[sno]) ;
      }

      MatrixScalarMul(m_xform_covariance, 1.0/(double)nsubjects,
                      m_xform_covariance) ;
      printf("covariance:\n") ;
      MatrixPrint(stdout, m_xform_covariance) ;
      MatrixAsciiWriteInto(fp, m_xform_covariance) ;
      fclose(fp) ;
      if (stats_only)
        exit(0) ;
    }

    MRIcomputeMeansAndStds(mri_mean, mri_std, dof) ;
    check_mri(mri_mean) ;
    check_mri(mri_std) ;

    mri_mean->dof = dof ;

    if (smooth) {
      MRI *mri_kernel, *mri_smooth ;

      printf("applying smoothing kernel\n") ;
      mri_kernel = MRIgaussian1d(smooth, 100) ;
      mri_smooth = MRIconvolveGaussian(mri_mean, NULL, mri_kernel) ;
      MRIfree(&mri_kernel) ;
      MRIfree(&mri_mean) ;
      mri_mean = mri_smooth ;
    }
    fprintf(stderr, "\nwriting T1 means with %d dof to %s...\n", mri_mean->dof,
            out_fname) ;
    MRIwrite(mri_mean, out_fname) ;
    MRIfree(&mri_mean) ;
    if (dof <= 1) /* can't calculate variances - set them to reasonable val */
    {
      //               src      dst
      MRIreplaceValues(mri_std, mri_std, 0, 1) ;
    }
    if (!novar) {
      // mri_std contains the variance here  (does it?? I don't think so -- BRF)
      if (!var_fname) {
        fprintf(stderr, "\nwriting T1 standard deviations to %s...\n", out_fname);
        MRIappend(mri_std, out_fname) ;
      } else {
        fprintf(stderr, "\nwriting T1 standard deviations to %s...\n", var_fname);
        MRIwrite(mri_std, var_fname) ;
      }
    }
    MRIfree(&mri_std) ;
    if (mri)
      MRIfree(&mri);
  } /* end if binarize */
  return(0) ;
}
int main(int argc, char *argv[]) {
  char **av;
  MRI *mri_T1, *mri_tmp, *mri_ctrl, *mri_in, *mri_out;
  MRI *mri_snr, *mri_bias;
  MRI *mri_mask1 = NULL;
  MRI *mri_mask2 = NULL;

  int ac, nargs;
  int  width, height, depth, x, y, z;
  int mask1_set = 0;
  int mask2_set = 0;
  int i, j, k, cx, cy, cz, count;
  LTA          *lta = 0;
  int          transform_type;
  double mean, std, value, src, bias, norm;
//  HISTOGRAM *h;
//  float bin_size;
//  int nbins, bin_no;
  double mean1, std1, mean2, std2, count1, count2, slope, offset;
  VOL_GEOM vgtmp;
  LT *lt = NULL;
  MATRIX *m_tmp = NULL;

  Progname = argv[0];

  nargs = handle_version_option
          (argc, argv,
           "$Id: mri_normalize_tp2.c,v 1.8 2011/03/02 00:04:23 nicks Exp $",
           "$Name: stable5 $");
  if (nargs && argc - nargs == 1)
    exit (0);
  argc -= nargs ;

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

  if (argc  !=  3)
    usage(1);

  if (tp1_ctrl_fname == NULL  || tp1_T1_fname == NULL) {
    printf("Use options to specify ctrl volume and T1 volume for tp1\n");
    usage(1);
  }

  mri_in = MRIread(argv[1]) ;
  if (!mri_in)
    ErrorExit(ERROR_BADPARM, "%s: could not read input volume %s",
              Progname, argv[1]) ;

  mri_T1 = MRIread(tp1_T1_fname) ;
  if (!mri_T1)
    ErrorExit(ERROR_BADPARM, "%s: could not read T1 volume for tp1 %s",
              Progname, tp1_T1_fname) ;

  mri_ctrl = MRIread(tp1_ctrl_fname) ;
  if (!mri_ctrl)
    ErrorExit(ERROR_BADPARM,
              "%s: could not read control points volume for tp1 %s",
              Progname, tp1_ctrl_fname) ;

  if ((mri_in->width != mri_T1->width) ||
      (mri_in->height != mri_T1->height) ||
      (mri_in->depth != mri_T1->depth) ||
      (mri_in->width != mri_ctrl->width) ||
      (mri_in->height != mri_ctrl->height) ||
      (mri_in->depth != mri_ctrl->depth)
     ) ErrorExit
         (ERROR_BADPARM,
          "%s: three input volumes have different sizes \n", Progname);

  if (mask1_fname) {
    mri_mask1 = MRIread(mask1_fname) ;
    if (!mri_mask1)
      ErrorExit(ERROR_BADPARM,
                "%s, could not read mask volume for tp1 %s",
                Progname, mask1_fname);
    mask1_set = 1;
    if ((mri_mask1->width != mri_in->width) ||
        (mri_mask1->height != mri_in->height) ||
        (mri_mask1->depth != mri_in->depth))
      ErrorExit
      (ERROR_BADPARM,
       "%s:  mask volumes have different sizes than other volumes \n",
       Progname);
  }
  if (mask2_fname) {
    mri_mask2 = MRIread(mask2_fname) ;
    if (!mri_mask2)
      ErrorExit
      (ERROR_BADPARM,
       "%s, could not read mask volume for tp2 %s",
       Progname, mask2_fname);
    mask2_set = 1;
    if ((mri_mask2->width != mri_T1->width) ||
        (mri_mask2->height != mri_T1->height) ||
        (mri_mask2->depth != mri_T1->depth)
       )
      ErrorExit
      (ERROR_BADPARM,
       "%s:  mask volumes have different sizes than other volumes \n",
       Progname);
  }

  width = mri_in->width ;
  height = mri_in->height ;
  depth = mri_in->depth ;

  //nbins = 200;
  //h = HISTOalloc(nbins);

  mri_out = MRIclone(mri_in, NULL) ;

  /* Read LTA transform and apply it to mri_ctrl */
  if (xform_fname != NULL) {
    // read transform
    transform_type =  TransformFileNameType(xform_fname);

    if (transform_type == MNI_TRANSFORM_TYPE ||
        transform_type == TRANSFORM_ARRAY_TYPE ||
        transform_type == REGISTER_DAT ||
        transform_type == FSLREG_TYPE
       ) {
      printf("Reading transform ...\n");
      lta = LTAreadEx(xform_fname) ;
      if (!lta)
        ErrorExit(ERROR_NOFILE, "%s: could not read transform file %s",
                  Progname, xform_fname) ;

      if (transform_type == FSLREG_TYPE) {
        if (lta_src == 0 || lta_dst == 0) {
          fprintf
          (stderr,
           "ERROR: fslmat does not have information "
           "on the src and dst volumes\n");
          fprintf
          (stderr,
           "ERROR: you must give options '-lta_src' and "
           "'-lta_dst' to specify the src and dst volume infos\n");
        }

        LTAmodifySrcDstGeom
        (lta, lta_src, lta_dst); // add src and dst information
        LTAchangeType(lta, LINEAR_VOX_TO_VOX); //this is necessary
      }

      if (lta->xforms[0].src.valid == 0) {
        if (lta_src == 0) {
          fprintf
          (stderr,
           "The transform does not have the valid src volume info.\n");
          fprintf
          (stderr,
           "Either you give src volume info by option -lta_src or\n");
          fprintf(stderr, "make the transform to have the valid src info.\n");
          ErrorExit(ERROR_BAD_PARM, "Bailing out...\n");
        } else {
          LTAmodifySrcDstGeom(lta, lta_src, NULL); // add src information
          //   getVolGeom(lta_src, &lt->src);
        }
      }
      if (lta->xforms[0].dst.valid == 0) {
        if (lta_dst == 0) {
          fprintf
          (stderr,
           "The transform does not have the valid dst volume info.\n");
          fprintf
          (stderr,
           "Either you give src volume info by option -lta_dst or\n");
          fprintf
          (stderr,
           "make the transform to have the valid dst info.\n");
          fprintf
          (stderr,
           "If the dst was average_305, then you can set\n");
          fprintf
          (stderr,
           "environmental variable USE_AVERAGE305 true\n");
          fprintf
          (stderr,
           "without giving the dst volume for RAS-to-RAS transform.\n");
          ErrorExit(ERROR_BAD_PARM, "Bailing out...\n");
        } else {
          LTAmodifySrcDstGeom(lta, NULL, lta_dst); // add  dst information
        }
      }
    } else {
      ErrorExit
      (ERROR_BADPARM,
       "transform is not of MNI, nor Register.dat, nor FSLMAT type");
    }

    if (invert) {
      m_tmp = lta->xforms[0].m_L ;
      lta->xforms[0].m_L = MatrixInverse(lta->xforms[0].m_L, NULL) ;
      MatrixFree(&m_tmp) ;
      lt = &lta->xforms[0];
      if (lt->dst.valid == 0 || lt->src.valid == 0) {
        fprintf
        (stderr,
         "WARNING:***********************************************\n");
        fprintf
        (stderr,
         "WARNING: dst volume infor is invalid.  "
         "Most likely produce wrong inverse.\n");
        fprintf
        (stderr,
         "WARNING:***********************************************\n");
      }
      copyVolGeom(&lt->dst, &vgtmp);
      copyVolGeom(&lt->src, &lt->dst);
      copyVolGeom(&vgtmp, &lt->src);
    }

    //    LTAchangeType(lta, LINEAR_VOX_TO_VOX);

    /* apply lta to the ctrl volume */
    mri_tmp = MRIalloc(mri_ctrl->width,
                       mri_ctrl->height,
                       mri_ctrl->depth,
                       mri_ctrl->type) ;
    MRIcopyHeader(mri_in, mri_tmp) ;
    // this function doesn't do NEAREST at all!!
    // I found the bug, in LTAtransformInterp()
    mri_tmp = LTAtransformInterp(mri_ctrl, mri_tmp, lta, SAMPLE_NEAREST);

    MRIfree(&mri_ctrl);
    mri_ctrl = mri_tmp;

    if (mask1_fname != NULL && mask2_fname == NULL) {
      printf("map mask for tp1 to get mask for tp2 ...\n");
      mri_mask2 = MRIalloc(mri_in->width,
                           mri_in->height,
                           mri_in->depth,
                           mri_mask1->type) ;
      MRIcopyHeader(mri_in, mri_mask2) ;

      mri_mask2 = LTAtransformInterp(mri_mask1,
                                     mri_mask2,
                                     lta,
                                     SAMPLE_NEAREST);
      mask2_set = 1;
      if (debug_flag)
        MRIwrite(mri_mask2, "mri_mask2.mgz");
    } else if (mask2_fname != NULL && mask1_fname == NULL) {
      printf("map mask for tp2 to get mask for tp1 ...\n");
      //need to invert lta first
      m_tmp = lta->xforms[0].m_L ;
      lta->xforms[0].m_L = MatrixInverse(lta->xforms[0].m_L, NULL) ;
      MatrixFree(&m_tmp) ;
      lt = &lta->xforms[0];

      copyVolGeom(&lt->dst, &vgtmp);
      copyVolGeom(&lt->src, &lt->dst);
      copyVolGeom(&vgtmp, &lt->src);

      mri_mask1 = MRIalloc(mri_T1->width,
                           mri_T1->height,
                           mri_T1->depth,
                           mri_mask2->type) ;
      MRIcopyHeader(mri_T1, mri_mask1) ;

      mri_mask1 = LTAtransformInterp(mri_mask2,
                                     mri_mask1,
                                     lta,
                                     SAMPLE_NEAREST);
      mask1_set = 1;
      if (debug_flag)
        MRIwrite(mri_mask1, "mri_mask1.mgz");
    }

    if (lta_src)
      MRIfree(&lta_src);
    if (lta_dst)
      MRIfree(&lta_dst);

    if (lta)
      LTAfree(&lta);
  }   /* if (xform_fname != NULL) */

  if (debug_flag) {
    //    MRIwrite(mri_snr, "snr.mgz");
    MRIwrite(mri_ctrl, "ctrl.mgz");
  }

  if (mask1_set == 0) {
    //create mask1
    mri_mask1 = MRIalloc(mri_T1->width,
                         mri_T1->height,
                         mri_T1->depth,
                         MRI_UCHAR) ;
    for (z=0; z < depth; z++)
      for (y=0; y< height; y++)
        for (x=0; x < width; x++) {
          if (MRIgetVoxVal(mri_T1, x, y, z, 0) < noise_threshold) {
            MRIvox(mri_mask1,x,y,z) = 0;
          } else
            MRIvox(mri_mask1,x,y,z) = 1;
        }
  }

  if (mask2_set == 0) {
    //create mask2
    mri_mask2 = MRIalloc(mri_in->width,
                         mri_in->height,
                         mri_in->depth,
                         MRI_UCHAR) ;
    for (z=0; z < depth; z++)
      for (y=0; y< height; y++)
        for (x=0; x < width; x++) {
          if (MRIgetVoxVal(mri_in, x, y, z, 0) < noise_threshold) {
            MRIvox(mri_mask2,x,y,z) = 0;
          } else
            MRIvox(mri_mask2,x,y,z) = 1;
        }
  }


#if 0
  /* compute the mean and std of T1 volume */
  /* Using only high SNR points */
  mri_snr = MRIalloc(mri_T1->width, mri_T1->height, mri_T1->depth, MRI_FLOAT) ;
  MRIcopyHeader(mri_T1, mri_snr) ;

  h->bin_size = bin_size = 0.5;
  for (bin_no = 0; bin_no < nbins; bin_no++)
    h->bins[bin_no] = (bin_no)*bin_size;

  for (z=0; z < depth; z++)
    for (y=0; y< height; y++)
      for (x=0; x < width; x++) {
        if (MRIgetVoxVal(mri_T1, x, y, z, 0) < noise_threshold) {
          MRIFvox(mri_snr,x,y,z) = 0;
          continue;
        }
        mean = 0;
        std = 0;
        count = 0;
        for (i=-1; i<=1; i++)
          for (j=-1; j<=1; j++)
            for (k=-1;k<=1;k++) {
              cx = x+i;
              cy = y+j, cz = z+k;

              if (cx < 0 ||
                  cx >= width ||
                  cy < 0 ||
                  cy >= height ||
                  cz < 0 ||
                  cz >= depth) continue;
              count++;
              value = MRIgetVoxVal(mri_T1, cx, cy, cz, 0);
              mean += value;
              std += value*value;
            }

        mean /= (count + 1e-30);
        std /=  (count + 1e-30);

        std = std - mean *mean;

        if (std <= 0)
          std = 0;
        value = mean/sqrt(std);

        MRIFvox(mri_snr,x,y,z) = value;
        bin_no = nint((float)value/(float)bin_size);
        if (bin_no >= nbins) bin_no = nbins - 1;
        h->counts[bin_no]++;
      }

  for (num = 0.0f, b = h->nbins - 1; b >= 1; b --) {
    num += h->counts[b];
    if (num > 20000) /* this may make me only use WM points,
                        is it good to use only WM to compute
                        scale of intensity?? */
      break;
  }

  printf("using SNR threshold %2.3f at bin %d\n", h->bins[b], b);

  mean1 = 0;
  std1 = 0;
  count1 = 0;
  for (z=0; z < depth; z++)
    for (y=0; y< height; y++)
      for (x=0; x < width; x++) {
        if (MRIgetVoxVal(mri_T1, x, y, z, 0) < noise_threshold) {
          continue;
        }

        value = MRIFvox(mri_snr,x,y,z);

        if (value < h->bins[b]) continue;

        value = MRIgetVoxVal(mri_T1, x, y, z, 0);
        count1++;
        mean1 += value;
        std1 += value*value;

      }

  MRIfree(&mri_snr);
#else
  printf("compute mean and std of tp1 volume within masked area...\n");
  mean1 = 0;
  std1 = 0;
  count1 = 0;
  for (z=0; z < depth; z++)
    for (y=0; y< height; y++)
      for (x=0; x < width; x++) {
        if (MRIgetVoxVal(mri_mask1, x, y, z, 0) <= 1e-30) {
          continue;
        }

        value = MRIgetVoxVal(mri_T1, x, y, z, 0);


        count1++;
        mean1 += value;
        std1 += value*value;

      }

#endif

  mean1 /= (count1 + 1e-30);
  std1 /= (count1 + 1e-30);
  std1 = std1 - mean1*mean1;
  if (std1 <= 0)
    printf("warning: negative std for T1 volume. \n");
  else
    printf("mean and variance for tp1 volume are %g and %g\n", mean1, std1);

  printf("now compute SNR and stats for input volume ... \n");
  mri_snr = MRIalloc(mri_in->width, mri_in->height, mri_in->depth, MRI_FLOAT) ;
  MRIcopyHeader(mri_in, mri_snr) ;
  //HISTOclear(h,h);
  //h->bin_size = bin_size = 0.5;
  //for (bin_no = 0; bin_no < nbins; bin_no++)
  //  h->bins[bin_no] = (bin_no)*bin_size;

  for (z=0; z < depth; z++)
    for (y=0; y< height; y++)
      for (x=0; x < width; x++) {
        if (MRIgetVoxVal(mri_in, x, y, z, 0) < noise_threshold) {
          MRIFvox(mri_snr,x,y,z) = 0;
          continue;
        }
        mean = 0;
        std = 0;
        count = 0;
        for (i=-1; i<=1; i++)
          for (j=-1; j<=1; j++)
            for (k=-1;k<=1;k++) {
              cx = x+i;
              cy = y+j, cz = z+k;

              if (cx < 0 ||
                  cx >= width ||
                  cy < 0 ||
                  cy >= height ||
                  cz < 0 ||
                  cz >= depth) continue;
              count++;
              value = MRIgetVoxVal(mri_in, cx, cy, cz, 0);
              mean += value;
              std += value*value;
            }

        mean /= (count + 1e-30);
        std /=  (count + 1e-30);

        std = std - mean *mean;

        if (std <= 0)
          std = 0;
        value = mean/sqrt(std);

        MRIFvox(mri_snr,x,y,z) = value;
        //bin_no = nint((float)value/(float)bin_size);
        //if (bin_no >= nbins) bin_no = nbins - 1;
        //h->counts[bin_no]++;
      }

#if 0
  for (num = 0.0f, b = h->nbins - 1; b >= 1; b --) {
    num += h->counts[b];
    if (num > 20000) /* this may make me only use WM points, is it good to
                        use only WM to compute scale of intensity?? */
      break;
  }

  printf("using SNR threshold %2.3f at bin %d\n", h->bins[b], b);

  mean2 = 0;
  std2 = 0;
  count2 = 0;
  for (z=0; z < depth; z++)
    for (y=0; y< height; y++)
      for (x=0; x < width; x++) {
        if (MRIgetVoxVal(mri_in, x, y, z, 0) < noise_threshold) {
          continue;
        }

        value = MRIFvox(mri_snr,x,y,z);

        if (value >= h->bins[b]) {
          count2++;
          mean2 += value;
          std2 += value*value;
        }
      }
#else
  printf("compute mean and std of tp2 volume within masked area\n");
  /* somehow mri_watershed seems to leave some unzero voxels around
  image border, so I will skip image boundaries
  no, that's not a problem of most recent mri_watershed;
  something wrong previously */
  mean2 = 0;
  std2 = 0;
  count2 = 0;
  for (z=0; z < depth; z++)
    for (y=0; y< height; y++)
      for (x=0; x < width; x++) {
        if (MRIgetVoxVal(mri_mask2, x, y, z, 0) <= 1e-30) {
          continue;
        }

        value = MRIgetVoxVal(mri_in, x, y, z, 0);

        count2++;
        mean2 += value;
        std2 += value*value;
      }
#endif

  mean2 /= (count2 + 1e-30);
  std2 /= (count2 + 1e-30);
  std2 = std2 - mean2*mean2;
  if (std2 <= 0)
    printf("warning: negative std for input volume. \n");
  else
    printf("mean and variance for input tp2 volume are %g and %g\n",
           mean2, std2);

  //compute intensity scale
  slope = sqrt(std1/std2);
  offset = mean1 - slope*mean2;

  printf("scale input volume by %g x + %g\n", slope, offset);
  // first change mri_in to FLOAT type
  mri_tmp = MRIchangeType(mri_in, MRI_FLOAT, 0, 1.0, 1);
  MRIfree(&mri_in);
  mri_in = mri_tmp;
  for (z=0; z < depth; z++)
    for (y=0; y< height; y++)
      for (x=0; x < width; x++) {
        value = MRIFvox(mri_in, x, y, z);
        MRIFvox(mri_in, x, y, z) = value*slope + offset;
      }


  //  printf("compute SNR map of tp2 volume\n"); //already done above
  //  mri_snr = MRIalloc(mri_ctrl->width,
  //     mri_ctrl->height, mri_ctrl->depth, MRI_FLOAT) ;

  for (z=0; z < depth; z++)
    for (y=0; y< height; y++)
      for (x=0; x < width; x++) {
        if (MRIgetVoxVal(mri_in, x, y, z, 0) < noise_threshold) {
          //    MRIFvox(mri_snr,x,y,z) = 0;
          continue;
        }

        value = MRIFvox(mri_snr,x,y,z);

        if (value < 20) MRIvox(mri_ctrl, x, y, z) = 0;
        else if (MRIvox(mri_ctrl, x, y, z) > 0) {
          MRIvox(mri_ctrl, x, y, z) = 1;
        }
      }
  if (debug_flag) {
    MRIwrite(mri_snr, "snr.mgz");
    //    MRIwrite(mri_ctrl, "ctrl.mgz");
  }

  // SNR >= 20 seems a good threshold

  // Now use ctrl points to normalize tp2
  printf("normalize tp2...\n");
  mri_bias = MRIbuildBiasImage(mri_in, mri_ctrl, NULL, bias_sigma) ;

  for (z = 0 ; z < depth ; z++) {
    for (y = 0 ; y < height ; y++) {
      for (x = 0 ; x < width ; x++) {
        src = MRIgetVoxVal(mri_in, x, y, z, 0) ;
        bias = MRIgetVoxVal(mri_bias, x, y, z, 0) ;
        if (!bias)   /* should never happen */
          norm = (float)src ;
        else
          norm = (float)src * 110.0 / (float)bias ;
        if (norm > 255.0f && mri_out->type == MRI_UCHAR)
          norm = 255.0f ;
        else if (norm < 0.0f && mri_out->type == MRI_UCHAR)
          norm = 0.0f ;
        MRIsetVoxVal(mri_out, x, y, z, 0, norm) ;
      }
    }
  }

  printf("writing normalized volume to %s...\n", argv[2]) ;
  MRIwrite(mri_out, argv[2]);

  MRIfree(&mri_in);
  MRIfree(&mri_bias);
  MRIfree(&mri_out);
  MRIfree(&mri_T1);
  MRIfree(&mri_ctrl);
  MRIfree(&mri_snr);
  //HISTOfree(&h);

  exit(0);

}  /*  end main()  */
Example #5
0
int main(int argc, char *argv[])
{
  char **av;
  MRI *mri_src, *mri_mask, *mri_dst ;
  int nargs, ac, nmask;
  int x, y, z;
  float value;
  MRI_REGION *region;
  LTA          *lta = 0;
  int          transform_type;
  MRI *mri_tmp;

  nargs =
    handle_version_option
    (
      argc, argv,
      "$Id: mri_mask.c,v 1.18 2012/12/07 22:45:50 greve 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 != 4)
  {
    printf("Incorrect number of arguments, argc = %d\n", argc);
    usage(1);
  }

  mri_src = MRIread(argv[1]) ;
  if (!mri_src)
    ErrorExit(ERROR_BADPARM, "%s: could not read source volume %s",
              Progname, argv[1]) ;
  mri_mask = MRIread(argv[2]) ;
  if (!mri_mask)
    ErrorExit(ERROR_BADPARM, "%s: could not read mask volume %s",
              Progname, argv[2]) ;

  if(mri_src->width != mri_mask->width)
  {
    printf("ERROR: dimension mismatch between source and mask\n");
    exit(1);
  }

  printf("DoAbs = %d\n",DoAbs);

  /* Read LTA transform and apply it to mri_mask */
  if (xform_fname != NULL)
  {

    printf("Apply the given LTA xfrom to the mask volume\n");
    // read transform
    transform_type =  TransformFileNameType(xform_fname);

    if (transform_type == MNI_TRANSFORM_TYPE ||
        transform_type == TRANSFORM_ARRAY_TYPE ||
        transform_type == REGISTER_DAT ||
        transform_type == FSLREG_TYPE
       )
    {
      printf("Reading transform ...\n");
      lta = LTAreadEx(xform_fname) ;
      if (!lta)
        ErrorExit(ERROR_NOFILE, "%s: could not read transform file %s",
                  Progname, xform_fname) ;

      if (transform_type == FSLREG_TYPE)
      {
        if (lta_src == 0 || lta_dst == 0)
        {
          fprintf(stderr,
                  "ERROR: fslmat does not have information on "
                  "the src and dst volumes\n");
          fprintf(stderr,
                  "ERROR: you must give options '-lta_src' "
                  "and '-lta_dst' to specify the src and dst volume infos\n");
        }

        LTAmodifySrcDstGeom(lta, lta_src, lta_dst);
        // add src and dst information
        LTAchangeType(lta, LINEAR_VOX_TO_VOX);
      }

      if (lta->xforms[0].src.valid == 0)
      {
        if (lta_src == 0)
        {
          fprintf(stderr,
                  "The transform does not have the valid src volume info.\n");
          fprintf(stderr,
                  "Either you give src volume info by option -lta_src or\n");
          fprintf(stderr,
                  "make the transform to have the valid src info.\n");
          ErrorExit(ERROR_BAD_PARM, "Bailing out...\n");
        }
        else
        {
          LTAmodifySrcDstGeom(lta, lta_src, NULL); // add src information
          //      getVolGeom(lta_src, &lt->src);
        }
      }
      if (lta->xforms[0].dst.valid == 0)
      {
        if (lta_dst == 0)
        {
          fprintf(stderr,
                  "The transform does not have the valid dst volume info.\n");
          fprintf(stderr,
                  "Either you give src volume info by option -lta_dst or\n");
          fprintf(stderr,
                  "make the transform to have the valid dst info.\n");
          fprintf(stderr,
                  "If the dst was average_305, then you can set\n");
          fprintf(stderr,
                  "environmental variable USE_AVERAGE305 true\n");
          fprintf(stderr,
                  "without giving the dst volume for RAS-to-RAS transform.\n");
          ErrorExit(ERROR_BAD_PARM, "Bailing out...\n");
        }
        else
        {
          LTAmodifySrcDstGeom(lta, NULL, lta_dst); // add  dst information
        }
      }
    }
    else
    {
      ErrorExit(ERROR_BADPARM,
                "transform is not of MNI, nor Register.dat, nor FSLMAT type");
    }

    if (invert)
    {
      VOL_GEOM vgtmp;
      LT *lt;
      MATRIX *m_tmp = lta->xforms[0].m_L ;
      lta->xforms[0].m_L = MatrixInverse(lta->xforms[0].m_L, NULL) ;
      MatrixFree(&m_tmp) ;
      lt = &lta->xforms[0];
      if (lt->dst.valid == 0 || lt->src.valid == 0)
      {
        fprintf(stderr,
                "WARNING:**************************************"
                "*************************\n");
        fprintf(stderr,
                "WARNING:dst volume information is invalid.  "
                "Most likely produced wrong inverse.\n");
        fprintf(stderr,
                "WARNING:**************************************"
                "*************************\n");
      }
      copyVolGeom(&lt->dst, &vgtmp);
      copyVolGeom(&lt->src, &lt->dst);
      copyVolGeom(&vgtmp, &lt->src);
    }

    //    LTAchangeType(lta, LINEAR_VOX_TO_VOX);
    mri_tmp =
      MRIalloc(mri_src->width,
               mri_src->height,
               mri_src->depth,
               mri_mask->type) ;
    MRIcopyHeader(mri_src, mri_tmp) ;

    mri_tmp = LTAtransformInterp(mri_mask, mri_tmp, lta, InterpMethod);

    // mri_tmp =
    //MRIlinearTransformInterp
    //  (
    //   mri_mask, mri_tmp, lta->xforms[0].m_L, InterpMethod
    //  );

    MRIfree(&mri_mask);

    mri_mask = mri_tmp;

    if (lta_src)
    {
      MRIfree(&lta_src);
    }
    if (lta_dst)
    {
      MRIfree(&lta_dst);
    }
    if (lta)
    {
      LTAfree(&lta);
    }
  }   /* if (xform_fname != NULL) */

  // Threshold mask
  nmask = 0;
  for (z = 0 ; z <mri_mask->depth ; z++)
  {
    for (y = 0 ; y < mri_mask->height ; y++)
    {
      for (x = 0 ; x < mri_mask->width ; x++)
      {
        value = MRIgetVoxVal(mri_mask, x, y, z, 0);
        if(DoAbs)
        {
          value = fabs(value);
        }
        if(value <= threshold)
        {
          MRIsetVoxVal(mri_mask,x,y,z,0,0);
        }
        else
        {
          nmask ++;
        }
      }
    }
  }
  printf("Found %d voxels in mask (pct=%6.2f)\n",nmask,
	 100.0*nmask/(mri_mask->width*mri_mask->height*mri_mask->depth));

  if(DoBB){
    printf("Computing bounding box, npad = %d\n",nPadBB);
    region = REGIONgetBoundingBox(mri_mask,nPadBB);
    REGIONprint(stdout, region);
    mri_tmp = MRIextractRegion(mri_mask, NULL, region);
    if(mri_tmp == NULL) exit(1);
    MRIfree(&mri_mask);
    mri_mask = mri_tmp;
    mri_tmp = MRIextractRegion(mri_src, NULL, region);
    if(mri_tmp == NULL) exit(1);
    MRIfree(&mri_src);
    mri_src = mri_tmp;
  }

  int mask=0;
  float out_val=0;
  if (do_transfer)
  {
    mask = (int)transfer_val;
    out_val = transfer_val;
  }
  mri_dst = MRImask(mri_src, mri_mask, NULL, mask, out_val) ;
  if (!mri_dst)
  {
    ErrorExit(Gerror, "%s: stripping failed", Progname) ;
  }

  if (keep_mask_deletion_edits)
  {
    mri_dst = MRImask(mri_dst, mri_mask, NULL, 1, 1) ; // keep voxels = 1
    if (!mri_dst)
      ErrorExit(Gerror, "%s: stripping failed on keep_mask_deletion_edits",
                Progname) ;
  }

  printf("Writing masked volume to %s...", argv[3]) ;
  MRIwrite(mri_dst, argv[3]);
  printf("done.\n") ;

  MRIfree(&mri_src);
  MRIfree(&mri_mask);
  MRIfree(&mri_dst);

  exit(0);

}  /*  end main()  */