AFNI file: README.realtime
================================================
Realtime AFNI control information: What it needs
================================================
AFNI needs some information about the acquisition in order to properly
construct a dataset from the images. This information is sent to AFNI
as a series of command strings. A sample set of command strings is
given below:
ACQUISITION_TYPE 2D+zt
TR 5.0
XYFOV 240.0 240.0 112.0
ZNUM 16
XYZAXES S-I A-P L-R
DATUM short
XYMATRIX 64 64
The commands can be given in any order. Each command takes up a single
line of input (i.e., commands are separated by the '\n' character in the
input buffer, and the whole set of commands is terminated by the usual '\0').
Each command line has one or more arguments. The full list of possible
command strings and their arguments is:
ACQUISITION_TYPE arg
This command tells AFNI how the image data will be formatted:
arg = 2D+z -> a single 3D volume, one slice at a time
2D+zt -> multiple 3D volumes, one slice at a time [the default]
3D -> a single 3D volume, all at once
3D+t -> multiple 3D volumes, one full volume at a time
*This command is not required, since there is a default.
NAME arg
or
PREFIX arg
This command tells AFNI what name to use for the new dataset.
*It is not required, since AFNI will generate a name if none is given.
TR arg
This command tells AFNI what the imaging TR is, in seconds. The default
value, if this command is not given, is 1.0.
*It is recommended that this command be used, so that the dataset has
the correct header information. But this command is not required.
ZDELTA dz
This command tells AFNI the slice thickness, in mm.
*This command, or the next one, MUST be used, so that the correct
size of the dataset along the z-axis size known.
XYFOV xx yy [zz]
This command tells AFNI the size of the images, in mm. The first
value ('xx') is the x-axis dimension, and the second value ('yy') is
the y-axis dimension. If the third value ('zz') is present, then it
is the z-axis dimension (slab thickness of all slices).
*This command MUST be used to at least to give the sizes of the dataset
along the x- and y-axes. If 'zz' is not given, then the ZDELTA command
is also required.
*If 'yy'==0, then it is taken to be the same as 'xx' (square images).
ZFIRST zz[d]
Specifies the location of the first slice, along the z-axis, in mm.
The value 'zz' gives the offset. The optional code 'd' gives the
direction that distance 'zz' applies. The values allowed for the
single character 'd' are
I = inferior
S = superior
A = anterior
P = posterior
R = right
L = left
*This command is optional - if not given, then the volume will be
centered about z=0 (which is what always happens for the x- and
y-axes). If the direction code 'd' is given, then it must agree
with the sense of the z-axis given in the XYZAXES command.
When more than one dataset is being acquired in a scanning session,
then getting ZFIRST correct is important so that the AFNI datasets
will be properly positioned relative to each other (e.g., so you
can overlay SPGR and EPI data correctly).
XYZFIRST xx[d] yy[d] zz[d]
This new option (10 Dec 2002) lets you set the offsets of the dataset
volume on all 3 axes. It is very similar to ZFIRST above, but you
give values for all axes. For example:
XYZAXES S-I A-P L-R
XYZFIRST 30 20A 50R
sets the x-origin to 30S (since no direction code was given for x),
the y-origin to 20A, and
the z-origin to 50R. Since the z-axis is L-R and starts in the
R hemisphere, these sagittal slices are all in the R hemisphere. If
the 'R' code had been left off the '50R', then the z-origin would have
been set to 50L. Note that the origin is the CENTER of the first voxel.
*This command is optional. If it is given along with ZFIRST (why?), then
whichever one comes last wins (for the z-axis).
XYMATRIX nx ny [nz]
Specifies the size of the images to come, in pixels:
nx = number of pixels along x-axis
ny = number of pixels along y-axis
nz = number of pixels along z-axis (optional here)
*This command is required. If 'nz' is not given here, then it must
be given using the ZNUM command.
ZNUM nz
Specifies the number of pixels along the z-axis (slice direction).
*This value must be given, either with XYMATRIX or ZNUM.
*Note that AFNI cannot handle single-slice datasets!
DATUM typ
Specifies the type of data in the images:
typ = short -> 16 bit signed integers [the default]
float -> 32 bit IEEE floats
byte -> 8 bit unsigned integers
complex -> 64 bit IEEE complex values (real/imag pairs)
*This command is not required, as long as the data are really shorts.
The amount of data read for each image will be determined by this
command, the XYMATRIX dimensions, and the ACQUISITION_TYPE (whether
2D or 3D data is being sent).
BYTEORDER order
This new command string (27 Jun 2003) tells the realtime plugin the
byte order (endian) that the image data is in. If the byte order is
different from that of the machine afni is running on, the realtime
plugin will perform byte swapping on the images as they are read in.
order = LSB_FIRST -> least significant byte first (little endian)
= MSB_FIRST -> most significant byte first (big endian)
*This command is not required. Without this command, image bytes will
not be swapped.
*This command works for DATUM type of short, int, float or complex.
ZORDER arg
Specifies the order in which the slices will be read.
arg = alt -> alternating order (e.g., slices are presented
to AFNI in order 1 3 5 7 9 2 4 6 8, when nz=9).
= seq -> sequential order (e.g., slices are presented
to AFNI in order 1 2 3 4 5 6 7 8 9, when nz=9).
*This command is not required, since 'alt' is the default. It will
be ignored if a 3D ACQUISITION_TYPE is used.
XYZAXES xcode ycode zcode
Specifies the orientation of the 3D volume data being sent to AFNI.
Each of the 3 codes specifies one axis orientation, along which the
corresponding pixel coordinate increases. The possible codes are:
I-S (or IS) -> inferior-to-superior
S-I (or SI) -> superior-to-inferior
A-P (or AP) -> anterior-to-posterior
P-A (or PA) -> posterior-to-anterior
R-L (or RL) -> right-to-left
L-R (or LR) -> left-to-right
For example, "XYZAXES S-I A-P L-R" specifies a sagittal set of slices,
with the slice acquisition order being left-to-right. (In this example,
if ZFIRST is used, the 'd' code in that command must be either 'L' or 'R'.)
The 3 different axes codes must point in different spatial directions
(e.g., you can't say "XYZAXES S-I A-P I-S").
*This command is required, so that AFNI knows the orientation of the
slices in space.
GRAPH_XRANGE x_range
Specifies the bounding range of the horizontal axis on the 3D motion
correction graph window (which is measured in repetitions). The actual
range will be [0, x_range]. E.g. "GRAPH_XRANGE 120".
GRAPH_YRANGE y_range
Specifies the bounding range of the vertical axis on the 3D motion
correction graph window (the units will vary). The actual range will
be [-y_range, +y_range]. E.g. "GRAPH_YRANGE 2.3".
If both GRAPH_XRANGE and GRAPH_YRANGE are given, then no final (scaled)
motion correction graph will appear.
GRAPH_EXPR expression
Allows the user to replace the 6 default 3D motion correction graphs with a
single graph, where the 'expression' is evaluated at each step based on the
6 motion parameters at that step. The variables 'a' through 'f' are used
to represent dx, dy, dz, roll, pitch and yaw, respectively.
E.g. GRAPH_EXPR sqrt((a*a+b*b+c*c+d*d+e*e+f*f)/6)
See '3dcalc -help' for more information on expressions.
** Note that spaces should NOT be used in the expression.
NUM_CHAN nc
Specifies the number of independent image "channels" that will be
sent to AFNI. Each channel goes into a separate dataset. Channel
images are interleaved; for example, if nc=3, then
image #1 -> datataset #1
image #2 -> datataset #2
image #3 -> datataset #3
image #4 -> datataset #1
image #5 -> datataset #2
et cetera.
For 2D acquisitions, each slice is one "image" in the list above.
For 3D acquisitions, each volume is one "image".
All channels will have the same datum type, the same xyz dimensions,
and so on.
* This command is optional, since the default value of nc is 1.
DRIVE_AFNI command
You can also pass commands to control AFNI (e.g., open windows) in the
image prolog. See README.driver for the list of command strings.
More than one DRIVE_AFNI command can be used in the realtime prolog.
* This command is optional.
DRIVE_WAIT command
This command works exactly like DRIVE_AFNI, except that the real-time
plugin waits for the next complete volume to execute the command. The
purpose is to execute the command after the relevant data has arrived.
NOTE text to attach to dataset
This command lets you attach text notes to the dataset(s) being created
by the realtime plugin. All the text after "NOTE ", up to (not including)
the next '\n', will be attached as a text note. More than one NOTE can
be given. If you want to send a multiline note, then you have to convert
the '\n' characters in the note text to '\a' or '\f' characters (ASCII
7 and 12 (decimal), respectively). Any '\a' or '\f' characters in the
text will be converted to '\n' characters before the note is processed.
OBLIQUE_XFORM m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 m13 m14 m15
This command is to send an IJK_TO_DICOM_REAL oblique transformation
matrix, consisting of 16 floats in row-major order, to be applied to
all resulting datasets (i.e. stored in the daxes->ijk_to_dicom_real
structure).
==============================================
How AFNI reads realtime command and image data
==============================================
This stuff is all carried out in the image source program (e.g., Rx_xpi).
Most of the current source code is in file ep_afni.c, for operation at
the MCW Bruker 3 Tesla scanner. Also see the sample program rtfeedme.c.
Step 1: The image source program opens a TCP/IP socket to the system
running AFNI, on port 7954 - the realtime AFNI plugin is listening
there. AFNI checks if the host that opened the connection is on
its "trust list". When this socket is ready then ...
Step 2: The image source program tells AFNI from where it should really
get its data. A control string is written to the 7954 socket.
The first line of this control string specifies whether to use
a TCP/IP socket for the data channel, or to use shared memory.
If there is a second line on the control string, then it is the
name of an "info program" that AFNI should run to get the command
information described above. At the old MCW Bruker 3 Tesla scanner,
these commands are generated by the program 3T_toafni.c, which
runs a script on the 3T60 console computer to get values from
ParaVision, and then takes that information and formats most of
the control commands for realtime AFNI. In the ep_afni.c
routines, the name of the info program is stored in string variable
AFNI_infocom, which is initialized in ep_afni.h to be "3T_toafni".
If this string is NOT sent, then AFNI will try to get the image
metadata from the image data stream (cf. Step 3, below).
When AFNI reads the control string from the 7954 socket, it then
closes down the 7954 socket and opens the data channel (TCP/IP or
shared memory) that the first line of the control string specified.
If the second line of the control string specified an info program
to get the command strings, this program will not be run until the
first image data arrives at AFNI.
There are 2 reasons for separating the data channel from the control
socket. First, if the image source program is one the same system
as AFNI, then shared memory can be used for the data channel.
However, I wanted AFNI to be able to be on a separate system from
the image source program, so I also wanted to allow for transport of
image data via a socket. At the beginning, AFNI doesn't know where
it will get the data from, so the initial connection must be via a
socket, but later it might want to switch to shared memory. Second,
in principal AFNI could acquire data from more than one image source
at a time. This is not yet implemented, but keeping the initial
control socket separated from the actual data stream makes this a
possibility. (The control socket is only used briefly, since only
a few bytes are transmitted along it.)
Step 3: Once the data channel to AFNI is open, the image source program
can send image data to AFNI (this is done in AFNI_send_image()
in ep_afni.c). Before the first image is sent, there must be
at least one AFNI command string sent along the data channel.
In the way I've set up ep_afni.c for the MCW Bruker 3T, two commands
are actually sent here just before the first image:
DATUM short
XYMATRIX nx ny
All the rest of the commands come from 3T_toafni. The reason
for this separation is that 3T_toafni doesn't actually know how
the user chose to reconstruct the images (e.g., 64x64 acquisition
could be reconstructed to 128x128 image). The information given
here is the minimal amount needed for AFNI to compute how many
bytes in the data channel go with each image. This MUST be
present here so that AFNI can read and buffer image data from
the data channel.
If the image source program knows ALL the information that AFNI
needs, then there is no need for the info program. In such a
case, all the command strings for AFNI can be collected into
one big string (with '\n' line separators and the usual '\0'
terminator) and sent to AFNI just before the first image data.
This "Do it all at once" approach (MUCH simpler than using an
info program to get the command strings) would require some
small changes to routine AFNI_send_image() in ep_afni.c.
"Do it all at once" is the approach taken by the realtime
simulation program rtfeedme.c, which will take an AFNI dataset
apart and transmit it to the realtime plugin.
If the "Do it all at once" option is not practical, then an
alternative info program to 3T_toafni must be developed for each
new scanner+computer setup. Note that the info program writes its
output command strings to stdout, which will be captured by AFNI.
After the initial command information is sent down the data
channel, everything that follows down the data channel must be
raw image information - no more commands and no headers. For
example, if you have 64x64 images of shorts, then each set of
8192 bytes (after the terminal '\0' of the initial command
string) is taken as an image.
If an info program was specified on the 7954 socket, then
it will be run by AFNI (in a forked sub-process) at this time.
Until it completes, AFNI will just buffer the image data it
receives, since it doesn't know how to assemble the images into
3D volumes (e.g., it doesn't know the number of slices).
When the data channel connection is closed (usually because the
image source program exits), then AFNI will write the new dataset
to disk. This is why there is no command to AFNI to tell it how
many volumes to acquire - it will just add them to the dataset
until there is no more data. AFNI will then start to listen on the
TCP/IP 7954 port for another control connection, so it can acquire
another dataset.
** If you want to start a new acquisition WITHOUT shutting down
the data channel connection, there is a hack-ish way to do so.
THe way the plugin is written, it reads an entire image's (2D or 3D)
worth of data whenever it can get it. If the first 30 bytes of this
data is the ASCII string "Et Earello Endorenna utulien!!" (without
the quotes), then this is a marker that the acquisition is over, the
datasets are to be saved, and the data channel is to be made ready
for a new set of AFNI command strings that describe the next realtime
acquisition. It is important to note that when you send this "end of
acquisition" marker string, that an entire image's worth of data must
be sent, even though only the first 30 bytes matter.
======================
Hosts that AFNI trusts
======================
AFNI checks the incoming IP address of socket connections to see if the
host is on the "trust list". The default trust list is
141.106.106 = any MCW Biophysics computer (we're very trustworthy)
127.0.0.1 = localhost
192.168 = private class B networks (this is a reserved set of
addresses that should not be visible to the Internet)
You can add to this list by defining the environment variable as in the
example below (before starting AFNI):
setenv AFNI_TRUSTHOST 123.45.67
This means that any IP address starting with the above string will be
acceptable. If you want to add more than one possibility, then you can
also use environment variables AFNI_TRUSTHOST_1, AFNI_TRUSTHOST_2, up to
AFNI_TRUSTHOST_99. (That should be enough - how trusting do you really
want to be?) If you want to remove the builtin trust for MCW Biophysics,
you'll have to edit file thd_trusthost.c.
Note that while AFNI also makes uses of NIML_TRUSTHOST_* variables,
plug_realtime does not.
You cannot use hostnames for this purpose - only actual IP addresses in
the dotted form, as shown above. (What I'll do when IPv6 becomes widely
used, I don't know. Yet.)
This page auto-generated on
Thu Oct 10 09:43:56 PM EDT 2024