/******************* DWIstructtensor.c *************************************/ /* Author: Daniel Glen, 13 Jun 2005 */ /* compute tensor of structure of DWI volumes for the purpose of anisotropic*/ /* smoothing of the image. */ /* called as function to generate D tensor, which can be a 2D or 3D tensor */ /* The D tensor is then used as basis for smoothing along directionality of */ /* DWI image. */ /* This tensor is not the same as the traditional diffusion tensor of DTI */ /* imaging, but it is a diffusion tensor referring to the diffusion within */ /* the image, the movement of stuff within the image. */ /* Only one D tensor volume is generated for all of the DWI volumes */ /* The 2D form has three elements in tensor form for each voxel or a 2x2 */ /* matrix in matrix form. */ /* The 3D form has 6 elements in tensor form for each voxel or 3x3 in matrix*/ /* form. */ /* This program is appropriate as a function within another main program */ /* to generate the tensor. The calling function could then use the tensor to*/ /* smooth the image */ #ifdef __GNUC__ /* inline used to make macro-equivalent speed functions */ /* but only available for gcc */ #define INLINE inline #else #define INLINE /**/ #endif #include "thd_shear3d.h" #include "matrix.h" #include "afni.h" #define TINYNUMBER 1E-10 #define SMALLNUMBER 1E-4 static char D_prefix[THD_MAX_PREFIX] = "TempDAni"; float aniso_sigma1 = 0.5; float aniso_sigma2 = 1.0; THD_3dim_dataset *DWIstructtensor(THD_3dim_dataset * DWI_dset, int flag2D3D, byte *maskptr, int smooth_flag, int save_tempdsets_flag); void Smooth_DWI_dset(THD_3dim_dataset * DWI_dset, int flag2D3D); void Smooth_Gradient_Matrix(MRI_IMARR *Gradient_Im, int flag2D3D); MRI_IMARR *Compute_Gradient_Matrix(THD_3dim_dataset *DWI_dset, int flag2D3D,byte*maskptr,int prodflag, int smooth_flag, float smooth_factor); MRI_IMARR *Compute_Gradient_Matrix_Im(MRI_IMAGE *SourceIm, int flag2D3D, byte *maskptr, int xflag, int yflag, int zflag); MRI_IMARR *Eig_Gradient(MRI_IMARR *Gradient_Im, int flag2D3D, byte *maskptr); MRI_IMARR *Compute_Phi(MRI_IMARR *EV_Im, int flag2D3D, byte *maskptr); MRI_IMARR *ComputeDTensor(MRI_IMARR *phi_Im, int flag2D3D, byte *maskptr); THD_3dim_dataset *Copy_IMARR_to_dset(THD_3dim_dataset * base_dset,MRI_IMARR *Imptr, char *new_prefix); static INLINE float vox_val(int x,int y,int z,float *imptr, int nx, int ny, int nz, byte *maskptr, int i, int j, int k); extern THD_3dim_dataset * Copy_dset_to_float(THD_3dim_dataset * dset , char * new_prefix ); void Compute_IMARR_Max(MRI_IMARR *Imptr); float Find_Max_Im(MRI_IMAGE *im, byte *maskptr); void Save_imarr_to_dset(MRI_IMARR *Imarr_Im, THD_3dim_dataset *base_dset, char *dset_name); extern int compute_method; /* determines which method to compute phi */ /*! compute image diffusion tensor, D, anisotropic smoothing of DWI */ THD_3dim_dataset * DWIstructtensor(THD_3dim_dataset * DWI_dset, int flag2D3D, byte *maskptr, int smooth_flag, int save_tempdsets_flag) { MRI_IMARR *Gradient_Im, *EV_Im, *phi_Im, *D_Im; THD_3dim_dataset *D_dset, *tempdset; ENTRY("DWIstructtensor"); /* tempdset = Copy_dset_to_float(DWI_dset, "tempani"); */ /* make another copy for smoothing */ /*if(smooth_flag) Smooth_DWI_dset(tempdset,flag2D3D);*/ /* smooth DWI images a little with Gaussian smoothing */ /* compute gradients of smoothed DWI images */ /* and form matrix of gradients - imarr with 3 sub-briks for 2D */ Gradient_Im = Compute_Gradient_Matrix(DWI_dset, flag2D3D, maskptr, 1,smooth_flag, aniso_sigma1); /* THD_delete_3dim_dataset(tempdset , False ) ;*/ /* delete temporary copy */ if(save_tempdsets_flag) Save_imarr_to_dset(Gradient_Im,DWI_dset, "Gradient"); /*Compute_IMARR_Max(Gradient_Im);*/ /* smooth each component of gradient matrix more */ if(smooth_flag) Smooth_Gradient_Matrix(Gradient_Im, flag2D3D); /* compute eigenvalues, eigenvectors of Smoothed gradient matrix */ /* imarr with 6 sub-briks for 2D (extended the Gradient_Im from 3 to 6) */ EV_Im = Eig_Gradient(Gradient_Im, flag2D3D, maskptr); if(save_tempdsets_flag) Save_imarr_to_dset(EV_Im,DWI_dset, "Eigens"); /*Compute_IMARR_Max(EV_Im);*/ /* compute phi (kind of reciprocal of eigenvalues) */ /* replace first two eigenvalue sub-briks for phi_Im */ phi_Im = Compute_Phi(EV_Im, flag2D3D, maskptr); if(save_tempdsets_flag) Save_imarr_to_dset(phi_Im,DWI_dset, "phi"); /*printf("computed phi_Im\n");*/ /*Compute_IMARR_Max(phi_Im);*/ /* compute D, diffusion tensor of structure of DWI */ /* replace first 3 sub-briks for 2D with Dxx, Dxy, Dyy */ D_Im = ComputeDTensor(phi_Im, flag2D3D, maskptr); /* do not have to free any temporary image arrays */ /* DESTROY_IMARR(phi_Im);*/ /* DESTROY_IMARR(EV_Im); */ /* for 2D, keep first three sub-briks and remove remaining sub-briks */ if(flag2D3D==2) { TRUNCATE_IMARR(D_Im,3); D_dset = Copy_IMARR_to_dset(DWI_dset, D_Im, D_prefix); tross_Copy_History (DWI_dset, D_dset); EDIT_dset_items (D_dset, ADN_brick_label_one + 0, "Dxx", ADN_none); EDIT_dset_items (D_dset, ADN_brick_label_one + 1, "Dxy", ADN_none); EDIT_dset_items (D_dset, ADN_brick_label_one + 2, "Dyy", ADN_none); } else { TRUNCATE_IMARR(D_Im,6); D_dset = Copy_IMARR_to_dset(DWI_dset, D_Im, D_prefix); tross_Copy_History (DWI_dset, D_dset); EDIT_dset_items (D_dset, ADN_brick_label_one + 0, "Dxx", ADN_none); EDIT_dset_items (D_dset, ADN_brick_label_one + 1, "Dxy", ADN_none); EDIT_dset_items (D_dset, ADN_brick_label_one + 2, "Dxz", ADN_none); EDIT_dset_items (D_dset, ADN_brick_label_one + 3, "Dyy", ADN_none); EDIT_dset_items (D_dset, ADN_brick_label_one + 4, "Dyz", ADN_none); EDIT_dset_items (D_dset, ADN_brick_label_one + 5, "Dzz", ADN_none); } EDIT_dset_items( D_dset , ADN_malloc_type , DATABLOCK_MEM_MALLOC , /* store in memory */ ADN_prefix , "Dtensor", ADN_label1 , "Dtensor" , ADN_none ) ; /* return D - diffusion tensor of image */ RETURN(D_dset); } /*! save IMARR structure to temporary dataset and write to disk */ void Save_imarr_to_dset(MRI_IMARR *Imarr_Im, THD_3dim_dataset *base_dset, char *dset_name) { THD_3dim_dataset *temp_dset; int nbriks,i; char tempstring[256]; ENTRY("Save_imarr_dset"); temp_dset = Copy_IMARR_to_dset(base_dset, Imarr_Im, dset_name); nbriks = temp_dset->dblk->nvals; tross_Copy_History (base_dset, temp_dset); for(i=0;idblk->brick = NULL; /* don't delete MRI_IMARR structure */ THD_delete_3dim_dataset( temp_dset, False ) ; /* delete temporary dset */ /* from memory (not disk) */ EXRETURN; } /* apply small amount of smoothing to data */ void Smooth_DWI_dset(THD_3dim_dataset *DWI_dset, int flag2D3D) { float *ar; MRI_IMAGE *data_im = NULL; int nx, ny, nz, fim_type, i; THD_dataxes * daxes ; float dz; ENTRY("Smooth_DWI_dset"); /** load the grid parameters **/ daxes = DWI_dset->daxes ; nx = daxes->nxx ; ny = daxes->nyy ; nz = daxes->nzz ; fim_type = MRI_float ; /* only works with floats here */ if(flag2D3D == 2) /* for 2D, don't smooth in Z direction */ dz = 0.0f; else dz = 1.0f; /* smooth DWI images a little with Gaussian smoothing */ for(i=0;idblk->nvals; i++) { /* for each sub-brik in dataset */ data_im = DSET_BRICK (DWI_dset, i); /* set pointer to the ith sub-brik of the dataset */ ar = (float *) mri_data_pointer(data_im) ; EDIT_blur_volume( nx,ny,nz, 1.0f,1.0f,dz, fim_type, ar, 0.5f ) ; } EXRETURN; } /* apply small amount of smoothing to data */ void Smooth_Gradient_Matrix(MRI_IMARR *Gradient_Im, int flag2D3D) { float *ar; MRI_IMAGE *data_im = NULL; int nx, ny, nz, fim_type, i; float dz; ENTRY("Smooth_Gradient_Matrix"); /** load the grid parameters **/ fim_type = MRI_float ; /* only works with floats here */ /* smooth DWI images a little with Gaussian smoothing */ for(i=0;inum; i++) { /* for each sub-brik in dataset */ data_im = Gradient_Im->imarr[i]; /* set pointer to the ith sub-brik of the dataset */ ar = (float *) mri_data_pointer(data_im) ; nx = data_im->nx; ny = data_im->ny; nz = data_im->nz; if(flag2D3D == 2) /* for 2D, don't smooth in Z direction */ dz = 0.0f; else dz = 1.0f; EDIT_blur_volume( nx,ny,nz, 1.0f,1.0f,dz, fim_type, ar, aniso_sigma2 ) ; } EXRETURN; } /****************************************************************************************/ /* old unoptimized code */ /* compute numerical gradients for each voxel and compose matrix for smoothing including [(du/dx)^2 du/dx*du/dy (du/dy)^2] */ MRI_IMARR * Compute_Gradient_Matrix_old(THD_3dim_dataset *DWI_dset, int flag2D3D, byte *maskptr, int prodflag) { /* DWI_dset is input dataset */ /* flag2D3D is flag for dimensionality of gradient */ /* maskptr is pointer to mask array to mask data - null if no mask */ /* prodflag is productflag whether to simply compute du/dx and du/dy or du/dx^2, du/dx*du/dy, du/dy^2 */ /* gradient matrix is returned as MRI_IMARR (2 or 3 sub-briks for 2D case)*/ /* edge points and masked points are treated equivalently */ /* with a test for the index of each node in the kernels and the central voxels themselves */ /* du/dx is calculated with 3x3 kernel for 2D as */ /* -a 0 a v0 0 v3 */ /* -b 0 b v1 0 v4 */ /* -a 0 a v2 0 v5*/ /* where a=3/16, b= 10/16 */ /* du/dy is calculated with 3x3 kernel for 2D as */ /* c d c v0 v1 v2 */ /* 0 0 0 0 0 0 */ /* -c -d -c v3 v4 v5 */ /* where c=3/16, d= 10/16 */ /* for 3d, instead of alternating rows and columns, */ /* use alternating planes in direction (p+1) - (p-1) for du/dx */ /* a b a a b a r+1 */ /* b c b - b c b r */ /* a b a a b a r-1 */ /* q-1 q q+1 */ /* where a = 0.02, b=0.06,c =0.18 */ /* two vertical planes before and after the current voxel for du/dx */ /* two horizontal planes above and below the current voxel for du/dy */ /* two slices before and after the current voxel for du/dz */ MRI_IMARR *Gradient_Im; MRI_IMAGE *im, *data_im; byte *tempmaskptr; float *ar,*gptr[6]; static double a, b, c, d; double dudx, dudy, dudz; float v0, v1, v2, v3, v4, v5, tempv, temp; float vv[3][3][3]; /* voxel values for cubic stencil */ int nx, ny, nz, i, j, k, l, ii, nbriks, nout,ll ,kk, jj; THD_dataxes * daxes ; /*float dx = 1.0;*/ /* delta x - assume cubical voxels for now */ ENTRY("Compute_Gradient_Matrix"); tempmaskptr = maskptr; /* set up constants for kernel */ if(flag2D3D==2) { a = 0.1875; /* (2.0 * dx); */ /*3/16;*/ b = 0.625; /* (2.0 * dx);*/ /* 10/16;*/ c = 0.1875; d = 0.625; if(prodflag) nout = 3; else nout = 2; } else { a = 0.02; b = 0.06; c = 0.18; if(prodflag) nout = 6; else nout = 3; } /** load the grid parameters **/ daxes = DWI_dset->daxes ; nx = daxes->nxx ; ny = daxes->nyy ; nz = daxes->nzz ; nbriks = DWI_dset->dblk->nvals; /* make new Image Array to hold gradients and then gradient products */ INIT_IMARR(Gradient_Im); for(i=0;iimarr[ii]); gptr[ii] = (float *) mri_data_pointer(im); if(gptr[ii]==NULL) { ERROR_message("can not create temporary data storage pointers"); RETURN(NULL); } } for(j=0;jnx; ny = data_im->ny; nz = data_im->nz; nxyz = data_im->nxyz; nxy = nx * ny; nbriks = DWI_dset->dblk->nvals; /* precompute offsets for each stencil point relative to the center point */ yp1xp1 = nxp1 = nx + 1; yp1xm1 = nxm1 = nx - 1; nym1 = ny - 1; nzm1 = nz - 1; maskflag = 0; /* make new Image Array to hold gradients and then gradient products */ INIT_IMARR(Gradient_Im); for(i=0;iimarr[ii]); gptr[ii] =(float *) mri_data_pointer(im); } baseoffset = 0; vptr = vptr0 = vptr1 = ar; tempmaskptr = maskptr; for(vz=0;vz=2, y>=2 */ v0 = v1; v1 = v2; v2 = *(++vptr0); v3 = v4; v4 = v5; v5 = *(++vptr); /* row after voxel */ v6 = v7; v7 = v8; v8 = *(++vptr1); dv0 = dv1; dv1 = dv2; dv2 = v8 - v2; } dudy = a*(dv0 + dv2) + b* dv1; dudx = a*(v2+v8-v0-v6) + b*(v5-v3); if(prodflag) { *(gptr[0]) += dudx * dudx; /* sum gradient product components in output image array */ *(gptr[1]) += dudx * dudy; *(gptr[2]) += dudy * dudy; gptr[2]++; } else { *(gptr[0]) += dudx; /* sum gradient components in output image array */ *(gptr[1]) += dudy; } gptr[0]++; gptr[1]++; baseoffset++; } /* x loop */ } /* y loop*/ } /* z loop */ } /* sub-brick loop */ } else { /* 3D case */ /* get 9 row pointers this time and fill 27 values */ /* this time each slice gets 3 row pointers, but we need z-1, z, z+1 slices v0-v8 are voxel values in z-1 slice, v9-v17 in slice z, v18-v26 in slice z+1*/ /* v0 v1 v2 v9 v10 v11 v18 v19 v20 v3 v4 v5 v12 v13 v14 v21 v22 v23 v6 v7 v8 v15 v16 v17 v24 v25 v26 z-1 z z+1 */ for(i=0;iimarr[ii]); gptr[ii] =(float *) mri_data_pointer(im); } baseoffset = 0; vptr = vptr0 = vptr1 = vptr2 = vptr3 = vptr5 = vptr6 = vptr7 = vptr8 = ar; tempmaskptr = maskptr; for(vz=0;vz=1, y>=2 */ /* z-1 slice */ v0 = v1; v1 = v2; v2 = *(++vptr0); v3 = v4; v4 = v5; v5 = *(++vptr1); v6 = v7; v7 = v8; v8 = *(++vptr2); /*z slice */ v9 = v10; v10 = v11; v11 = *(++vptr3); v12 = v13; v13 = v14; v14 = *(++vptr); v15 = v16; v16 = v17; v17 = *(++vptr5); /* z+1 slice */ v18 = v19; v19 = v20; v20 = *(++vptr6); v21 = v22; v22 = v23; v23 = *(++vptr7); v24 = v25; v25 = v26; v26 = *(++vptr8); /* slide differences for dudy */ dv0600 = dv0701; dv0701 = dv0802; dv1509 = dv1610; dv1610 = dv1711; dv2418 = dv2519; dv2519 = dv2620; /* slide sums for dudz */ sv1824 = sv1925; sv1925 = sv2026; sv0006 = sv0107; sv0107 = sv0208; dv2103 = dv2204; dv2204 = dv2305; } /* compute new sliding sums and differences */ dv0802 = v8 - v2; dv1711 = v17 - v11; dv2620 = v26 - v20; sv2026 = v20 + v26; sv0208 = v2 + v8; dv2204 = v22 - v4; /* v0 v1 v2 v9 v10 v11 v18 v19 v20 v3 v4 v5 v12 v13 v14 v21 v22 v23 v6 v7 v8 v15 v16 v17 v24 v25 v26 z-1 z z+1 */ /* du/dx across alternating planes left and right of current voxel */ /* corners of planes */ /* centers of edges of planes */ /* centers of sides - adjacent in x-1, x+1 in same slice */ /* dudx = a * (v2 + v20 + v8 + v26 - v0 - v18 - v6 -v24) + \ b * (v11 + v5 + v23 + v17 - v9 - v3 -v21 - v15) + \ c * (v14 - v12);*/ dudx = a * (sv0208 + sv2026 - sv0006 - sv1824) + \ b * (v11 + v5 + v23 + v17 - v9 - v3 -v21 - v15) + \ c * (v14 - v12); /* dudy = a * (v6 + v8 + v24 + v26 - v0 - v2 - v18 - v20) + \ b * (v7 + v15 + v17 + v25 - v1 - v9 - v11 - v19) + \ c * (v16 - v10) ; */ dudy = a * (dv0600 + dv0802 + dv2418 + dv2620) + \ b * (dv0701 + dv1509 + dv1711 + dv2519) + \ c * dv1610; /* dudz = a * (v18 + v20 + v24 + v26 - v0 - v2 - v6 - v8) + \ b * (v19 + v21 + v23 + v25 - v1 - v3 - v5 - v7) + \ c * (v22 - v4);*/ dudz = a * (sv1824 + sv2026 - sv0006 - sv0208) + \ b * (sv1925 + dv2103 + dv2305 - sv0107) + \ c * dv2204; if(prodflag) { *(gptr[0]) += dudx * dudx; /* sum gradient product components in output image array */ *(gptr[1]) += dudx * dudy; *(gptr[2]) += dudx * dudz; *(gptr[3]) += dudy * dudy; *(gptr[4]) += dudy * dudz; *(gptr[5]) += dudz * dudz; } else { *(gptr[0]) += dudx; /* sum gradient components in output image array */ *(gptr[1]) += dudy; *(gptr[2]) += dudz; } baseoffset++; for(ii=0;iiimarr[ii]); gptr[ii] =(float *) mri_data_pointer(im); } for(vi=0;vinx ; ny = SourceIm->ny; nz = SourceIm->nz ; nxyz = SourceIm->nxyz; nxy = nx * ny; yp1xp1 = nx + 1; yp1xm1 = nxm1 = nx - 1; nym1 = ny - 1; nzm1 = nz - 1; /* make new Image Array to hold gradients and then gradient products */ INIT_IMARR(Gradient_Im); for(i=0;iimarr[ii]); gptr[ii] = (float *) mri_data_pointer(im); } ar = mri_data_pointer(SourceIm); baseoffset = 0; vptr = vptr0 = vptr1 = vptr2 = vptr3 = vptr5 = vptr6 = vptr7 = vptr8 = ar; tempmaskptr = maskptr; #if 1 if(flag2D3D==2) { /* 2D option */ for(vz=0;vz=TINYNUMBER) *(gptr[0]) = dudx; /* sum gradient components in output image array */ /*else *gptr[0] = 0.0; */ /* already zeroed out when allocated */ } if(yflag) { dv0 = dv1; dv1 = dv2; dv2 = v8 - v2; dudy = a*(dv0 + dv2) + b* dv1; temp = fabs(dudy); if(temp>=TINYNUMBER) *(gptr[noutm1]) = dudy; /*else *(gptr[noutm1]) = 0.0;*/ /* already zeroed out when allocated */ } for(ii=0;ii=1, y>=2 */ /* z-1 slice */ v0 = v1; v1 = v2; v2 = *(++vptr0); v3 = v4; v4 = v5; v5 = *(++vptr1); v6 = v7; v7 = v8; v8 = *(++vptr2); /*z slice */ v9 = v10; v10 = v11; v11 = *(++vptr3); v12 = v13; v13 = v14; v14 = *(++vptr); v15 = v16; v16 = v17; v17 = *(++vptr5); /* z+1 slice */ v18 = v19; v19 = v20; v20 = *(++vptr6); v21 = v22; v22 = v23; v23 = *(++vptr7); v24 = v25; v25 = v26; v26 = *(++vptr8); /* slide differences for dudy */ if(yflag) { dv0600 = dv0701; dv0701 = dv0802; dv1509 = dv1610; dv1610 = dv1711; dv2418 = dv2519; dv2519 = dv2620; } /* slide sums for dudz */ if((zflag) || (xflag)) { sv1824 = sv1925; /* for dudx, dudz */ sv1925 = sv2026; /* for dudx, dudz */ sv0006 = sv0107; /* for dudx, dudz */ sv0107 = sv0208; /* for dudx, dudz */ sv2026 = v20 + v26; /* for dudx, dudz */ sv0208 = v2 + v8; /* for dudx, dudz */ if(zflag) { dv2103 = dv2204; dv2204 = dv2305; dv2204 = v22 - v4; /* for dudz */ } } } /* v0 v1 v2 v9 v10 v11 v18 v19 v20 v3 v4 v5 v12 v13 v14 v21 v22 v23 v6 v7 v8 v15 v16 v17 v24 v25 v26 z-1 z z+1 */ /* du/dx across alternating planes left and right of current voxel */ /* corners of planes */ /* centers of edges of planes */ /* centers of sides - adjacent in x-1, x+1 in same slice */ /* dudx = a * (v2 + v20 + v8 + v26 - v0 - v18 - v6 -v24) + \ b * (v11 + v5 + v23 + v17 - v9 - v3 -v21 - v15) + \ c * (v14 - v12);*/ if(xflag) { dudx = a * (sv0208 + sv2026 - sv0006 - sv1824) + \ b * (v11 + v5 + v23 + v17 - v9 - v3 -v21 - v15) + \ c * (v14 - v12); temp = fabs(dudx); if(temp>=TINYNUMBER) *(gptr[0]) = dudx; /* sum gradient components in output image array */ /*else *gptr[0] = 0.0; */ /* already zeroed out when allocated */ } /* dudy = a * (v6 + v8 + v24 + v26 - v0 - v2 - v18 - v20) + \ b * (v7 + v15 + v17 + v25 - v1 - v9 - v11 - v19) + \ c * (v16 - v10) ; */ if(yflag) { dv0802 = v8 - v2; /* for dudy */ dv1711 = v17 - v11; /* for dudy */ dv2620 = v26 - v20; /* for dudy */ dudy = a * (dv0600 + dv0802 + dv2418 + dv2620) + \ b * (dv0701 + dv1509 + dv1711 + dv2519) + \ c * dv1610; temp = fabs(dudy); if(temp>=TINYNUMBER) *(gptr[ybrik]) = dudy; /* sum gradient components in output image array */ /*else *gptr[0] = 0.0; */ /* already zeroed out when allocated */ } /* dudz = a * (v18 + v20 + v24 + v26 - v0 - v2 - v6 - v8) + \ b * (v19 + v21 + v23 + v25 - v1 - v3 - v5 - v7) + \ c * (v22 - v4);*/ if(zflag) { dudz = a * (sv1824 + sv2026 - sv0006 - sv0208) + \ b * (sv1925 + dv2103 + dv2305 - sv0107) + \ c * dv2204; temp = fabs(dudz); if(temp>=TINYNUMBER) *(gptr[noutm1]) = dudz; /* sum gradient components in output image array */ /*else *gptr[0] = 0.0; */ /* already zeroed out when allocated */ *(gptr[noutm1]) = dudz; } baseoffset++; for(ii=0;ii (b) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) x = min(x, (nx-1)); x = max(x,0); y = min(y, (ny-1)); y = max(y, 0); z = min(z, (nz-1)); z = max(z, 0); offset = nx*(z*ny+y) + x; /* put mask check here too */ if((maskptr!=NULL) && !(*(maskptr+offset))) /* if not in mask use i,j,k offset*/ offset = nx*(k*ny+j) + i; voxval = *(imptr+offset); /*define VOX_VAL(x,y,offset,nx, ny) \ (*((offset) + min(max((y),0),(ny-1))*(nx) + min(max((x),0),(nx-1)))<)*/ return(voxval); } /* Compute eigenvectors and eigenvalues for Gradient matrix */ MRI_IMARR *Eig_Gradient(MRI_IMARR *Gradient_Im, int flag2D3D, byte *maskptr) { MRI_IMARR *Eig_Im; MRI_IMAGE *im; byte *tempmaskptr; float *gptr[12]; int ii, jj, starti, endi; register float a1, a2, a3, aa2; double a13, rad, L1, L2, x11, x12, x21, x22; int nx, ny, nz, nxyz; float maxim, tempmax0, tempmax2; double almostzero; double aa[9], e[3]; int i; ENTRY("Eig_Gradient"); tempmaskptr = maskptr; im = Gradient_Im->imarr[0]; nx = im->nx; ny = im->ny; nz = im->nz; nxyz = im->nxyz; /* will use Gradient_Im structure and data space in place already for eigenvalues and eigenvectors ) */ if(flag2D3D==2) { starti = 3; endi = 6; } else { starti = 6; endi = 12; } /* for 2D, need 6 sub-briks in output mri_imarr-2 eigenvalues,4 vector components */ for(ii=starti;iiimarr[ii]); gptr[ii] = (float *) mri_data_pointer(im); } /* find max Sxx, Syy in gradients */ im = (Gradient_Im->imarr[0]); tempmax0 = Find_Max_Im(im, maskptr); /* max Sxx */ if(flag2D3D==2) im = (Gradient_Im->imarr[2]); else im = (Gradient_Im->imarr[3]); tempmax2 = Find_Max_Im(im, maskptr); /* max Syy */ if(tempmax0>tempmax2) maxim = tempmax0; else maxim = tempmax2; if(flag2D3D==3) { im = (Gradient_Im->imarr[5]); tempmax2 = Find_Max_Im(im, maskptr); /* max Szz */ if(tempmax2>maxim) maxim = tempmax2; } almostzero = maxim / 100000.0; for(ii=0;ii=a2) { *gptr[0] = L1; *gptr[1] = L2; *gptr[2] = x11; *gptr[3] = x12; *gptr[4] = x21; *gptr[5] = x22; } else { *gptr[0] = L2; *gptr[1] = L1; *gptr[2] = x21; *gptr[3] = x22; *gptr[4] = x11; *gptr[5] = x12; } } else { /* 3d flag */ aa[0] = *gptr[0]; aa[1] = *gptr[1]; aa[2] = *gptr[2]; aa[3] = *gptr[1]; aa[4] = *gptr[3]; aa[5] = *gptr[4]; aa[6] = *gptr[2]; aa[7] = *gptr[4]; aa[8] = *gptr[5]; symeig_double(3, aa, e); /* e has eigenvalues in result, aa has eigenvectors */ /* add check for small eigenvalues here */ /* reverse the order in gptr to give maximum value first */ *gptr[0] = e[2]; /* eigenvalues */ *gptr[1] = e[1]; *gptr[2] = e[0]; *gptr[3] = aa[6]; /* eigenvectors */ *gptr[4] = aa[7]; *gptr[5] = aa[8]; *gptr[6] = aa[3]; *gptr[7] = aa[4]; *gptr[8] = aa[5]; *gptr[9] = aa[0]; *gptr[10] = aa[1]; *gptr[11] = aa[2]; } } /* not masked */ for(jj=0;jjnxyz; gptr = (float *) mri_data_pointer(im); for(i=0;imax_im) max_im = t1; } } RETURN(max_im); } /* compute inverted eigenvalue matrix */ MRI_IMARR *Compute_Phi(MRI_IMARR *EV_Im, int flag2D3D, byte *maskptr) { MRI_IMARR *phi_Im; MRI_IMAGE *im; double c1 = 0.01f, c2 = -0.01f; /* c2 = -1.00,*/ double mc1 = 0.99, evensplit, secondsplit; double e1, e2,e3, e12, a, b, emax; /* e1me2;*/ float *gptr[3]; int nxyz, ii, jj, endi; byte *tempmaskptr; ENTRY("Compute_Phi"); if(flag2D3D==2) { evensplit = 0.5; secondsplit = 1.0; } else { evensplit = 1.0/3.0; secondsplit = 0.5; } endi = flag2D3D; im = EV_Im->imarr[0]; nxyz = im->nxyz; tempmaskptr = maskptr; /* replace first two eigenvalue sub-briks with phi values */ for(ii=0;iiimarr[ii]); gptr[ii] = (float *) mri_data_pointer(im); } /* Ding method phi1,2 = c/e1, c/e2 */ if(compute_method==0) { emax = Find_Max_Im(EV_Im->imarr[0], maskptr); a = emax / 100.0; b = 1.0 / a; for(ii=0;ii=a) e1 = 1/e1me2; else e1 = -9999.0; *gptr[0] = e1; *gptr[1] = 0.01; gptr[0]++; gptr[1]++; if(e1>emax) emax = e1; } im = (EV_Im->imarr[0]); gptr[0] = (float *) mri_data_pointer(im); for(ii=0;iiimarr[0]; nxyz = im->nxyz; tempmaskptr = maskptr; if(flag2D3D==2) endi = 6; else endi = 12; /* replace first three phi,eigenvector sub-briks with Dxx,Dxy,Dyy values */ for(ii=0;iiimarr[ii]); gptr[ii] = (float *) mri_data_pointer(im); } if(flag2D3D==2) { for(ii=0;iidblk ) ; EDIT_dset_items( new_dset , ADN_malloc_type , DATABLOCK_MEM_MALLOC , /* store in memory */ ADN_prefix , new_prefix , ADN_label1 , new_prefix , ADN_nvals , Imptr->num , /* # sub-bricks */ ADN_ntt , 0 , /* # time points */ ADN_datum_all , MRI_float , /* atomic datum */ ADN_none ) ; THD_init_datablock_keywords( new_dset->dblk ) ; THD_init_datablock_stataux( new_dset->dblk ) ; /* new_dset->dblk->brick = Imptr;*/ /* update pointer to data */ new_dset->dblk->nvals = Imptr->num; for(i=0;inum; i++) { /* for each sub-brik in dataset */ /* Imptr->imarr[i]->kind = MRI_float;*/ EDIT_substitute_brick(new_dset,i, MRI_float, mri_data_pointer(Imptr->imarr[i])); } RETURN(new_dset); } /* compute maximum and print maximum of each sub-brik in MRI_IMARR data */ /* for debugging */ void Compute_IMARR_Max(MRI_IMARR *Imptr) { int i,j,nxyz; float tmax,tt; float *gptr; MRI_IMAGE *im; for(i=0;inum;i++) { /* for each sub-brik */ tmax = TINYNUMBER; im = Imptr->imarr[i]; gptr = (float *) mri_data_pointer(im); nxyz = im->nxyz; for(j=0;jtmax) tmax = tt; } printf("max brik %d = %f\n", i, tmax); } }