nifti1_io.c
来自「DTMK软件开发包,此为开源软件,是一款很好的医学图像开发资源.」· C语言 代码 · 共 1,582 行 · 第 1/5 页
C
1,582 行
*//*-------------------------------------------------------------------------*/
char *nifti_slice_string( int ss )
{
switch( ss ){
case NIFTI_SLICE_SEQ_INC: return "sequential_increasing" ;
case NIFTI_SLICE_SEQ_DEC: return "sequential_decreasing" ;
case NIFTI_SLICE_ALT_INC: return "alternating_increasing" ;
case NIFTI_SLICE_ALT_DEC: return "alternating_decreasing" ;
case NIFTI_SLICE_ALT_INC2: return "alternating_increasing_2" ;
case NIFTI_SLICE_ALT_DEC2: return "alternating_decreasing_2" ;
}
return "Unknown" ;
}
/*---------------------------------------------------------------------------*/
/*! Return a pointer to a string holding the name of a NIFTI orientation.
\param ii orientation code
\return pointer to static string holding the orientation information
\warning Do not free() or modify the return string!
It points to static storage.
\sa NIFTI_L2R in nifti1_io.h
*//*-------------------------------------------------------------------------*/
char *nifti_orientation_string( int ii )
{
switch( ii ){
case NIFTI_L2R: return "Left-to-Right" ;
case NIFTI_R2L: return "Right-to-Left" ;
case NIFTI_P2A: return "Posterior-to-Anterior" ;
case NIFTI_A2P: return "Anterior-to-Posterior" ;
case NIFTI_I2S: return "Inferior-to-Superior" ;
case NIFTI_S2I: return "Superior-to-Inferior" ;
}
return "Unknown" ;
}
/*--------------------------------------------------------------------------*/
/*! Given a datatype code, set number of bytes per voxel and the swapsize.
\param datatype nifti1 datatype code
\param nbyper pointer to return value: number of bytes per voxel
\param swapsize pointer to return value: size of swap blocks
\return appropriate values at nbyper and swapsize
The swapsize is set to 0 if this datatype doesn't ever need swapping.
\sa NIFTI1_DATATYPES in nifti1.h
*//*------------------------------------------------------------------------*/
void nifti_datatype_sizes( int datatype , int *nbyper, int *swapsize )
{
int nb=0, ss=0 ;
switch( datatype ){
case DT_INT8:
case DT_UINT8: nb = 1 ; ss = 0 ; break ;
case DT_INT16:
case DT_UINT16: nb = 2 ; ss = 2 ; break ;
case DT_RGB24: nb = 3 ; ss = 0 ; break ;
case DT_RGBA32: nb = 4 ; ss = 0 ; break ;
case DT_INT32:
case DT_UINT32:
case DT_FLOAT32: nb = 4 ; ss = 4 ; break ;
case DT_COMPLEX64: nb = 8 ; ss = 4 ; break ;
case DT_FLOAT64:
case DT_INT64:
case DT_UINT64: nb = 8 ; ss = 8 ; break ;
case DT_FLOAT128: nb = 16 ; ss = 16 ; break ;
case DT_COMPLEX128: nb = 16 ; ss = 8 ; break ;
case DT_COMPLEX256: nb = 32 ; ss = 16 ; break ;
}
ASSIF(nbyper,nb) ; ASSIF(swapsize,ss) ; return ;
}
/*---------------------------------------------------------------------------*/
/*! Given the quaternion parameters (etc.), compute a transformation matrix.
See comments in nifti1.h for details.
- qb,qc,qd = quaternion parameters
- qx,qy,qz = offset parameters
- dx,dy,dz = grid stepsizes (non-negative inputs are set to 1.0)
- qfac = sign of dz step (< 0 is negative; >= 0 is positive)
<pre>
If qx=qy=qz=0, dx=dy=dz=1, then the output is a rotation matrix.
For qfac >= 0, the rotation is proper.
For qfac < 0, the rotation is improper.
</pre>
\see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h
\see nifti_mat44_to_quatern, nifti_make_orthog_mat44,
nifti_mat44_to_orientation
*//*-------------------------------------------------------------------------*/
mat44 nifti_quatern_to_mat44( float qb, float qc, float qd,
float qx, float qy, float qz,
float dx, float dy, float dz, float qfac )
{
mat44 R ;
double a,b=qb,c=qc,d=qd , xd,yd,zd ;
/* last row is always [ 0 0 0 1 ] */
R.m[3][0]=R.m[3][1]=R.m[3][2] = 0.0 ; R.m[3][3]= 1.0 ;
/* compute a parameter from b,c,d */
a = 1.0l - (b*b + c*c + d*d) ;
if( a < 1.e-7l ){ /* special case */
a = 1.0l / sqrt(b*b+c*c+d*d) ;
b *= a ; c *= a ; d *= a ; /* normalize (b,c,d) vector */
a = 0.0l ; /* a = 0 ==> 180 degree rotation */
} else{
a = sqrt(a) ; /* angle = 2*arccos(a) */
}
/* load rotation matrix, including scaling factors for voxel sizes */
xd = (dx > 0.0) ? dx : 1.0l ; /* make sure are positive */
yd = (dy > 0.0) ? dy : 1.0l ;
zd = (dz > 0.0) ? dz : 1.0l ;
if( qfac < 0.0 ) zd = -zd ; /* left handedness? */
R.m[0][0] = (a*a+b*b-c*c-d*d) * xd ;
R.m[0][1] = 2.0l * (b*c-a*d ) * yd ;
R.m[0][2] = 2.0l * (b*d+a*c ) * zd ;
R.m[1][0] = 2.0l * (b*c+a*d ) * xd ;
R.m[1][1] = (a*a+c*c-b*b-d*d) * yd ;
R.m[1][2] = 2.0l * (c*d-a*b ) * zd ;
R.m[2][0] = 2.0l * (b*d-a*c ) * xd ;
R.m[2][1] = 2.0l * (c*d+a*b ) * yd ;
R.m[2][2] = (a*a+d*d-c*c-b*b) * zd ;
/* load offsets */
R.m[0][3] = qx ; R.m[1][3] = qy ; R.m[2][3] = qz ;
return R ;
}
/*---------------------------------------------------------------------------*/
/*! Given the 3x4 upper corner of the matrix R, compute the quaternion
parameters that fit it.
- Any NULL pointer on input won't get assigned (e.g., if you don't want
dx,dy,dz, just pass NULL in for those pointers).
- If the 3 input matrix columns are NOT orthogonal, they will be
orthogonalized prior to calculating the parameters, using
the polar decomposition to find the orthogonal matrix closest
to the column-normalized input matrix.
- However, if the 3 input matrix columns are NOT orthogonal, then
the matrix produced by nifti_quatern_to_mat44 WILL have orthogonal
columns, so it won't be the same as the matrix input here.
This "feature" is because the NIFTI 'qform' transform is
deliberately not fully general -- it is intended to model a volume
with perpendicular axes.
- If the 3 input matrix columns are not even linearly independent,
you'll just have to take your luck, won't you?
\see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h
\see nifti_quatern_to_mat44, nifti_make_orthog_mat44,
nifti_mat44_to_orientation
*//*-------------------------------------------------------------------------*/
void nifti_mat44_to_quatern( mat44 R ,
float *qb, float *qc, float *qd,
float *qx, float *qy, float *qz,
float *dx, float *dy, float *dz, float *qfac )
{
double r11,r12,r13 , r21,r22,r23 , r31,r32,r33 ;
double xd,yd,zd , a,b,c,d ;
mat33 P,Q ;
/* offset outputs are read write out of input matrix */
ASSIF(qx,R.m[0][3]) ; ASSIF(qy,R.m[1][3]) ; ASSIF(qz,R.m[2][3]) ;
/* load 3x3 matrix into local variables */
r11 = R.m[0][0] ; r12 = R.m[0][1] ; r13 = R.m[0][2] ;
r21 = R.m[1][0] ; r22 = R.m[1][1] ; r23 = R.m[1][2] ;
r31 = R.m[2][0] ; r32 = R.m[2][1] ; r33 = R.m[2][2] ;
/* compute lengths of each column; these determine grid spacings */
xd = sqrt( r11*r11 + r21*r21 + r31*r31 ) ;
yd = sqrt( r12*r12 + r22*r22 + r32*r32 ) ;
zd = sqrt( r13*r13 + r23*r23 + r33*r33 ) ;
/* if a column length is zero, patch the trouble */
if( xd == 0.0l ){ r11 = 1.0l ; r21 = r31 = 0.0l ; xd = 1.0l ; }
if( yd == 0.0l ){ r22 = 1.0l ; r12 = r32 = 0.0l ; yd = 1.0l ; }
if( zd == 0.0l ){ r33 = 1.0l ; r13 = r23 = 0.0l ; zd = 1.0l ; }
/* assign the output lengths */
ASSIF(dx,xd) ; ASSIF(dy,yd) ; ASSIF(dz,zd) ;
/* normalize the columns */
r11 /= xd ; r21 /= xd ; r31 /= xd ;
r12 /= yd ; r22 /= yd ; r32 /= yd ;
r13 /= zd ; r23 /= zd ; r33 /= zd ;
/* At this point, the matrix has normal columns, but we have to allow
for the fact that the hideous user may not have given us a matrix
with orthogonal columns.
So, now find the orthogonal matrix closest to the current matrix.
One reason for using the polar decomposition to get this
orthogonal matrix, rather than just directly orthogonalizing
the columns, is so that inputting the inverse matrix to R
will result in the inverse orthogonal matrix at this point.
If we just orthogonalized the columns, this wouldn't necessarily hold. */
Q.m[0][0] = r11 ; Q.m[0][1] = r12 ; Q.m[0][2] = r13 ; /* load Q */
Q.m[1][0] = r21 ; Q.m[1][1] = r22 ; Q.m[1][2] = r23 ;
Q.m[2][0] = r31 ; Q.m[2][1] = r32 ; Q.m[2][2] = r33 ;
P = nifti_mat33_polar(Q) ; /* P is orthog matrix closest to Q */
r11 = P.m[0][0] ; r12 = P.m[0][1] ; r13 = P.m[0][2] ; /* unload */
r21 = P.m[1][0] ; r22 = P.m[1][1] ; r23 = P.m[1][2] ;
r31 = P.m[2][0] ; r32 = P.m[2][1] ; r33 = P.m[2][2] ;
/* [ r11 r12 r13 ] */
/* at this point, the matrix [ r21 r22 r23 ] is orthogonal */
/* [ r31 r32 r33 ] */
/* compute the determinant to determine if it is proper */
zd = r11*r22*r33-r11*r32*r23-r21*r12*r33
+r21*r32*r13+r31*r12*r23-r31*r22*r13 ; /* should be -1 or 1 */
if( zd > 0 ){ /* proper */
ASSIF(qfac,1.0) ;
} else { /* improper ==> flip 3rd column */
ASSIF(qfac,-1.0) ;
r13 = -r13 ; r23 = -r23 ; r33 = -r33 ;
}
/* now, compute quaternion parameters */
a = r11 + r22 + r33 + 1.0l ;
if( a > 0.5l ){ /* simplest case */
a = 0.5l * sqrt(a) ;
b = 0.25l * (r32-r23) / a ;
c = 0.25l * (r13-r31) / a ;
d = 0.25l * (r21-r12) / a ;
} else { /* trickier case */
xd = 1.0 + r11 - (r22+r33) ; /* 4*b*b */
yd = 1.0 + r22 - (r11+r33) ; /* 4*c*c */
zd = 1.0 + r33 - (r11+r22) ; /* 4*d*d */
if( xd > 1.0 ){
b = 0.5l * sqrt(xd) ;
c = 0.25l* (r12+r21) / b ;
d = 0.25l* (r13+r31) / b ;
a = 0.25l* (r32-r23) / b ;
} else if( yd > 1.0 ){
c = 0.5l * sqrt(yd) ;
b = 0.25l* (r12+r21) / c ;
d = 0.25l* (r23+r32) / c ;
a = 0.25l* (r13-r31) / c ;
} else {
d = 0.5l * sqrt(zd) ;
b = 0.25l* (r13+r31) / d ;
c = 0.25l* (r23+r32) / d ;
a = 0.25l* (r21-r12) / d ;
}
if( a < 0.0l ){ b=-b ; c=-c ; d=-d; a=-a; }
}
ASSIF(qb,b) ; ASSIF(qc,c) ; ASSIF(qd,d) ;
return ;
}
/*---------------------------------------------------------------------------*/
/*! Compute the inverse of a bordered 4x4 matrix.
<pre>
- Some numerical code fragments were generated by Maple 8.
- If a singular matrix is input, the output matrix will be all zero.
- You can check for this by examining the [3][3] element, which will
be 1.0 for the normal case and 0.0 for the bad case.
The input matrix should have the form:
[ r11 r12 r13 v1 ]
[ r21 r22 r23 v2 ]
[ r31 r32 r33 v3 ]
[ 0 0 0 1 ]
</pre>
*//*-------------------------------------------------------------------------*/
mat44 nifti_mat44_inverse( mat44 R )
{
double r11,r12,r13,r21,r22,r23,r31,r32,r33,v1,v2,v3 , deti ;
mat44 Q ;
/* INPUT MATRIX IS: */
r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 v1 ] */
r2
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?