-------------------------------------------
Standard tcl script: annot2roi.tcl
-------------------------------------------

Overview

This script resamples MGH style surface region
annotations files (*.annot) and can then generate
3D ROIs from them, for either a single-subject
scan or for fsaverage.

The primary input is an MGH-style annotation file
on the fsaverage subject, selected from the
dropdown in $SUBJECTS_DIR/fsaverage/labels.

The first step (skipped if subject is fsaverage)
is to sample the fsaverage annotation onto an
individual subject's surface using mri_surf2surf.
The resampled annotation is saved in the
subject's "label" subdirectory in $SUBJECTS_DIR.

The second, optional step is to generate AFNI
BRIKs containing 3D ROIs for each region in the
annotation at the resolution of the current
individual subject functional scan (and aligned
with it), along with an all-regions-in-one ROI
BRIK.  These signed short (2-byte) BRIKs will
contain the sequential integer region id numbers
taken from the annotation, which can also be
found in the corresponding ASCII file in:
$SUBJECTS_DIR/fsaverage/scripts/<annotation_infix>.ctab
When the subject is fsaverage, the ROIs will be
generated at 256^3, 1mm^3 resolution of the
$SUBJECTS_DIR/fsaverage/mri/orig.mgz file (rather
than at a typically lesser functional volume
resolution).

The ROI BRIK files are saved to the current
functional scan dir for single subjects, and to a
pseudo functional scandir for fsaverage.  For
fsaverage 3D ROIs, first use csurf -> File -> New
Functional to create an empty 'functional'
session in $FUNCTIONALS_DIR named
"fsaverage-3D-ROIs" before running the script.

For an individual subject, two additional
required inputs are a functional scan (in order
to determine ROI BRIK voxel size) and a
register.dat file (to align the data to the
individual subject's surface annotation).  If
used interactively, select the scan from the
"scandir:" dropdown in csurf before starting
tksurfer.

For fsaverage, the ROI BRIKs will be generated as
mentioned at the 256^3 1mm^3 resolution of the
$SUBJECTS_DIR/fsaverage/mri/orig.mgz file (so an
identity matrix register.dat will be used).

Other sub-options for the second ROI-making step
are to search along the surface normal (in either
mm or fraction of distance to local pial
surface).  Any functional voxel (or fsaverage
1mm^3 pseudo functional voxel) intersected by the
normal search will be included in the 3D ROI.
Region boundaries can also be optionally eroded
to make more focal ROIs.

Another sub-option is to fill any remaining
holes, which can be generated when searches
continue above the pial surface (e.g., where
surface normals can diverge on gyral crowns).

Finally, if both hemispheres have been processed,
the right and left hemisphere ROI BRIKs will
automatically be merged in a single BRIK without
an lh- or rh- prefix.

If subject is fsaverage, the right/left merged
all-in-one ROIs BRIK will be auto-converted to an
MGH compatible (single-hemisphere) 1x1x1mm
parcellation file that will saved to the
fsaverage mri subdir:

  $SUBJECTS_DIR/fsaverage/mri/<annotation_infix>.mgz

Interactive use, details

When used interactively (via the "GO" button near
the upper left "tcl:" dropdown) the script first
makes a pop-up.  The currently available
fsaverage .annot files are loaded into the
"annot:" dropdown (default CsurfMaps1).

If "make_3D_AFNI_ROIs_flag" is ticked, the bottom
part of the pop-up panel is enabled and 3D AFNI
ROI files are also generated at the resolution of
the current functional scan.  The additional
parameters below "make_3D_AFNI_ROIs_flag" control
sampling along the surface normal and final
touch-up 3D filling of the ROI(s).

When single-subject-specific 3D ROIs are
generated, the script should be run from a
functional scan dir, because resampling from an
annotation region on the surface to a 3D ROI
requires a functional scan (to determine voxel
size of output 3D ROI files), and a standard
register.dat file (to map 3D voxel indices to 3D
surface vertex coordinates).  To automatically
load the desired scandir, select a session and
a scandir in csurf before starting tksurfer.

To make fsaverage 3D ROIs, run the script from a
functional session named "fsaverage-3D-ROIs" (a
pseudofunct scan and an identity-matrix
register.dat will be auto-created).

The "erodesteps" entry (default=0=OFF) allows
eroding a given number of rings of single
vertices from the edges of the surface ROIs
before generating the 3D AFNI ROIs to make them
more focal.

Clicking the "normsampsearchflag" tickbox enables
additional entries on the popup for searching
along the local surface normal.  These can be
further toggled between search distance in mm vs.
search distance in fraction of cortical thickness
(dist to pial surface) using the "normfracflag"
tickbox.

If regions overlap during the making of the
all-in-one 3D AFNI ROI file (as a result of
intersecting normal searches), the later region
(in the annotation file) wins.

By default, $savesingleROIbriksflag is 0 (OFF),
so the BRIKs generated for each individual region
(e.g., a total of 7G for HCP-MMP1!) will be
deleted after they have been incorporated into
the ALL_ANNOT_ROIs BRIK (flag mainly useful for
debugging).

Finally, ticking "fill3Dholesflag" enables
running the C/tcl function fill_idnumbrik_holes
on the output ROI BRIK(s) (overwrites input).  If
a voxel has a zero for its region id (i.e.,
region "Unknown"), the 26 voxels surrounding that
voxel are examined to determine which region id
is most commonly represented (not counting id=0).
If the fraction of any immediately surrounding
non-zero neighbor ids exceeds the setting of
$neighfracthres (default=0.8), the voxel will be
filled.  Any voxel with a non-zero region id will
not be touched.  The conservative default setting
of $neighfracthresh = 0.8 requires 80% of the
surrounding 26 voxels to be filled to fill an
empty voxel.  Decrease $neighfracthresh for more
aggressive hole-filling.  The most conservative
setting of $neighfracthresh is 1.0, which
requires every surrounding voxel to be filled to
fill a central hole.

When all parameters are set, click "RUN SCRIPT".
It takes several sec to generate the (temp) ROI
BRIK for each region, and several sec to fill
holes in the completed ALL_ANNOT_ROIs BRIK
(assuming you are not saving individual region
BRIKs).

The ROI BRIKs can be viewed in AFNI as an overlay
(over a functional MRI underlay for a single
subject or over orig+orig.BRIK for fsaverage).
Once both hemispheres have been processed, the
BRIKs with single hemisphere ROIs will be merged
into one ROI BRIK without a rh- or lh- prefix,
using the C/tcl tksurfer function:

  merge_indum_briks <lh-in.BRIK> <rh-in.BRIK> <out.BRIK>

which will merge files that look like this:

  lh-ALL_ANNOT_ROIs-fr=0.0to1.1+orig.BRIK
  rh-ALL_ANNOT_ROIs-fr=0.0to1.1+orig.BRIK

into a single BRIK without an lh- or rh- prefix:

  ALL_ANNOT_ROIs-fr=0.0to1.1+orig.BRIK

This function expects short (2-byte) BRIKs
containing sequential idnum integers, each
starting with region=0=Unknown.  The first BRIK
(usu. LH) will be read in, and then any non-zero
voxels in the second BRIK (usu. RH) will replace
equivalent voxels in the first BRIK.  The idnums
for the second (RH) BRIK (which before
modification start with region idnum=1) will each
be incremented by the total number of regions in
the first (LH) BRIK (including 0=Unkonwn) so that
left and right region idnums do not overlap, are
sequential, and so that there is only one
"Unknown" region (same for both hemispheres).

If the subject is fsaverage, the all-in-one 3D
ROI BRIK will be auto-converted to an MGH *.mgz
file that will be saved in:

  $SUBJECTS_DIR)/fsaverage/mri/$annotinfix.mgz

This can be viewed in tkmedit by reading it in as
a second image, using the "im2:" dropdown at the
bottom middle (it will be auto-detected as an
overlay).  If the annotation file has a
non-standard name, you may have to untick and
re-tick "la" (show second image as a transparent
overlay instead of second blink comparison image)
just to the right of the "im2:" entry.

The 3D (tkmedit) display colors for each named
region in tkmedit will be read out of one of the
following ASCII color table files, by looking at
the prefix of the original annotation file that
was selected:

  $CSURF_DIR/lib/lut/FreeSurferColorLUT.txt (incl's lh/rh)
  $CSURF_DIR/lib/lut/CsurfColorLUT-both.txt
  $CSURF_DIR/lib/lut/HCP-MMP1ColorLUT-both.txt

The utilities for generating these files are
described below after explaining a number of
conflicting color table conventions.

ASCII color tables vs. annotation color tables

There are a number of different conventions for
the ASCII color tables that map region idnums to
region names and colors in 2D and 3D displays
that also differ from the conventions used in MGH
annotation files ($hemi-$parcellation_name.annot).

Standard single-hemisphere MGH annotation files
have sequential region idnums starting with
region 0=Unknown with no gaps.  Since
surface-based analysis is typically done
separately for each hemisphere, region idnums in
left and right hemisphere *.annot files can/will
overlap (even though the region names in the
annotation itself may be hemisphere-specific).
This is because any gaps in the ASCII color table
file used to direct construction of an annotation
are squeezed out in the output annotation file
(csurf tksurfer write_mgh_annot originally
retained the gap-containing idnums taken from the
master color table file, but had to change to
sequential because the gapped *.annot files
caused crashes in some MGH freesurfer utilities).

This means that the mapping between region idnums
and region names in the master ASCII color table
file are NOT preserved in the annotation file.
To avoid ambiguity, when any annotation file is
read (read_mgh_annot), its internal sequential
idnum color table is written out to the file:

  $SUBJECTS_DIR/$subject/scripts/$annotprefix.ctab

By contrast with hemisphere-specific, sequential
color tables in annotation files, the standard
master ASCII FreeSurfer color table:

  $CSURF_DIR/lib/lut/FreeSurferColorLUT.txt

contains a large number of named regions for both
hemispheres mapped to idnums that are not
required to be sequential.  The idnums begin with
region 0 (Unknown) and in FreeSurfer5.3 go up to
region 14175 (wm_rh_S_temporal_transverse).  Most
(but not all) of these regions have
hemisphere-specific infixes (with several
different naming conventions) and unique RGB
colors.  Finally, the regions are not always
sorted numerically by idnum in the file.

The CsurfMaps1 parcellation ASCII color table
file (used to generate rh/lh-CsurfMaps1.annot):

  $CSURF_DIR/lib/lut/CsurfColorLUT.txt

is similar to FreeSurferColorLUT.txt in that it
has gaps.  But it contain no hemisphere-specific
names (e.g., MT_upper), and is sorted
numerically.

Finally, the HCP parcellation was resampled to
fsaverage and used to generate left and right
hemisphere MGH annotation files.  The sequential
annotation color tables generated upon reading
the annotation for each hemisphere in csurf
tksurfer are found here:

  $CSURF_DIR/lib/lut/lh-HCP-MMP1ColorLUT.txt	
  $CSURF_DIR/lib/lut/rh-HCP-MMP1ColorLUT.txt	

The HCP parcellation has distinct left and right
hemisphere area names with a "L_" or "R_" prefix,
but the left and right hemisphere idnums overlap.

Generating both-hemisphere color tables for 3D display

To generate color tables containing unique left
and right hemisphere names, (sequential) idnums,
and unique region colors for displaying and using
3D ROIs, there is a standalone tcl script:

  $CSURF_DIR/bin/noarch/mkbothlut

that takes the ASCII color tables above as input
and generates a new color table with a "-both"
infix, as mentioned above:

  $CSURF_DIR/lib/lut/CsurfColorLUT-both.txt
  $CSURF_DIR/lib/lut/HCP-MMP1ColorLUT-both.txt

In the case of CsurfMaps1, the left-plus-right
color table is made by pre-appending "L_" and
"R_" to make left and right hemisphere versions
of the region names, adding the max left
hemisphere idnum to all right hemisphere areas,
and incrementing the red color by 1 (to make
similar but L/R unique colors for each bilateral
region).

In the case of HCP-MMP1, the left-plus-right
color table is made by keeping the already
hemisphere-specific names, adding the max left
hemisphere idnum to all right hemisphere areas,
and keeping the already unique-but-similar RGB
region colors.

Complete example for single subject ROIs

Starting with a functional scan (e.g., an AFNI
BRIK in /tmp), here is a minimal outline of what
is required starting with raw functional data:

  (1) create an empty functional dir:

    File -> New Functional

  (2) import at least one functional scan into it:

    SessionTools -> File Make Scandirs, Find/Copy Raw
    click DELETE LAST SCANDIR
       [just "alignscan" left, rename to "functscan"]
    click FIND
       [locate functional scan in /tmp]
    click MAKE SCANDIRS
    click STRIP/COPY RAW

  (3) align that functional scan with recon-all struct

    SessionTools -> Setup Align/Funct Scans
    click "Funct Scan Dir" (top)
    click READ HEADER
    click INIT/FLIP to initialize transform
    click FUNCT=>SUBJ
       [do manual alignment]
       tkregister -> click SAVE REG
    Save/Close

  (4) run annot2roi.tcl

    csurf -> SURFACE
    select annot2roi.tcl from tksurfer "tcl:" dropdown
    ["rawdata" should be preset to "functscan"]
    GO

See csurf -> Help -> Retinotopy HOWTO for hints
on manual alignment.

Tcl script equivalent

Here is an example set of tcl commands required
(example scandir is "polar1"):

### re-sample fsaverage annotation to this subj
set annotinfix HCP-MMP1
set fsavgannot \
$env(SUBJECTS_DIR)/fsaverage/label/$hemi.$annotinfix.annot
set subjannot \
  $env(SUBJECTS_DIR)/$subject/label/$hemi.$annotinfix.annot
set cmd "mri_surf2surf \
  --srcsubject fsaverage \
  --trgsubject $subject \
  --hemi $hemi \
  --mapmethod nnf \
  --sval-annot $fsavgannot \
  --tval $subjannot"
exec $cmd
### convert subj-specific annot to 3D ROI's
setfile regdat */polar1/register.dat		;# setfile expands abbrev
setfile rawdata */polar1/polar1+orig.BRIK
setfile anlabel $subjannot
set erodesteps 0
read_mgh_annot
for {set i 0} {$i < $erodesteps} {incr i} {
  erode_annot
}
# load sample surf (speeds write_annotcols_timecourses_stats)
set insurfCURR $insurf
setfile insurf $hemi.orig
read_binary_surface
# set sample parms
set normdsampsearchflag 1			;# turn on normal search
set normdfracflag 1			;# use fractional dist (vs. mm)
set normdfracsamp 0.0			;# frac thickness search begin
set normdfracmax  1.0			;# frac thickness search end
# make indiv plus all-in-one ROI BRIKs
write_annotcols_timecourses_stats 3     ;# 3=3D-ROIs
# restore init surface
setfile insurf $insurfCURR
read_binary_surface
# HOWTO fillholes:
#   fill_idnumbrik_holes <pref+orig.BRIK> <neighfracthresh[OK:0-1]>
# HOWTO merge L/R and convert to mgz:
#   merge_idnum_briks <lh-name+orig.BRIK> <rh-name+orig.BRIK> <name+orig.BRIK>
#   shortcorbrik2intmgz <name+orig.BRIK> <name.mgz>
