Attributes in the AFNI Dataset Header ===================================== Each attribute is an array of values. There are three kinds of attributes allowed: float, int, and string (array of char). Each attribute has a name, which by convention is all caps. All the attributes are read in at once when a dataset .HEAD file is opened. The software searches for the attributes it wants, by name, when it needs them. Attributes that are not wanted by the programs are thus simply ignored. For example, the HISTORY_NOTE attribute is only used by functions in the thd_notes.c source file. -------------------- Format of Attributes -------------------- The format of attributes is a little clunky and non-robust, but that's the way it is for now. The .HEAD file structure was "designed" in 1994, and has not changed at all since then. Here is an example of an int attribute in the .HEAD file: type = integer-attribute name = ORIENT_SPECIFIC count = 3 3 5 1 The first line of the attribute is the "type =" line, which can take values "integer-attribute", "float-attribute", or "string-attribute". The second line is the "name =" line; the name that follows must not contain any blanks. The third line is the "count =" line; the value that follows is the number of entries in the attribute array. These 3 lines are read with the code below: char aname[THD_MAX_NAME] , atypestr[THD_MAX_NAME] ; int acount ; fscanf( header_file , " type = %s name = %s count = %d" , atypestr , aname , &acount ) ; Recall that a blank in a format matches any amount of whitespace in the input stream; for example, "name =" and "name =" are both acceptable second lines in an attribute (as are a number of other bizarre things that are too painful to elucidate). Following the third line is the list of values for the attribute array. For float and int attributes, these values are separated by blanks (or other C "whitespace"). If the .HEAD file is generated by an AFNI program, then a maximum of 5 values per line will be written. However, this is not required -- it is just there to make the .HEAD file easy to edit manually. For string attributes, the entire array of "count" characters follows on the fourth line, right after a single opening quote ' character. For example: type = string-attribute name = TYPESTRING count = 15 '3DIM_HEAD_ANAT~ Note that the starting ' is not part of the attribute value and is not included in the count. Also note that ASCII NUL characters '\0' are replaced with tilde ~ characters when the header is written. (This is to make it easy to edit the file manually). They will be replaced with NULs (not to be confused with NULL) when the attribute is read in. If a string actually contains a tilde, then the tilde will be replaced with an asterisk * when the attribute is written out. However, asterisks will NOT be replaced with tildes on input -- that is, there is no way for an attribute string to contain a tilde. Some of the attributes described below may contain more array entries in the .HEAD file than are listed. These entries are "reserves" for future expansion. In most cases, the expansions never happened. --------------------------------------- Extracting Attributes in a Shell Script --------------------------------------- Program 3dAttribute can be used to extract attributes from a dataset .HEAD file. For example 3dAttribute TYPESTRING anat+orig might produce (on stdout) the value "3DIM_HEAD_ANAT". This could be captured in a shell variable and used to make some decisions. For usage details, type the command 3dAttribute -help -------------------- Mandatory Attributes -------------------- All these attributes must be present for a dataset to be recognized from a .HEAD file. DATASET_RANK = Two values that determine the dimensionality of the (int) dataset: [0] = Number of spatial dimensions (must be 3) [1] = Number of sub-bricks in the dataset (in most programs, this is called "nvals") At one time I thought I might extend AFNI to support n-dimensional datasets, but as time went one, I decided to support the fourth dimension not by increasing the "rank" of a dataset, but by adding the time axis instead. Thus, the dataset rank is always set to 3. DATASET_DIMENSIONS = Three values that determine the size of each (int) spatial axis of the dataset: [0] = number of voxels along the x-axis (nx) [1] = number of voxels along the y-axis (ny) [2] = number of voxels along the z-axis (nz) The voxel with 3-index (i,j,k) in a sub-brick is located at position (i+j*nx+k*nx*ny), for i=0..nx-1, j=0..ny-1, k=0..nz-1. Each axis must have at least 2 points! TYPESTRING = One of "3DIM_HEAD_ANAT" or "3DIM_HEAD_FUNC" or (string) "3DIM_GEN_ANAT" or "3DIM_GEN_FUNC". Determines if the dataset is of Anat or Func type (grayscale underlay or color overlay). If Anat type, and if it is a _HEAD_ dataset in the +orig view, then Talairach markers might be attached to it (if it was created by to3d). SCENE_DATA = Three integer codes describing the dataset type (int) [0] = view type: 0=+orig, 1=+acpc, 2=+tlrc [1] = func type: If dataset is Anat type, then this is one of the following codes: #define ANAT_SPGR_TYPE 0 #define ANAT_FSE_TYPE 1 #define ANAT_EPI_TYPE 2 #define ANAT_MRAN_TYPE 3 #define ANAT_CT_TYPE 4 #define ANAT_SPECT_TYPE 5 #define ANAT_PET_TYPE 6 #define ANAT_MRA_TYPE 7 #define ANAT_BMAP_TYPE 8 #define ANAT_DIFF_TYPE 9 #define ANAT_OMRI_TYPE 10 #define ANAT_BUCK_TYPE 11 At this time, Anat codes 0..10 are treated identically by all AFNI programs. Code 11 marks the dataset as a "bucket" type, which is treated differently in the display; the "Define Overlay" control panel will have a chooser that allows you to specify which sub-brick from the bucket should be used to make the underlay image. If dataset is Func type, then this is one of the following codes (Please modify @statauxcode if you make additions or changes here): #define FUNC_FIM_TYPE 0 /* 1 value */ #define FUNC_THR_TYPE 1 /* obsolete */ #define FUNC_COR_TYPE 2 /* fico: correlation */ #define FUNC_TT_TYPE 3 /* fitt: t-statistic */ #define FUNC_FT_TYPE 4 /* fift: F-statistic */ #define FUNC_ZT_TYPE 5 /* fizt: z-score */ #define FUNC_CT_TYPE 6 /* fict: Chi squared */ #define FUNC_BT_TYPE 7 /* fibt: Beta stat */ #define FUNC_BN_TYPE 8 /* fibn: Binomial */ #define FUNC_GT_TYPE 9 /* figt: Gamma */ #define FUNC_PT_TYPE 10 /* fipt: Poisson */ #define FUNC_BUCK_TYPE 11 /* fbuc: bucket */ These types are defined more fully in README.func_types. Unfortunately, the func type codes overlap for Func and Anat datasets. This means that one cannot tell the contents of a dataset from a single attribute. However, this bad design choice (from 1994) is now enshrined in the .HEAD files of thousands of datasets, so it will be hard to change. [2] = 0 or 1 or 2 or 3, corresponding to the TYPESTRING values given above. If this value does not match the typestring value, then the dataset is malformed and AFNI will reject it! ORIENT_SPECIFIC = Three integer codes describing the spatial orientation (int) of the dataset axes; [0] for the x-axis, [1] for the y-axis, and [2] for the z-axis. The possible codes are: #define ORI_R2L_TYPE 0 /* Right to Left */ #define ORI_L2R_TYPE 1 /* Left to Right */ #define ORI_P2A_TYPE 2 /* Posterior to Anterior */ #define ORI_A2P_TYPE 3 /* Anterior to Posterior */ #define ORI_I2S_TYPE 4 /* Inferior to Superior */ #define ORI_S2I_TYPE 5 /* Superior to Inferior */ Note that these codes must make sense (e.g., they can't all be 4). Only program to3d enforces this restriction, but if you create a nonsensical dataset, then bad things will happen at some point. Spatial xyz-coordinates in AFNI are sometimes used in dataset order, which refers to the order given here. They are also sometimes used in Dicom order, in which x=R-L, y=A-P, and z=I-S (R,A,I are < 0; L,P,S are > 0). There are utility functions for converting dataset ordered 3-vectors to and from Dicom ordered 3-vectors -- see the functions in file thd_coords.c. Distances in AFNI are always encoded in millimeters. ORIGIN = Three numbers giving the xyz-coordinates of the center of (float) the (0,0,0) voxel in the dataset. The order of these numbers is the same as the order of the xyz-axes (cf. ORIENT_SPECIFIC). However, the AFNI convention is that R-L, A-P, and I-S are negative-to-positive. Thus, if the y-axis is P-A (say), then the y-origin is likely to be positive (and the y-delta, below, would be negative). These numbers are usually computed from the centering controls in to3d. DELTA = Three numbers giving the (x,y,z) voxel sizes, in the same order as ORIENT_SPECIFIC. That is, [0] = x-delta, [1] = y-delta, and [2] = z-delta. These values may be negative; in the example above, where the y-axis is P-A, then y-delta would be negative. The center of the (i,j,k) voxel is located at xyz-coordinates ORIGIN[0]+i*DELTA[0], ORIGIN[1]+j*DELTA[1], ORIGIN[2]+k*DELTA[2] --------------------------------- Time-Dependent Dataset Attributes --------------------------------- These attributes are mandatory if the .HEAD file describes a 3D+time dataset. TAXIS_NUMS = [0] = Number of points in time (at present, must be equal (int) to nvals=DATASET_RANK[1], or AFNI programs will not be happy; that is, each time point can only have a single numerical value per voxel). [1] = Number of slices with time offsets. If zero, then no slice-dependent time offsets are present (all slices are presumed to be acquired at the same time). If positive, specifies the number of values to read from TAXIS_OFFSETS. Normally, this would either be 0 or be equal to DATASET_DIMENSIONS[2]. [2] = Units codes for TAXIS_FLOATS[1]; one of the following #define UNITS_MSEC_TYPE 77001 /* don't ask me */ #define UNITS_SEC_TYPE 77002 /* where these */ #define UNITS_HZ_TYPE 77003 /* came from! */ TAXIS_FLOATS = [0] = Time origin (in units given by TAXIS_NUMS[2]). (float) This is 0 in datasets created by to3d (at present). [1] = Time step (TR). [2] = Duration of acquisition. This is 0 in datasets created by to3d (at present) [3] = If TAXIS_NUMS[1] > 0, then this is the z-axis offset for the slice-dependent time offsets. This will be equal to ORIGIN[2] in datasets created by to3d.c. [4] = If TAXIS_NUMS[1] > 0, then this is the z-axis step for the slice-dependent time offsets. This will be equal to DELTA[2] in datasets created by to3d.c. TAXIS_OFFSETS = If TAXIS_NUMS[1] > 0, then this array gives the time (floats) offsets of the slices defined by TAXIS_FLOATS[3..4]. The time offset at z = TAXIS_FLOATS[3] + k*TAXIS_FLOATS[4] is TAXIS_OFFSETS[k], for k=0..TAXIS_NUMS[1]-1. If TAXIS_NUMS[1] == 0, then this attribute is not used. The functions in thd_timeof.c are used to compute the time for any given voxel, taking into account the slice-dependent offsets. --------------------------- Almost Mandatory Attributes --------------------------- The following useful attributes are present in most AFNI datasets created by AFNI package programs. However, if they are not present, then the function that assembles a dataset struct will get by. IDCODE_STRING = 15 character string (plus NUL) giving a (hopefully) (string) unique identifier for the dataset, independent of the filename assigned by the user. If this attribute is not present, the input routine will make one up for the dataset. ID codes are used to provide links between datasets; see IDCODE_ANAT_PARENT for an example. (ID codes are generated in file thd_idcode.c.) IDCODE_DATE = Maximum of 47 characters giving the creation date for (string) the dataset. (Antedates the History Note, which contains the same information and more.) Not used anywhere except in 3dinfo. BYTEORDER_STRING = If this attribute is present, describes the byte- (string) ordering of the data in the .BRIK file. Its value must be one of the strings "LSB_FIRST" or "MSB_FIRST". If this attribute is not present, AFNI will assume that the brick is in the "native" order for the CPU on which the program is running. If this attribute is present, and it is different from the native CPU order, then short sub-bricks are 2-swapped (AB->BA) and float or complex sub-bricks are 4-swapped (ABCD->DCBA) when the .BRIK file is read into memory. BRICK_STATS = There should be 2*nvals values here. For the p-th (float) sub-brick, BRICK_STATS[2*p] is the minimum value stored in the brick, and BRICK_STATS[2*p+1] is the maximum value stored in the brick. If the brick is scaled, then these values refer to the scaled values, NOT to the actual values stored in the .BRIK file. Most AFNI programs create this attribute as they write the dataset to disk (e.g., by using the DSET_write macro, or by calling THD_load_statistics). The main function of this attribute is to provide the display of the dataset numerical ranges on the "Define Overlay" control panel. BRICK_TYPES = There should be nvals=DATASET_RANK[1] values here. For (int) the p-th sub-brick, BRICK_TYPES[p] is a code that tells the type of data stored in the .BRIK file for that sub-brick. (Although it is possible to create a dataset that has varying sub-brick types, I do not recommend it. That is, I recommend that all BRICK_TYPE[p] values be the same.) The legal types for AFNI datasets are 0 = byte (unsigned char; 1 byte) 1 = short (2 bytes, signed) 3 = float (4 bytes, assumed to be IEEE format) 5 = complex (8 bytes: real+imaginary parts) Future versions of AFNI may support 2=int, 4=double, and 6=rgb, or other extensions (but don't hold your breath). Relatively few AFNI programs support complex-valued datasets. If this attribute is not present, then the sub-bricks will all be assumed to be shorts (which was the only datum type supported in AFNI 1.0). The p-th sub-brick will have nx*ny*nz*sz bytes from the .BRIK file, where nx,ny,nz are from DATASET_DIMENSIONS and sz=sizeof(datum type). BRICK_FLOAT_FACS = There should be nvals=DATASET_RANK[1] values here. For (float) the p-th sub-brick, if f=BRICK_FLOAT_FACS[p] is positive, then the values in the .BRIK should be scaled by f to give their "true" values. Normally, this would only be used with byte or short types (to save disk space), but it is legal to use f > 0 for float type sub-bricks as well (although pointless and confusing). If f==0, then the values are unscaled. Possible uses for f < 0 are reserved for the future. If this attribute is not present, then all brick factors are taken to be 0 (i.e., no scaling). BRICK_LABS = These are labels for the sub-bricks, and are used in the (string) choosers for sub-brick display when the dataset is a bucket type. This attribute should contain nvals sub-strings, separated by NUL characters. If this attribute is not present, then the input routine will make up some labels of the form "#0", "#1", etc. BRICK_STATAUX = This stores auxiliary statistical information about (float) sub-bricks that contain statistical parameters. Each unit of this array contains the following iv = sub-brick index (0..nvals-1) jv = statistical code (see below) nv = number of parameters that follow (may be 0) and then nv more numbers. That is, there are nv+3 numbers for each unit of this array, starting at location [0]. After the first unit is read out (from BRICK_STATAUX[0] up to BRICK_STATAUX[2+BRICK_STATAUX[2]]), then the next one starts immediately with the next value of iv. jv should be one of the 9 statistical types supported by AFNI, and described in README.func_types, and below: ------------- ----------------- ------------------------------ Type Index=jv Distribution Auxiliary Parameters [stataux] ------------- ----------------- ------------------------------ FUNC_COR_TYPE Correlation Coeff # Samples, # Fit Param, # Orts FUNC_TT_TYPE Student t Degrees-of-Freedom (DOF) FUNC_FT_TYPE F ratio Numerator DOF, Denominator DOF FUNC_ZT_TYPE Standard Normal -- none -- FUNC_CT_TYPE Chi-Squared DOF FUNC_BT_TYPE Incomplete Beta Parameters "a" and "b" FUNC_BN_TYPE Binomial # Trials, Probability per trial FUNC_GT_TYPE Gamma Shape, Scale FUNC_PT_TYPE Poisson Mean The main function of this attribute is to let the "Define Overlay" threshold slider show a p-value. This attribute also allows various other statistical calculations, such as the "-1zscore" option to 3dmerge. STAT_AUX = The BRICK_STATAUX attribute allows you to attach statistical (float) distribution information to arbitrary sub-bricks of a bucket dataset. The older STAT_AUX attribute is for the Func type datasets of the following types: fico = FUNC_COR_TYPE fitt = FUNC_TT_TYPE fift = FUNC_FT_TYPE fict = FUNC_CT_TYPE fibt = FUNC_BT_TYPE fibn = FUNC_BN_TYPE figt = FUNC_GT_TYPE fipt = FUNC_PT_TYPE These parameters apply to the second sub-brick (#1) of the dataset. (Datasets of these types must have exactly 2 sub-bricks.) The number and definition of these parameters is the same as the BRICK_STATAUX cases, above. ---------------- Notes Attributes ---------------- Special characters in these strings are escaped. For example, the newline character is stored in the header as the two character combination "\n", but will be displayed as a newline when the Notes are printed (e.g., in 3dinfo). The characters that are escaped are '\r' '\n' '\"' '\t' '\a' '\v' '\b' CR LF quote TAB BEL VTAB BS For details, see function tross_Encode_String() in file thd_notes.c. HISTORY_NOTE = A multi-line string giving the history of the dataset. (string) Can be read with 3dinfo, the Notes plugin, or 3dNotes. Written functions in thd_notes.c, including tross_Copy_History: copies dataset histories tross_Make_History: adds a history line from argc,argv NOTES_COUNT = The number of auxiliary notes attached to the dataset (int) (from 0 to 999). NOTE_NUMBER_001 = The first auxiliary note attached to the dataset. (string) Can be read/written with the Notes plugin, or 3dNotes. (You have to guess what the attribute name for the 237th Note will be.) ----------------------- Registration Attributes ----------------------- Note that the MATVEC attributes are transformations of Dicom-ordered coordinates, and so have to be permuted to transform dataset-ordered xyz-coordinates. The MATVEC attributes describe the transformation of coordinates from input dataset to the output dataset in the form [xyz_out] = [mat] ([xyz_in]-[xyz_cen]) + [vec] + [xyz_cen] where [mat] is a 3x3 orthogonal matrix; [vec] is a 3-vector; [xyz_in] is the input vector; [xyz_cen] is the center of rotation (usually the center of the dataset); [xyz_out] is the output vector. Dicom coordinate order is used for these matrices and vectors, which means that they need to be permuted to dataset order for application. For examples of how this is done, see 3drotate.c and 3dvolreg.c. TAGALIGN_MATVEC = 12 numbers giving the 3x3 matrix and 3-vector of the (float) transformation derived in 3dTagalign. The matrix-vector are loaded from the following elements of the attribute: [ 0 1 2 ] [ 3 ] [mat] = [ 4 5 6 ] [vec] = [ 7 ] [ 8 9 10 ] [ 11 ] This is used by 3drotate with the -matvec_dset option, and is written by 3dTagalign. VOLREG_MATVEC_xxxxxx = For sub-brick #xxxxxx (so a max of 999,999 (float) sub-bricks can be used), this stores the 12 numbers for the matrix-vector of the transformation from 3dvolreg. This is used by the -rotparent options of 3drotate and 3dvolreg, and is written into the output dataset of 3dvolreg. The value of xxxxxx is printf("%06d",k) for k=0..VOLREG_ROTCOM_NUM-1. VOLREG_ROTCOM_xxxxxx = The -rotate/-ashift options to 3drotate that are (string) equivalent to the above matrix-vector transformation. It is not actually used anywhere, but is there for reference. VOLREG_CENTER_OLD = The xyz-coordinates (Dicom order) of the center of (float) the input dataset to 3dvolreg; this is written to 3dvolreg's output dataset, and is used by the -rotparent options to 3dvolreg and 3drotate. VOLREG_CENTER_BASE = The xyz-coordinates (Dicom order) of the center of the base dataset to 3dvolreg; this is written to 3dvolreg's output dataset, and is used by the -rotparent options to 3dvolreg and 3drotate. VOLREG_ROTPARENT_IDCODE = If a 3dvolreg run uses the -rotparent option, (string) then this value in the header of the output dataset tells which dataset was the rotparent. VOLREG_ROTPARENT_NAME = The .HEAD filename of the -rotparent. (string) VOLREG_GRIDPARENT_IDCODE = Similar to the above, but for a 3dvolreg (string) output dataset that was created using a -gridparent option. VOLREG_GRIDPARENT_NAME = The .HEAD filename of the -gridparent. (string) VOLREG_INPUT_IDCODE = In the 3dvolreg output dataset header, this (string) tells which dataset was the input to 3dvolreg. VOLREG_INPUT_NAME = The .HEAD filename of the 3dvolreg input dataset. (string) VOLREG_BASE_IDCODE = In the 3dvolreg output dataset header, this (string) tells which dataset was the base for registration. VOLREG_BASE_NAME = The .HEAD filename of the 3dvolreg base dataset. (string) VOLREG_ROTCOM_NUM = The single value in here tells how many sub-bricks (int) were registered by 3dvolreg. (The only reason this might be different than nvals is that someone might later tack extra sub-bricks onto this dataset using 3dTcat.) This is how many VOLREG_MATVEC_xxxxx and VOLREG_ROTCOM_xxxxxx attributes are present in the dataset. ------------------------ Miscellaneous Attributes ------------------------ IDCODE_ANAT_PARENT = ID code for the "anatomy parent" of this dataset (string) (if it has one). TO3D_ZPAD = 3 integers specifying how much zero-padding to3d applied (int) when it created the dataset (x,y,z axes). At this time, only the [2] component could be nonzero. If this attribute is not present, then no zero-padding was done by to3d. ------------------ Warping Attributes ------------------ IDCODE_WARP_PARENT = ID code for the "warp parent" of this dataset (string) (if it has one). This will normally be a dataset in the +orig view, even for datasets transformed from +acpc to +tlrc. That is, the transformation chain +orig to +acpc to +tlrc is symbolic; when you transform a dataset from +acpc to +tlrc, AFNI catenates that transformation onto the +orig to +acpc transformation and stores the result, which is the direct transformation from +orig to +tlrc. WARP_TYPE = [0] = Integer code describing the type of warp: (int) #define WARP_AFFINE_TYPE 0 #define WARP_TALAIRACH_12_TYPE 1 [1] = No longer used (was the resampling type, but that is now set separately by the user). WARP_DATA = Data that define the transformation from the warp parent (float) to the current dataset. Each basic linear transformation (BLT) takes 30 numbers. For WARP_AFFINE_TYPE, there is one BLT per warp; for WARP_TALAIRACH_12_TYPE, there are 12 BLTs per warp. Thus, for WARP_AFFINE_TYPE there should be 30 numbers in WARP_DATA, and for WARP_TALAIRACH_12_TYPE there should be 360 numbers. (WARP_AFFINE_TYPE is used for the +orig to +acpc transformation; WARP_TALAIRACH_12_TYPE is used for the +orig to +tlrc transformation - duh.) Each BLT is defined by a struct that contains two 3x3 matrices and four 3-vectors (2*3*3+4*3 = the 30 numbers). These values are: [mfor] = 3x3 forward transformation matrix [0..8] } range of [mbac] = 3x3 backward transformation matrix [9..17] } indexes [bvec] = 3-vector for forward transformation [18..20] } in the [svec] = 3-vector for backward transformation [21..23] } WARP_DATA [bot] } two more 3-vectors that [24..26] } BLT [top] } are described below [27..29] } array (the matrices are stored in row-major order; e.g., [ 0 1 2 ] [mfor] = [ 3 4 5 ] [ 6 7 8 ] -- the indices of the [mfor] matrix). The forward transformation is [x_map] = [mfor] [x_in] - [bvec]; The backward transformation is [x_in] = [mbac] [x_map] - [svec] (which implies [svec] = -[mbac] [bvec] and [mbac] = Inverse{[mfor]}). The forward transformation is the transformation of Dicom order coordinates from the warp parent dataset (usually in the +orig view) to the warped dataset (usually +acpc or +tlrc). The backward transformation is just the inverse of the forward transformation, and is stored for convenience (it could be recomputed from the forward transformation whenever it was needed, but that would be too much like work). The identity BLT would be stored as these 30 numbers: 1 0 0 } 0 1 0 } [mfor] = I 0 0 1 } 1 0 0 } 0 1 0 } [mbac] = I 0 0 1 } 0 0 0 } [bvec] = 0 0 0 0 } [svec] = 0 botx boty botz } these numbers are described below, topx topy topz } and depend on the application. If the transformation is WARP_TALAIRACH_12_TYPE, then each BLT only applies to a bounded region of 3-space. The [bot] and [top] vectors define the limits for each BLT, in the warped [x_map] coordinates. These values are used in the function AFNI_transform_vector() to compute the transformation of a 3-vector between +orig and +tlrc coordinates. For example, to compute the transformation from +tlrc back to +orig of a vector [x_tlrc], the code must scan all 12 [bot]..[top] regions to see which BLT to use. Similarly, to transform [x_orig] from +orig to +tlrc, the vector must be transformed with each BLT and then the result tested to see if it lies within the BLT's [bot]..[top] region. (If a lower bound is supposed to be -infinity, then that element of [bot] is -9999; if an upper bound is supposed to be +infinity, then that element of [top] is +9999 -- there is an implicit assumption that AFNI won't be applied to species with heads more than 10 meters in size.) For the +orig to +acpc transformation (of WARP_AFFINE_TYPE), the [bot] and [top] vectors store the bounding box of the transformed dataset. However, this fact isn't used much (only when the new dataset is created when the user presses the "Define Markers->Transform Data" button, which is when the +acpc.HEAD file would be created). If you were to manually edit the +acpc.HEAD file and change [bot] and [top], nothing would happen. This is not true for a +tlrc.HEAD file, since the [bot] and [top] vectors actually mean something for WARP_TALAIRACH_12_TYPE. ---------------------------- Talairach Markers Attributes ---------------------------- These are used to define the transformations from +orig to +acpc coordinates, and from +acpc to +tlrc. If they are present, then opening the "Define Markers" panel in AFNI will show a list of the markers and let you edit their locations. MARKSET_ALIGN (+orig to +acpc) markers are attached to 3DIM_HEAD_ANAT +orig datasets created by to3d (if there is no time axis). An empty set of such markers can also be attached to such datasets using the "-markers" option to 3drefit. (The label and help strings for the 2 types of marker sets are defined in 3ddata.h.) MARKS_XYZ = 30 values giving the xyz-coordinates (Dicom order) of (float) the markers for this dataset. (A maximum of 10 markers can be defined for a dataset.) MARKS_XYZ[0] = x0, MARKS_XYZ[1] = y0, MARKS_XYZ[2] = z0, MARKS_XYZ[3] = x1, etc. If a marker's xyz-coordinates are outside the bounding box of the dataset, it is considered not to be set. For this purpose, the bounding box of the dataset extends to the edges of the outermost voxels (not just their centers). MARKS_LAB = 200 characters giving the labels for the markers (20 chars (string) per marker, EXACTLY, including the NULs). A marker whose string is empty (all NUL characters) will not be defined or shown by AFNI. MARKS_HELP = 2560 characters giving the help strings for the markers (string) (256 chars per marker, EXACTLY, including the NULs). MARKS_FLAGS = [0] = Type of markers; one of the following: (int) #define MARKSET_ALIGN 1 /* +orig to +acpc */ #define MARKSET_BOUNDING 2 /* +acpc to +tlrc */ [1] = This should always be 1 (it is an "action code", but the only action ever defined was warping). -------------------------------- Attributes for User-Defined Tags -------------------------------- These tags defined and set by plug_tag.c; their original purpose was to aid in 3D alignment by having the user mark homologous points that would then be aligned with 3dTagalign. This application has pretty much been superseded with the advent of "3dvolreg -twopass" (but you never know, do you?). TAGSET_NUM = [0] = ntag = number of tags defined in the dataset (max=100) (int) [1] = nfper = number of floats stored per tag (should be 5) TAGSET_FLOATS = ntag*nfper values; for tag #i: (float) [nfper*i+0] = x-coordinate (Dicom order) [nfper*i+1] = y-coordinate (Dicom order) [nfper*i+2] = z-coordinate (Dicom order) [nfper*i+3] = tag numerical value [nfper*i+4] = sub-brick index of tag (if >= 0), or "not set" flag (if < 0) TAGSET_LABELS = ntag sub-strings (separated by NULs) with the labels (string) for each tag. ------------------------- Nearly Useless Attributes ------------------------- These attributes are leftovers from the early days of AFNI, but never became useful for anything. LABEL_1 = A short label describing the dataset. (string) LABEL_2 = Another short label describing the dataset. (string) DATASET_NAME = A longer name describing the dataset contents. (string) DATASET_KEYWORDS = List of keywords for this dataset. By convention, (string) keywords are separated by " ; ". (However, no program at this time uses the keywords or this convention!) BRICK_KEYWORDS = List of keywords for each sub-brick of the dataset. (string) Should contain nvals sub-strings (separated by NULs). Again, by convention, separate keywords for the same sub-brick would be separated by " ; " within the sub-brick's keyword string. -------------------------- Programming Considerations -------------------------- When a new dataset is created, it is usually made with one of the library functions EDIT_empty_copy() or EDIT_full_copy(). These make a copy of a dataset struct in memory. They do NOT preserve attributes. Various struct elements will be translated to attributes when the dataset is written to disk (see thd_writedset.c), but other attributes in the "parent" dataset are not automatically copied. This means that if you attach some extra information to a dataset in a plugin using an attribute, say, and write it out using the DSET_write_header() macro, that information will not be preserved in "descendants" of that dataset. For example, if you did 3dcalc -a old+orig -expr "a" -prefix new then any plugin-defined attributes attached to old+orig.HEAD will not be reproduced in new+orig.HEAD. (In fact, this would be a good way to see exactly what attributes are generated by AFNI.) ============================================================================== Accessing Dataset Elements in a C Program ============================================================================== Suppose you know the name of a dataset, and want to read some information about it in your C program. Parsing the dataset .HEAD file, as described above, would be tedious and subject to change. The "libmri.a" library (header file "mrilib.h") compiled with AFNI has functions that will do this stuff for you. The code to open a dataset file, read all its header information, and return an "empty" (unpopulated with volumetric data) dataset is like so: THD_3dim_dataset *dset ; dset = THD_open_dataset( "fred+orig.HEAD" ) ; if( dset == NULL ){ fprintf(stderr,"My bad.\n"); exit(1); } At this point, "dset" points to the complicated and ever-growing struct type that comprises an AFNI dataset (defined in "3ddata.h", which is included by "mrilib.h"). Rather than access the elements of this struct yourself, there is a large number of macros to do this for you. Some of these are documented below. Macros to Query the Status of a Dataset --------------------------------------- These macros return 1 if the dataset satisfies some condition, and return 0 if it doesn't. Here, the input "ds" is of type "THD_3dim_dataset *": DSET_ONDISK(ds) returns 1 if the dataset actually has data on disk DSET_IS_BRIK(ds) returns 1 if the dataset actually has a .BRIK file DSET_IS_MINC(ds) returns 1 if the dataset is from a MINC file ISFUNC(ds) returns 1 if the dataset is a functional type ISANAT(ds) returns 1 if the dataset is an anatomical type ISFUNCBUCKET(ds) returns 1 if the dataset is a functional bucket ISANATBUCKET(ds) returns 1 if the dataset is an anatomical bucket ISBUCKET(ds) returns 1 if the dataset is either type of bucket DSET_COMPRESSED(ds) returns 1 if the dataset .BRIK file is compressed DSET_LOADED(ds) returns 1 if the dataset .BRIK file has been loaded into memory via macro DSET_load() Macros to Query Information About Dataset Geometry -------------------------------------------------- DSET_NVALS(ds) returns the number of sub-bricks in the dataset DSET_NVOX(ds) returns the number of voxels in one sub-brick DSET_NX(ds) returns the x-axis grid array dimension DSET_NY(ds) returns the y-axis grid array dimension DSET_NZ(ds) returns the z-axis grid array dimension DSET_DX(ds) returns the x-axis grid spacing (in mm) DSET_DY(ds) returns the y-axis grid spacing (in mm) DSET_DZ(ds) returns the z-axis grid spacing (in mm) DSET_XORG(ds) returns the x-axis grid origin (in mm) DSET_YORG(ds) returns the y-axis grid origin (in mm) DSET_ZORG(ds) returns the z-axis grid origin (in mm) Along the x-axis, voxel index #i is at x = DSET_XORG(ds)+i*DSET_DX(ds), for i = 0 .. DSET_NX(ds)-1. Similar remarks apply to the y- and z-axes. Note that DSET_DX(ds) (etc.) may be negative. DSET_CUBICAL(ds) returns 1 if the dataset voxels are cubical, returns 0 if they are not The following macros may be useful for converting from 1D indexes (q) into the sub-brick arrays to 3D spatially relevant indexes (i,j,k): DSET_index_to_ix(ds,q) returns the value of i that corresponds to q DSET_index_to_jy(ds,q) returns the value of j that corresponds to q DSET_index_to_kz(ds,q) returns the value of k that corresponds to q DSET_ixyz_to_index(ds,i,j,k) returns the q that corresponds to (i,j,k) Macros to Query Information about the Dataset Time Axis ------------------------------------------------------- DSET_TIMESTEP(ds) returns the TR; if 0 is returned, there is no time axis DSET_NUM_TIMES(ds) returns the number of points along the time axis; if 1 is returned, there is no time axis Macros to Query Information About Dataset Sub-Brick Contents ------------------------------------------------------------ DSET_BRICK_TYPE(ds,i) returns a code indicating the type of data stored in the i-th sub-brick of the dataset; the type codes are defined in "mrilib.h" (e.g., MRI_short) DSET_BRICK_FACTOR(ds,i) returns the float scale factor for the data in the i-th sub-brick of the dataset; if 0.0 is returned, then don't scale this data, otherwise each value should be scaled by this factor before being used DSET_BRICK_BYTES(ds,i) returns the number of bytes used to store the data in the i-th sub-brick of the dataset DSET_BRICK_LABEL(ds,i) returns a pointer to the string label for the i-th sub-brick of the dataset DSET_BRICK_STATCODE(ds,i) returns an integer code for the type of statistic stored in the i-th sub-brick of the dataset (e.g., FUNC_FT_TYPE for an F-test statistic); returns -1 if this isn't a statistic sub-brick DSET_BRICK_STATAUX(ds,i) returns a pointer to a float array holding the auxiliary statistical parameters for the i-th sub-brick of the dataset; returns NULL if this isn't a statistic sub-brick DSET_BRICK_STATPAR(ds,i,j) returns the float value of the j-th auxiliary statistical parameter of the i-th sub-brick of the dataset; returns 0.0 if this isn't a statistic sub-brick DSET_BRICK_ARRAY(ds,i) returns a pointer to the data array for the i-th sub-brick of the dataset; returns NULL if the dataset .BRIK wasn't loaded into memory yet via the macro DSET_load() Macros to Query Information about Dataset Filenames (etc.) ---------------------------------------------------------- DSET_PREFIX(ds) returns a pointer to the dataset's prefix string DSET_FILECODE(ds) returns a pointer to the dataset's prefix+view string DSET_HEADNAME(ds) returns a pointer to the dataset's .HEAD filename string DSET_BRIKNAME(ds) returns a pointer to the dataset's .BRIK filename string DSET_DIRNAME(ds) returns a pointer to the dataset's directory name string DSET_IDCODE(ds)->str returns a pointer to the dataset's unique ID code string DSET_IDCODE(ds)->date returns a pointer to the dataset's date of creation EQUIV_DSETS(ds1,ds2) returns 1 if the two datasets have same ID code string Macros to Do Something with the Dataset --------------------------------------- DSET_load(ds) reads the dataset .BRIK file into memory (if it is already loaded, it does nothing) DSET_unload(ds) purges the dataset sub-brick arrays from memory (but the dataset struct itself is there, ready to be reloaded) DSET_delete(ds) purges the dataset sub-brick arrays from memory, then destroys the dataset struct itself as well DSET_mallocize(ds) forces the memory for the dataset to be allocated with malloc(), rather than possibly allowing mmap(); this macro should be used before DSET_load(); you CANNOT write into a mmap()-ed dataset's arrays, so if you are altering a dataset in-place, it must be mallocize-d! DSET_write(ds) writes a dataset (.HEAD and .BRIK) to disk; AFNI can't write MINC formatted datasets to disk, so don't try Important Dataset Fields without Macros --------------------------------------- ds->daxes->xxorient gives the orientation of the x-axis in space; this will be one of the following int codes: #define ORI_R2L_TYPE 0 /* Right-to-Left */ #define ORI_L2R_TYPE 1 /* Left-to-Right */ #define ORI_P2A_TYPE 2 /* Posterior-to-Anterior */ #define ORI_A2P_TYPE 3 /* Anterior-to-Posterior */ #define ORI_I2S_TYPE 4 /* Inferior-to-Superior */ #define ORI_S2I_TYPE 5 /* Superior-to-Inferior */ ds->daxes->yyorient gives the orientation of the y-axis in space ds->daxes->zzorient gives the orientation of the z-axis in space Functions to Access Attributes ------------------------------ Most attributes are loaded into dataset struct fields when a dataset is opened with THD_open_dataset(). To access the attributes directly, you can use the following functions: ATR_float *afl = THD_find_float_atr ( dset->dblk , "attribute_name" ) ; ATR_int *ain = THD_find_int_atr ( dset->dblk , "attribute_name" ) ; ATR_string *ast = THD_find_string_atr( dset->dblk , "attribute_name" ) ; The ATR_ structs are typedef-ed in 3ddata.h (included by mrilib.h). Cut directly from the living code: typedef struct { int type ; /*!< should be ATR_FLOAT_TYPE */ char * name ; /*!< name of attribute, read from HEAD file */ int nfl ; /*!< number of floats stored here */ float * fl ; /*!< array of floats stored here */ } ATR_float ; You can access the attribute values with afl->fl[i], for i=0..atr->nfl-1. This functionality is used in 3dvolreg.c, for example, to access the attributes whose name start with "VOLREG_". ==================================== Robert W Cox, PhD National Institute of Mental Health ====================================