nifti1.h
来自「DTMK软件开发包,此为开源软件,是一款很好的医学图像开发资源.」· C头文件 代码 · 共 1,370 行 · 第 1/5 页
H
1,370 行
In Method 3, the origin of coordinates would depend on the value
of sform_code; for example, for the Talairach coordinate system,
(0,0,0) corresponds to the Anterior Commissure.
QUATERNION REPRESENTATION OF ROTATION MATRIX (METHOD 2)
-------------------------------------------------------
The orientation of the (x,y,z) axes relative to the (i,j,k) axes
in 3D space is specified using a unit quaternion [a,b,c,d], where
a*a+b*b+c*c+d*d=1. The (b,c,d) values are all that is needed, since
we require that a = sqrt(1.0-(b*b+c*c+d*d)) be nonnegative. The (b,c,d)
values are stored in the (quatern_b,quatern_c,quatern_d) fields.
The quaternion representation is chosen for its compactness in
representing rotations. The (proper) 3x3 rotation matrix that
corresponds to [a,b,c,d] is
[ a*a+b*b-c*c-d*d 2*b*c-2*a*d 2*b*d+2*a*c ]
R = [ 2*b*c+2*a*d a*a+c*c-b*b-d*d 2*c*d-2*a*b ]
[ 2*b*d-2*a*c 2*c*d+2*a*b a*a+d*d-c*c-b*b ]
[ R11 R12 R13 ]
= [ R21 R22 R23 ]
[ R31 R32 R33 ]
If (p,q,r) is a unit 3-vector, then rotation of angle h about that
direction is represented by the quaternion
[a,b,c,d] = [cos(h/2), p*sin(h/2), q*sin(h/2), r*sin(h/2)].
Requiring a >= 0 is equivalent to requiring -Pi <= h <= Pi. (Note that
[-a,-b,-c,-d] represents the same rotation as [a,b,c,d]; there are 2
quaternions that can be used to represent a given rotation matrix R.)
To rotate a 3-vector (x,y,z) using quaternions, we compute the
quaternion product
[0,x',y',z'] = [a,b,c,d] * [0,x,y,z] * [a,-b,-c,-d]
which is equivalent to the matrix-vector multiply
[ x' ] [ x ]
[ y' ] = R [ y ] (equivalence depends on a*a+b*b+c*c+d*d=1)
[ z' ] [ z ]
Multiplication of 2 quaternions is defined by the following:
[a,b,c,d] = a*1 + b*I + c*J + d*K
where
I*I = J*J = K*K = -1 (I,J,K are square roots of -1)
I*J = K J*K = I K*I = J
J*I = -K K*J = -I I*K = -J (not commutative!)
For example
[a,b,0,0] * [0,0,0,1] = [0,0,-b,a]
since this expands to
(a+b*I)*(K) = (a*K+b*I*K) = (a*K-b*J).
The above formula shows how to go from quaternion (b,c,d) to
rotation matrix and direction cosines. Conversely, given R,
we can compute the fields for the NIFTI-1 header by
a = 0.5 * sqrt(1+R11+R22+R33) (not stored)
b = 0.25 * (R32-R23) / a => quatern_b
c = 0.25 * (R13-R31) / a => quatern_c
d = 0.25 * (R21-R12) / a => quatern_d
If a=0 (a 180 degree rotation), alternative formulas are needed.
See the nifti1_io.c function mat44_to_quatern() for an implementation
of the various cases in converting R to [a,b,c,d].
Note that R-transpose (= R-inverse) would lead to the quaternion
[a,-b,-c,-d].
The choice to specify the qoffset_x (etc.) values in the final
coordinate system is partly to make it easy to convert DICOM images to
this format. The DICOM attribute "Image Position (Patient)" (0020,0032)
stores the (Xd,Yd,Zd) coordinates of the center of the first voxel.
Here, (Xd,Yd,Zd) refer to DICOM coordinates, and Xd=-x, Yd=-y, Zd=z,
where (x,y,z) refers to the NIFTI coordinate system discussed above.
(i.e., DICOM +Xd is Left, +Yd is Posterior, +Zd is Superior,
whereas +x is Right, +y is Anterior , +z is Superior. )
Thus, if the (0020,0032) DICOM attribute is extracted into (px,py,pz), then
qoffset_x = -px qoffset_y = -py qoffset_z = pz
is a reasonable setting when qform_code=NIFTI_XFORM_SCANNER_ANAT.
That is, DICOM's coordinate system is 180 degrees rotated about the z-axis
from the neuroscience/NIFTI coordinate system. To transform between DICOM
and NIFTI, you just have to negate the x- and y-coordinates.
The DICOM attribute (0020,0037) "Image Orientation (Patient)" gives the
orientation of the x- and y-axes of the image data in terms of 2 3-vectors.
The first vector is a unit vector along the x-axis, and the second is
along the y-axis. If the (0020,0037) attribute is extracted into the
value (xa,xb,xc,ya,yb,yc), then the first two columns of the R matrix
would be
[ -xa -ya ]
[ -xb -yb ]
[ xc yc ]
The negations are because DICOM's x- and y-axes are reversed relative
to NIFTI's. The third column of the R matrix gives the direction of
displacement (relative to the subject) along the slice-wise direction.
This orientation is not encoded in the DICOM standard in a simple way;
DICOM is mostly concerned with 2D images. The third column of R will be
either the cross-product of the first 2 columns or its negative. It is
possible to infer the sign of the 3rd column by examining the coordinates
in DICOM attribute (0020,0032) "Image Position (Patient)" for successive
slices. However, this method occasionally fails for reasons that I
(RW Cox) do not understand.
-----------------------------------------------------------------------------*/
/* [qs]form_code value: */ /* x,y,z coordinate system refers to: */
/*-----------------------*/ /*---------------------------------------*/
/*! \defgroup NIFTI1_XFORM_CODES
\brief nifti1 xform codes to describe the "standard" coordinate system
@{
*/
/*! Arbitrary coordinates (Method 1). */
#define NIFTI_XFORM_UNKNOWN 0
/*! Scanner-based anatomical coordinates */
#define NIFTI_XFORM_SCANNER_ANAT 1
/*! Coordinates aligned to another file's,
or to anatomical "truth". */
#define NIFTI_XFORM_ALIGNED_ANAT 2
/*! Coordinates aligned to Talairach-
Tournoux Atlas; (0,0,0)=AC, etc. */
#define NIFTI_XFORM_TALAIRACH 3
/*! MNI 152 normalized coordinates. */
#define NIFTI_XFORM_MNI_152 4
/* @} */
/*---------------------------------------------------------------------------*/
/* UNITS OF SPATIAL AND TEMPORAL DIMENSIONS:
----------------------------------------
The codes below can be used in xyzt_units to indicate the units of pixdim.
As noted earlier, dimensions 1,2,3 are for x,y,z; dimension 4 is for
time (t).
- If dim[4]=1 or dim[0] < 4, there is no time axis.
- A single time series (no space) would be specified with
- dim[0] = 4 (for scalar data) or dim[0] = 5 (for vector data)
- dim[1] = dim[2] = dim[3] = 1
- dim[4] = number of time points
- pixdim[4] = time step
- xyzt_units indicates units of pixdim[4]
- dim[5] = number of values stored at each time point
Bits 0..2 of xyzt_units specify the units of pixdim[1..3]
(e.g., spatial units are values 1..7).
Bits 3..5 of xyzt_units specify the units of pixdim[4]
(e.g., temporal units are multiples of 8).
This compression of 2 distinct concepts into 1 byte is due to the
limited space available in the 348 byte ANALYZE 7.5 header. The
macros XYZT_TO_SPACE and XYZT_TO_TIME can be used to mask off the
undesired bits from the xyzt_units fields, leaving "pure" space
and time codes. Inversely, the macro SPACE_TIME_TO_XYZT can be
used to assemble a space code (0,1,2,...,7) with a time code
(0,8,16,32,...,56) into the combined value for xyzt_units.
Note that codes are provided to indicate the "time" axis units are
actually frequency in Hertz (_HZ), in part-per-million (_PPM)
or in radians-per-second (_RADS).
The toffset field can be used to indicate a nonzero start point for
the time axis. That is, time point #m is at t=toffset+m*pixdim[4]
for m=0..dim[4]-1.
-----------------------------------------------------------------------------*/
/*! \defgroup NIFTI1_UNITS
\brief nifti1 units codes to describe the unit of measurement for
each dimension of the dataset
@{
*/
/*! NIFTI code for unspecified units. */
#define NIFTI_UNITS_UNKNOWN 0
/** Space codes are multiples of 1. **/
/*! NIFTI code for meters. */
#define NIFTI_UNITS_METER 1
/*! NIFTI code for millimeters. */
#define NIFTI_UNITS_MM 2
/*! NIFTI code for micrometers. */
#define NIFTI_UNITS_MICRON 3
/** Time codes are multiples of 8. **/
/*! NIFTI code for seconds. */
#define NIFTI_UNITS_SEC 8
/*! NIFTI code for milliseconds. */
#define NIFTI_UNITS_MSEC 16
/*! NIFTI code for microseconds. */
#define NIFTI_UNITS_USEC 24
/*** These units are for spectral data: ***/
/*! NIFTI code for Hertz. */
#define NIFTI_UNITS_HZ 32
/*! NIFTI code for ppm. */
#define NIFTI_UNITS_PPM 40
/*! NIFTI code for radians per second. */
#define NIFTI_UNITS_RADS 48
/* @} */
#undef XYZT_TO_SPACE
#undef XYZT_TO_TIME
#define XYZT_TO_SPACE(xyzt) ( (xyzt) & 0x07 )
#define XYZT_TO_TIME(xyzt) ( (xyzt) & 0x38 )
#undef SPACE_TIME_TO_XYZT
#define SPACE_TIME_TO_XYZT(ss,tt) ( (((char)(ss)) & 0x07) \
| (((char)(tt)) & 0x38) )
/*---------------------------------------------------------------------------*/
/* MRI-SPECIFIC SPATIAL AND TEMPORAL INFORMATION:
---------------------------------------------
A few fields are provided to store some extra information
that is sometimes important when storing the image data
from an FMRI time series experiment. (After processing such
data into statistical images, these fields are not likely
to be useful.)
{ freq_dim } = These fields encode which spatial dimension (1,2, or 3)
{ phase_dim } = corresponds to which acquisition dimension for MRI data.
{ slice_dim } =
Examples:
Rectangular scan multi-slice EPI:
freq_dim = 1 phase_dim = 2 slice_dim = 3 (or some permutation)
Spiral scan multi-slice EPI:
freq_dim = phase_dim = 0 slice_dim = 3
since the concepts of frequency- and phase-encoding directions
don't apply to spiral scan
slice_duration = If this is positive, AND if slice_dim is nonzero,
indicates the amount of time used to acquire 1 slice.
slice_duration*dim[slice_dim] can be less than pixdim[4]
with a clustered acquisition method, for example.
slice_code = If this is nonzero, AND if slice_dim is nonzero, AND
if slice_duration is positive, indicates the timing
pattern of the slice acquisition. The following codes
are defined:
NIFTI_SLICE_SEQ_INC == sequential increasing
NIFTI_SLICE_SEQ_DEC == sequential decreasing
NIFTI_SLICE_ALT_INC == alternating increasing
NIFTI_SLICE_ALT_DEC == alternating decreasing
NIFTI_SLICE_ALT_INC2 == alternating increasing #2
NIFTI_SLICE_ALT_DEC2 == alternating decreasing #2
{ slice_start } = Indicates the start and end of the slice acquisition
{ slice_end } = pattern, when slice_code is nonzero. These values
are present to allow for the possible addition of
"padded" slices at either end of the volume, which
don't fit into the slice timing pattern. If there
are no padding slices, then slice_start=0 and
slice_end=dim[slice_dim]-1 are the correct values.
For these values to be meaningful, slice_start must
be non-negative and slice_end must be greater than
slice_start. Otherwise, they should be ignored.
The following table indicates the slice timing pattern, relative to
time=0 for the first slice acquired, for some sample cases. Here,
dim[slice_dim]=7 (there are 7 slices, labeled 0..6), slice_duration=0.1,
and slice_start=1, slice_end=5 (1 padded slice on each end).
slice
index SEQ_INC SEQ_DEC ALT_INC ALT_DEC ALT_INC2 ALT_DEC2
6 : n/a n/a n/a n/a n/a n/a n/a = not applicable
5 : 0.4 0.0 0.2 0.0 0.4 0.2 (slice time offset
4 : 0
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?