------------------------------------------
 tkegister -- interactively blink-register two volumes
------------------------------------------
Register reads two series of images, a TARGET set
(e.g., orig.mgz) and a MOVEABLE set (e.g., a
volume from an fMRI series), and displays them in
coronal, sagittal, horizontal, planes.  The
images in the the TARGET buffer are fixed while
the images in the MOVEABLE buffer can be modified
with a linear transformation--which includes
rotation, translation, and stretching.

Volume to Surface

The primary goal of register is to generate a 4x4
linear transformation matrix (register.dat) that
can be used by other programs (e.g., paint,
tksurfer) to associate 3D statistics made from
the MOVEABLE image to individual vertices of a 2D
surface made from the TARGET image set.

The register.dat matrix can also be used by
tksurfer to extract raw functional data
timecourses (ASCII) given a surface point, or a
surface label (see R-click help for the "T"
button on the "label:" line).

Volume to Volume

The register.dat matrix can be used to overlay
stats from the MOVEABLE image set onto the TARGET
image set in 3D, using tkmedit (csurf -> View
Functional Data -> VOLUME-STATS).

Finally, tkregister can be used for quick and
dirty hand registration of one *.mgz to another
(e.g., tkregister orig1.mgz orig2.mgz).

Register.dat Matrix

The transformation matrix that is generated
transforms a point in the TARGET data set (e.g.,
a T1 image from which the orig.mgz surface was
made) to a point in the MOVEABLE data set (e.g.,
a functional MRI scan, corner based voxel
coordinates).

Transformations (rotations, translations,
stretchings) are applied to the MOVEABLE data set
relative to its current view/transformation.
They will be immediately visible in other planes
or other slices of the MOVEABLE data set.
Rotations take place around the last left-clicked
point.

Blink comparison

The image sets are compared to each other by
pressing the COMPARE button.  Once the
registration is satisfactory, it can be saved
with SAVE REG (asks before overwrite).  To go
back to the original registration, quit without
saving and restart, or use READ REG before saving
(in extended F3 interface).

Usage from a MacOS 10.11+ shell script

N.B.: on MacOS 10.11+, the environment variable
DYLD_LIBRARY_PATH is *not* passed into a shell
script, which will prevent tkregister from seeing
the csurf X11 tcl/tk libraries.  To use
tkregister in a MacOS 10.11+ shell script,
include the following line before the first call
to tkregister:

csh/tcsh:
  setenv DYLD_LIBRARY_PATH $CSURF_LIBRARY_PATH

sh/bash:
  export DYLD_LIBRARY_PATH=$CSURF_LIBRARY_PATH

-------------------------------------------
 Keyboard shortcuts -- for both image,tk windows
-------------------------------------------
Single key

  # interface size
  F1 -- small interface    (Mac=fn-F2)
  F2 -- standard interface (Mac=fn-F2)
  F3 -- large interface    (Mac=fn-F3)

  # move slice
  R/L arrow   -- slice up/down

  # COMPARE button
  0 [zero]    -- swap target and moveable

  # target (struct) brightness
  Mod-plus   -- target brightness up
  Mod-minus  -- target brigthness down

  # target (struct)  contrast
  Mod-asterisk -- target contrast up (times)
  Mod-slash    -- target contrast down (divide)

  # moveable (EPI) brightness
  up arrow -- moveable brightness up
  dn arrow -- moveable brightness down

  # fmid (basic threshold)
  Mod-b  -- toggle blur moveable
  Mod-i  -- toggle invert moveable

  # SEND/GOTO
  Mod-f  -- SEND (forward) point
  Mod-g  -- GOTO point
-------------------------------------------

Alignment Strategies

There are two basic alignment strategies for
functional data.

 Functional Scan => Surf Scan
 Functional Scan => Alignment Scan => Surf Scan

In the first, a single repetition from the
functional data set (typically t=0) is directly
registered to the high-resolution structurals
that were used to reconstruct the cortical
surface.  The difficulty with this is that the
functional contrast is low and reversed relative
to the hi-res T1's.

In the second strategy, a T1-weighted alignment
scan taken in the same plane as the functional
scans is first aligned to the hi-res structural
used to make the surface.  The resulting
transformation matrix is then copied onto the
register.dat file in the functional scan
directory.  A direct Functional => Subject
register can then be run to touch up the
alignment (or add shear--see below).

Aligning Two High-Resolution Data Sets

Register can also be used to manually align two
high resolution data sets prior to averaging, or
to quickly visually compare them:

  tkregister scan1.mgz scan2.mgz

There are many automatic algorithms to do this.
Register can be useful when the two data sets
were collected on different days with different
coverage or contrast, or with markedly different
neck, jaw, and scalp position.

Display Parameters

The default setting for "contrast" (12.0 -- up
for more contrast) increases contrast of the raw
data.  The default setting for "midpoint" (0.35,
meaning midpoint is 35% of maximum, so turn it
down to make images lighter), is designed for
images  normalized using mri_normalize.  These
affect both TARGET and MOVEABLE.

The "fmov" field adjusts the brightness of just
the MOVEABLE images, which should be adjusted to
be approximately the same as the TARGET image.

The "masktarg" button masks out the part of the
TARGET images that extend beyond the edge of the
MOVEABLE images volume.  This is typically used
for fine adjustments on data sets collected with
a surface coil where the MOVEABLE functional
images cover only a part of the brain and the
size change during COMPARE is distracting.

The unmarked entry to the left of the TARGET
button controls the rate of blinking between
TARGET and MOVEABLE when the COMPARE button is
continuously depressed (in milliseconds, minimum
is one frame per dataset, about 15 msec).

The "blurmov" check button does a 3D nearest
neighbor blur of the MOVEABLE data set at the
typically subsampled pixel resolution of the
TARGET dataset.  This takes effect with the next
COMPARE.  It will be recalculated on changing the
slice number or plane.

The "invertmov" check button inverts the contrast
of the MOVEABLE data set.  For typical EPI data,
this will make it easier to visually compare the
data sets.

The SAGMIRR button flips the chirality of the
MOVEABLE data set.  It is easiest to see the
effect of this in the HORIZONTAL or CORONAL
planes.

Tips

If the data sets are roughly aligned, a good
strategy is to adjust the MOVEABLE in coronal
view, change to sagittal and re-adjust, change to
horizontal and re-adjust, and so on -- that is,
change planes often.

It may be difficult to guess how to transform the
MOVEABLE data set if it is oriented very
differently than the TARGET data set (e.g., the
TARGET image is coronal but the MOVEABLE image
looks like a sideways horizontal slice).  A
simple strategy here is to transform the MOVEABLE
by rotating 90 degrees around a center point, and
then change to another plane.  If the MOVEABLE
still appears to be in the wrong plane, rotate 90
degrees again and change plane again.  Eventually
you will only need an in-plane rotation to
roughly align the data sets (N.B.: you can
quickly rotate 90 deg by 3 ctrl-clicks in the
left or right trough of the rotate slider).

To get a shearing transformation, use a rotation
combined with stretching.  For example, rotate 30
deg, stretch vertically, rotate back 30 deg (like
an SVD!), and finally, shrink vertically.  Don't
resort to stretching/shrinking until the data
sets are reasonably well aligned.

Format of register.dat (8 or 9 lines, ASCII)

 arthur   [name in subjects database]
 3.0      [pixel size (mm) of MOVEABLE]
 4.0      [slice thickness (mm) of MOVEABLE]
 0.2      [starting brightness of MOVEABLE]
   [transformation matrix]
 9.9915e-01  2.9973e-02 -4.6041e-02  6.5897e-02
 -5.7313e-03 -7.7659e-01 -6.2997e-01 -3.5452e+01
 5.4680e-02 -6.2928e-01  7.7525e-01 -6.6141e+00
 0.0000e+00  0.0000e+00  0.0000e+00  1.0000e+00
 round

Since the pixel size is included in the file, the
homogeneous 4x4 matrix can be directly used for
data sets with different pixel sizes.

How register.dat is used by paint.c (and others)

The linear registration matrix in register.dat
transforms a 3D surface coordinate vector to a 3D
functional data coordinate vector.  That is:

  Ax = b

where A is the 4x4 transformation matrix, x is
the surface coordinates vector, and b is the
functional data coordinates vector.

The original version of tkregister and paint
truncated the resulting floating point
coordinates of b before nearest neighbor sampling
of the moveable volume.

Newer MGH tkregister2 and bbregister round before
nearest neighbor sampling.  A register.dat file
of this kind will contain "round" on the line
following the transformation matrix (as above).

These two methods generate slightly different
transformation matrices in register.dat (they
differ by half a voxel in all 3 directions).

Csurf tkregister/paint/tkmedit/tksurfer can
automatically properly display and use *either*
kind of register.dat file.  That is, there will
be *no* off-by-half error in the surface data in
either case.  The "round" case is the default.

To manually convert between these two types of
sampling, use the F3 interface to change the
setting of the "round" checkbutton (initial state
taken from the current register.dat) adjust the
registration, and then SAVE REG.

-------------------------------------------------
 Outline C-code showing how register.dat is used
-------------------------------------------------

******************************************************/
/* paint.c: sample 3D data -> surface vtx list */

#include <math.h>

/* functional volume */
int nslices=24;     /* funct data */
int ydim=64;        /* funct data */
int xdim=64;        /* funct data */
int usethickness=1; /* use thickness (in curv)*/
float ***fim;       /* functimg vol (malloc) */
float distmm=2.0;   /* mm/frac along normal */
float distfrac=0.8; /* mm/frac along normal */

/* obtained from register.dat */
float ps;         /* inplane   register.dat:2 */
float st;         /* thickness register.dat:3 */
float tmat[4][4]; /*[row][col] register.dat:5-8*/
int roundregflag; /* sample meth: 0=trunc,1=round */

/* from reading surface */
int nvertices=130000;

typedef struct vertex_type_
{
   float  x, y, z;     /* position */
   float  nx, ny, nz;  /* curr normal */
   float  val;         /* scalar data */
   float  curv;        /* scalar data */
   /* etc */
} vertex_type;

vertex_type *vertices;

void paint_surface(void)
{
  int     k;
  int     i, j, imnr;
  float   surfx, surfy, surfz;
  float   centx, centy, centz;
  float   x, y, z;
  float   f, fydim=ydim;
  float   dist=0.0;
  vertex_type  *v;

  centx =  ps*xdim/2.0;
  centy = -st*nslices/2.0;
  centz =  ps*ydim/2.0;

  for (k=0; k<nvertices; k++) {
    v = &vertices[k];
    f = 0.0;
    if (usethickness) dist = distfrac * v->curv;
    else              dist = distmm;
    surfx = v->x + dist*v->nx;  /* along normal */
    surfy = v->y + dist*v->ny;
    surfz = v->z + dist*v->nz;
    xform(surfx,surfy,surfz,&x,&y,&z,tmat);
    if (roundregflag) {  /* new round sample */
      imnr = rint((y-centy)/st);
      i = rint(fydim-1.0-(centz-z)/ps);
      j = rint((centx-x)/ps);
    }
    else {  /* old trunc sample */
      imnr = floor((y-centy)/st);
      i = ydim-1-(centz-z)/ps;
      j = (centx-x)/ps;
    }
    if (imnr >= 0 && imnr <= nslices-1 &&
        i    >= 0 && i    <  ydim  &&
        j    >= 0 && j    <  xdim) { /*vtx in vox*/
      f = fim[imnr][ydim-1-i][j];
    }
    v->val = f;
  }
}

void xform(float x1, float y1, float z1,
   float *x2, float *y2, float *z2, float M[4][4])
{
   *x2 = x1*M[0][0]+y1*M[0][1]+z1*M[0][2]+M[0][3];
   *y2 = x1*M[1][0]+y1*M[1][1]+z1*M[1][2]+M[1][3];
   *z2 = x1*M[2][0]+y1*M[2][1]+z1*M[2][2]+M[2][3];
}
******************************************************/

Extended Interface

Several levels of interface are available by
typing the following commands while in the
interface or image window:

[fn]-F1   micro (just rotate/translate)
[fn]-F2   mini  (default, add stretching,
                 SEND/GOTO, blur, invert, mirror)
[fn]-F3   macro (add ALIGN, re-read register.dat,
                 SAVE RGB)

-------------------------------------------
 Standalone Commandline
-------------------------------------------
tkregister can also be run as a standalone
program (type "tkregister" to see full usage).

Here is the basic usage:

  tkregister <fullmovfile> <fulltargfile> req'd-opts...
  tkregister -mkdefault

 Example:

  tkregister \
    /sess/100729MS/image/1-ecc/ecc-vreg+orig.BRIK \
    /subj/martys09/mri/T1.mgz \
    -reps 256 \
    -nslices 26 \
    -imres 64 64 \
    -regdat /sess/100729MS/image/1-ecc/register.dat

However, for quick-and-dirty registration of two
*.mgz data sets, something like this will work
anywhere:

  tkregister orig1.mgz orig2.mgz
