/******************* 3danisosmooth.c *************************************/ /* Author: Daniel Glen, 13 Jun 2005 */ /* Smooths volumes using an anisotropic smoothing technique */ /* Intended for DWI images, it first computes a tensor of structure */ /* of DWI volumes for the purpose of anisotropic smoothing of the */ /* image. */ /* This D tensor is then used as basis for smoothing along directionality of */ /* the original DWI image. */ /* Although originally intended for DWI data, it can be applied to */ /* other types of data also */ /* The method can be applied in either 2D or 3D */ /**********************************************************************/ #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 "matrix.c"*/ #include "mrilib.h" #define TINYNUMBER 1E-10 #define SMALLNUMBER 1E-4 static double Dmean, Dmax, DeltaT; static char prefix[THD_MAX_PREFIX] = "SmoothAni"; static NI_stream ns = NULL; int compute_method = 0; /* use Ding's method to compute phi values */ int matchorig = 0; /* match original range of data - off by default */ float deltatflag = -1.0; /* compute pseudotime step or use specific value */ int noneg = 0; /* allow only non-negative values - off by default */ float NegVal = 0.0f; /* Value to replace negative voxels */ float edgefraction = 0.5; /* default fraction of anisotropic image to add */ float *brikmax, *brikmin; /* array of maximum and minimum values for each sub-brick in volume */ extern float aniso_sigma1, aniso_sigma2; #define Smooth_WriteCheckWaitMax 2000 #define Smooth_WriteCheckWait 400 #define START_PORT 4444 /* port range for aiv communications */ #define MAX_PORT 4544 THD_3dim_dataset * Copy_dset_to_float(THD_3dim_dataset * dset , char * new_prefix ); static void Smooth_dset_tensor(THD_3dim_dataset *tempdset, THD_3dim_dataset *structtensor, int flag2D3D, byte *maskptr, int save_tempdsets_flag); static int Smooth_Open_Stream(int port); static int Smooth_Show_Image(float *far, int nx, int ny); static int Show_dset_slice(THD_3dim_dataset *dset); static void Compute_Dstats(THD_3dim_dataset *structtensor,int flag2D3D, byte *maskptr); static void Compute_Ematrix(THD_3dim_dataset *structtensor, int flag2D3D, byte *maskptr); static void Compute_Gmatrix(MRI_IMARR *Flux_Im, int flag2D3D, byte *maskptr); static void Compute_Smooth(THD_3dim_dataset *udset, int outbrik,THD_3dim_dataset *tempdset,MRI_IMARR *G_Im,int flag2D3D, byte *maskptr); static void Compute_Flux(MRI_IMARR *Gradient_im, THD_3dim_dataset *structtensor, int flag2D3D, byte *maskptr); static void Update_Brik(THD_3dim_dataset *indset, THD_3dim_dataset *outdset, int brickn); static void Test_data(THD_3dim_dataset *structtensor); static void Fix_mask(byte *maskptr, THD_3dim_dataset *dset, int flag2D3D); static int Check_Neighbors_3D(byte *mptr, int nx, int nxy); static int Check_Neighbors_2D(byte *mptr, int nx); static void Compute_3dAS_Max(THD_3dim_dataset *dset, byte *maskptr, float *asfmax, float *asfmin); static void Compute_3dAS_Max_Brick(THD_3dim_dataset *dset, byte *maskptr, int bricki, float *asfmax, float *asfmin); static void AS_scale_float_dset(THD_3dim_dataset *dset, byte *maskptr, float fratio); extern THD_3dim_dataset * DWIstructtensor(THD_3dim_dataset * DWI_dset, int flag2D3D, byte *maskptr, int smooth_flag, int save_tempdsets_flag, float *cen); extern MRI_IMARR *Compute_Gradient_Matrix(THD_3dim_dataset *DWI_dset, int flag2D3D, byte *maskptr, int prodflag, int smoothflag, float smooth_factor); extern MRI_IMARR *Compute_Gradient_Matrix_Im(MRI_IMAGE *SourceIm, int flag2D3D, byte *maskptr, int xflag, int yflag, int zflag); 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 void Compute_IMARR_Max(MRI_IMARR *Imptr); extern void Save_imarr_to_dset(MRI_IMARR *Imarr_Im, THD_3dim_dataset *base_dset, char *dset_name); extern void set_with_diff_measures(int v); extern int get_with_diff_measures(void); /*! compute the overall minimum and maximum voxel values for a dataset */ int main( int argc , char * argv[] ) { THD_3dim_dataset * dset , * udset, * out_dset ; /* input and output datasets */ THD_3dim_dataset * structtensor; /* structure tensor dataset */ THD_3dim_dataset * mask_dset ; int nxyz, i, datum, nbriks; int afnitalk_flag = 0; int nopt = 1; byte *maskptr = NULL; int automask = 0; int flag2D3D = 0; int port, ret; char tempstring[256]; int iters = 10; int mmvox = 0; int save_tempdsets_flag = 0; int smooth_flag = 1; MRI_IMAGE *data_im = NULL; int output_datum = MRI_float; /* default output data type */ float *fptr; void *out_ptr; MRI_IMARR *fim_array; MRI_IMAGE *fim; float fimfac, cen[3]; float as_fmax, as_fmin; /* max and min values in original dataset */ /*----- Read command line -----*/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3danisosmooth [options] dataset\n" "Smooths a dataset using an anisotropic smoothing technique.\n\n" "The output dataset is preferentially smoothed to preserve edges.\n\n" "Options :\n" " -prefix pname = Use 'pname' for output dataset prefix name.\n" " -iters nnn = compute nnn iterations (default=10)\n" " -2D = smooth a slice at a time (default)\n" " -3D = smooth through slices. Can not be combined with 2D option\n" " -mask dset = use dset as mask to include/exclude voxels\n" " -automask = automatically compute mask for dataset\n" " Can not be combined with -mask\n" " -viewer = show central axial slice image every iteration.\n" " Starts aiv program internally.\n" " -nosmooth = do not do intermediate smoothing of gradients\n" " -sigma1 n.nnn = assign Gaussian smoothing sigma before\n" " gradient computation for calculation of structure tensor.\n" " Default = 0.5\n" " -sigma2 n.nnn = assign Gaussian smoothing sigma after\n" " gradient matrix computation for calculation of structure tensor.\n" " Default = 1.0\n" " -deltat n.nnn = assign pseudotime step. Default = 0.25\n" " -savetempdata = save temporary datasets each iteration.\n" " Dataset prefixes are Gradient, Eigens, phi, Dtensor.\n" " Ematrix, Flux and Gmatrix are also stored for the first sub-brick.\n" " Where appropriate, the filename is suffixed by .ITER where \n" " ITER is the iteration number. Existing datasets will get overwritten.\n" " -save_temp_with_diff_measures: Like -savetempdata, but with \n" " a dataset named Diff_measures.ITER containing FA, MD, Cl, Cp, \n" " and Cs values.\n" " -phiding = use Ding method for computing phi (default)\n" " -phiexp = use exponential method for computing phi\n" " -noneg = set negative voxels to 0\n" " -setneg NEGVAL = set negative voxels to NEGVAL\n" " -edgefraction n.nnn = adjust the fraction of the anisotropic\n" " component to be added to the original image. Can vary between\n" " 0 and 1. Default =0.5\n" " -datum type = Coerce the output data to be stored as the given type\n" " which may be byte, short or float. [default=float]\n" " -matchorig - match datum type and clip min and max to match input data\n" " -help = print this help screen\n\n" "References:\n" " Z Ding, JC Gore, AW Anderson, Reduction of Noise in Diffusion\n" " Tensor Images Using Anisotropic Smoothing, Mag. Res. Med.,\n" " 53:485-490, 2005\n" " J Weickert, H Scharr, A Scheme for Coherence-Enhancing\n" " Diffusion Filtering with Optimized Rotation Invariance,\n" " CVGPR Group Technical Report at the Department of Mathematics\n" " and Computer Science,University of Mannheim,Germany,TR 4/2000.\n" " J.Weickert,H.Scharr. A scheme for coherence-enhancing diffusion\n" " filtering with optimized rotation invariance. J Visual\n" " Communication and Image Representation, Special Issue On\n" " Partial Differential Equations In Image Processing,Comp Vision\n" " Computer Graphics, pages 103-118, 2002.\n" " Gerig, G., Kubler, O., Kikinis, R., Jolesz, F., Nonlinear\n" " anisotropic filtering of MRI data, IEEE Trans. Med. Imaging 11\n" " (2), 221-232, 1992.\n\n" ) ; printf("\n" MASTER_SHORTHELP_STRING ) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3danisosmooth main"); machdep(); AFNI_logger("3danisosmooth",argc,argv); PRINT_VERSION("3danisosmooth"); AUTHOR("Daniel Glen"); /* initSaturn("", 1, 0, 0, 9); startSaturn();*/ datum = MRI_float; compute_method = -1; /* detect multiple or default selection of compute_method */ deltatflag = -1.0; /* pseudo-time step */ while( nopt < argc && argv[nopt][0] == '-' ){ if( strcmp(argv[nopt],"-prefix") == 0 ){ if (++nopt >= argc) { ERROR_exit("Error - prefix needs an argument!"); } MCW_strncpy (prefix, argv[nopt], THD_MAX_PREFIX); /* change name from default prefix */ if (!THD_filename_ok (prefix)) { ERROR_exit("Error - %s is not a valid prefix!", prefix); } nopt++; continue; } if (strcmp (argv[nopt], "-automask") == 0) { if(maskptr != NULL){ ERROR_exit("ERROR: can't use -mask with -automask!"); } automask = 1; nopt++; continue; } if( strcmp(argv[nopt],"-mask") == 0 ){ if( automask ){ ERROR_exit("ERROR: can't use -mask with -automask!"); } mask_dset = THD_open_dataset(argv[++nopt]) ; if( mask_dset == NULL ){ ERROR_exit("ERROR: can't open -mask dataset!"); } if( maskptr != NULL ){ ERROR_exit("ERROR: can't have 2 -mask options!"); } maskptr = THD_makemask( mask_dset , 0 , 1.0,-1.0 ) ; mmvox = DSET_NVOX( mask_dset ) ; DSET_delete(mask_dset) ; nopt++ ; continue ; } if (strcmp (argv[nopt], "-viewer") == 0) { afnitalk_flag = 1; nopt++; continue; } if (strcmp (argv[nopt], "-2D") == 0) { if(flag2D3D==0) flag2D3D = 2; else { ERROR_exit("ERROR: can't select both 2D and 3D flags"); } nopt++; continue; } if (strcmp (argv[nopt], "-3D") == 0) { if(flag2D3D==0) flag2D3D = 3; else { ERROR_exit("can't select both 2D and 3D flags"); } nopt++; continue; } if (strcmp (argv[nopt], "-nosmooth") == 0) { smooth_flag = 0; nopt++; continue; } if (strcmp (argv[nopt], "-savetempdata") == 0) { save_tempdsets_flag = 1; nopt++; continue; } if (strcmp (argv[nopt], "-save_temp_with_diff_measures") == 0) { save_tempdsets_flag = 1; set_with_diff_measures(1); nopt++; continue; } if( strcmp(argv[nopt],"-iters") == 0 ){ if(++nopt >=argc ){ ERROR_exit("Error - need an argument after -iters!"); } iters = strtol(argv[nopt], NULL, 10); if ((iters <1)||(iters>200)) { ERROR_exit("Error - iters must be between 1 and 200"); } nopt++; continue; } if( strcmp(argv[nopt],"-deltat") == 0 ){ if(++nopt >=argc ){ ERROR_exit("Error - need an argument after -deltat!"); } deltatflag = atof(argv[nopt]); if (deltatflag <0) { ERROR_exit( "Error - deltatflag must be positive!"); } nopt++; continue; } if( strcmp(argv[nopt],"-sigma1") == 0 ){ if(++nopt >=argc ){ ERROR_exit("Error - need an argument after -sigma1!"); } aniso_sigma1 = atof(argv[nopt]); if (aniso_sigma1 <0) { ERROR_exit( "Error - sigma1 must be positive!"); } nopt++; continue; } if( strcmp(argv[nopt],"-sigma2") == 0 ){ if(++nopt >=argc ){ ERROR_exit("Error - need an argument after -sigma2!"); } aniso_sigma2 = atof(argv[nopt]); if (aniso_sigma2 <0) { ERROR_exit( "Error - sigma2 must be positive!"); } nopt++; continue; } if( strcmp(argv[nopt],"-phiding") == 0 ){ if(compute_method!=-1) { ERROR_exit("Error - can not specify two compute methods!"); } compute_method = 0; nopt++; continue; } if( strcmp(argv[nopt],"-phiexp") == 0 ){ if(compute_method!=-1) { ERROR_exit("Error - can not specify two compute methods!"); } compute_method = 1; nopt++; continue; } if( strcmp(argv[nopt],"-noneg") == 0 ){ noneg = 1; nopt++; continue; } if( strcmp(argv[nopt],"-setneg") == 0 ){ if(++nopt >=argc ){ ERROR_exit("Error - need an argument after -setneg!"); } noneg = 1; NegVal = atof(argv[nopt]); nopt++; continue; } if( strcmp(argv[nopt],"-matchorig") == 0 ){ matchorig = 1; nopt++; continue; } if( strcmp(argv[nopt],"-edgefraction") == 0 ){ if(++nopt >=argc ){ ERROR_exit("Error - need an argument after -edgefraction!"); } edgefraction = atof(argv[nopt]); if ((edgefraction <0) || (edgefraction > 1)) { ERROR_exit( "Error - edgefraction must be between 0 and 1!"); } nopt++; continue; } /**** -datum type ****/ if( strncasecmp(argv[nopt],"-datum",6) == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -datum!\n") ; if( strcasecmp(argv[nopt],"short") == 0 ){ output_datum = MRI_short ; } else if( strcasecmp(argv[nopt],"float") == 0 ){ output_datum = MRI_float ; } else if( strcasecmp(argv[nopt],"byte") == 0 ){ output_datum = MRI_byte ; } else if( strcasecmp(argv[nopt],"complex") == 0 ){ /* not listed in help */ output_datum = MRI_complex ; } else { ERROR_exit("-datum of type '%s' not supported in 3danisosmooth!\n",argv[nopt]) ; } nopt++ ; continue ; /* go to next arg */ } ERROR_exit( "Error - unknown option %s", argv[nopt]); } /*----- read input dataset -----*/ if( nopt >= argc ){ ERROR_exit("No input dataset!?"); } dset = THD_open_dataset( argv[nopt] ) ; if( !ISVALID_DSET(dset) ){ ERROR_exit("Can't open dataset %s",argv[nopt]); } nxyz = DSET_NVOX(dset) ; if( maskptr != NULL && mmvox != nxyz ){ ERROR_exit("Mask and input datasets not the same size!") ; } if(automask && (maskptr == NULL )){ maskptr = THD_automask( dset ) ; } if(flag2D3D == 0) flag2D3D = 2; /* make default 2D processing for speed */ if(maskptr) Fix_mask(maskptr, dset, flag2D3D); /* set mask edge voxels to 2, all others to 1 */ if(afnitalk_flag) { /* set up viewer */ port = START_PORT; ret = 0; while ((ret==0) && (portkind==MRI_float) { /* if data is already float, do not copy */ udset = dset; EDIT_dset_items( dset , ADN_malloc_type , DATABLOCK_MEM_MALLOC , /* store in memory */ ADN_prefix , prefix , ADN_label1 , prefix , ADN_datum_all , MRI_float , ADN_none ) ; } else { #endif if(matchorig) { data_im = DSET_BRICK (dset, 0); /* assume all data is same type as first sub-brik */ output_datum = data_im->kind; /* match original type of data */ } if(output_datum == MRI_float) udset = Copy_dset_to_float(dset, prefix); else udset = Copy_dset_to_float(dset, "ttttani"); /* not actually written to disk */ if(matchorig) { /* if user wants to match original data range */ brikmax = malloc(dset->dblk->nvals*sizeof(float)); brikmin = malloc(dset->dblk->nvals*sizeof(float)); for(i=0;idblk->nvals;i++) { Compute_3dAS_Max_Brick(udset, maskptr, i, &as_fmax, &as_fmin); brikmax[i] = as_fmax; brikmin[i] = as_fmin; } } tross_Copy_History (dset, udset); THD_delete_3dim_dataset(dset , False ) ; /* do not need original anymore */ /* }*/ if(afnitalk_flag) { Show_dset_slice(udset); /* show mid-slice in middle brik */ } for(i=0;idblk->nvals; out_dset = EDIT_empty_copy(udset) ; tross_Copy_History (udset, out_dset); EDIT_dset_items( out_dset , ADN_malloc_type , DATABLOCK_MEM_MALLOC , /* store in memory */ ADN_prefix , prefix , ADN_label1 , prefix , ADN_datum_all , output_datum , ADN_none ) ; /* make new Image Array */ INIT_IMARR(fim_array); for(i=0;idblk->brick = fim_array; /* update pointer to data */ for(i=0;idblk->nvals ; iv++ ){ /*- get sub-brick -*/ fim = THD_extract_float_brick( iv , dset ) ; if( fim == NULL ) { ERROR_exit("*Error - can not allocated float dset"); } ADDTO_IMARR(fim_array, fim); } float_dset->dblk->brick = fim_array; /* update pointer to data */ for(iv=0;ivdblk->nvals;iv++) DSET_BRICK_FACTOR(float_dset, iv) = 0.0; RETURN(float_dset); } /*! open aiv / AFNIRT stream */ static int Smooth_Open_Stream(port) int port; { int nn, Wait_tot; char streamname[256]; ENTRY("Smooth_Open_Stream"); sprintf(streamname, "tcp:localhost:%d", port); ns = NI_stream_open(streamname, "w"); if(ns==0) { /* could not create stream */ return(1); } Wait_tot = 0; /* check connection */ while(Wait_tot < Smooth_WriteCheckWaitMax){ nn = NI_stream_writecheck( ns , Smooth_WriteCheckWait) ; if( nn == 1 ){ RETURN(0) ; } if( nn < 0 ){ ns = NULL; RETURN(1); } Wait_tot += Smooth_WriteCheckWait; } RETURN(1); /* no connection */ } /*! show the middle brik, middle slice */ static int Show_dset_slice(THD_3dim_dataset *dset) { int mid_brik, nx, ny, nz; float *far=NULL; THD_dataxes * daxes=NULL ; MRI_IMAGE *data_im=NULL; int ret; ENTRY("Show_dset_slice"); mid_brik = (dset->dblk->nvals)/2 ; data_im = DSET_BRICK(dset, mid_brik); daxes = dset->daxes ; nx = daxes->nxx ; ny = daxes->nyy ; nz = daxes->nzz ; far = (float *) mri_data_pointer(data_im); nz = (nz-1) / 2; /* get middle slice in integer */ far += nx*ny*nz; /* show middle brik, middle Z slice */ ret = Smooth_Show_Image(far,nx,ny); RETURN(ret); } /*! create or update image window with the new data */ static int Smooth_Show_Image(far, nx, ny) float *far; int nx, ny; { MRI_IMAGE *im; /* char default_name[64] = "3danisosmooth image";*/ NI_element *nel; ENTRY("Smooth_Show_Image"); /*-- compute number of bytes per slice, and per image transmission --*/ im = mri_new_vol_empty(nx, ny , 1, MRI_float); /* 1 slice volume */ mri_fix_data_pointer(far, im); /* set image to float pointer */ /* im->name = malloc(strlen(default_name));*/ im->name = NULL; im->kind = MRI_float; /* sprintf(im->name, "%s", default_name);*/ nel = mri_to_niml(im); NI_write_element(ns, nel, NI_BINARY_MODE); NI_free_element(nel); mri_clear_data_pointer(im); mri_free(im); RETURN(0); } /*! Smooth dataset image using image diffusion tensor If (save_tempdsets_flag) then temp datasets are saved with a suffix of .DD where DD is the iteration number, which is save_tempdsets_flag-1 */ static void Smooth_dset_tensor(THD_3dim_dataset *udset, THD_3dim_dataset *structtensor, int flag2D3D, byte *maskptr, int save_tempdsets_flag) { MRI_IMARR *Gradient_Im; int nbriks,i; int sublist[2]; char obuff[128]={""}; THD_3dim_dataset *tempdset; ENTRY("Smooth_dset_tensor"); /* find mean and max of (Dxx+Dyy)*/ Compute_Dstats(structtensor,flag2D3D, maskptr); /* deviation from mean, can use structtensor space */ /* printf("Compute Ematrix\n");*/ Compute_Ematrix(structtensor, flag2D3D, maskptr); if(save_tempdsets_flag) { snprintf(obuff, 127,"Ematrix.%02d", save_tempdsets_flag-1); Save_imarr_to_dset(structtensor->dblk->brick,structtensor, obuff); } /* Compute_IMARR_Max(structtensor->dblk->brick);*/ nbriks = udset->dblk->nvals; sublist[0] = 1; for(i=0;inxyz;i++) { if(maskptr && !(*tempmaskptr++)) { dx++; dy++; } else { nvox++; ts0 = *dx + *dy; dx++; dy++; if(ts0>s1) s1 = ts0; /* update max(Dxx + Dyy)*/ s0 += ts0; /* get sum of Dxx + Dyy */ } } } else { /* 3D option */ for(i=0;inxyz;i++) { if(maskptr && !(*tempmaskptr++)) { dx++; dy++; dz++; } else { nvox++; ts0 = *dx + *dy + *dz; ts1 = *dx; ts2 = *dy; ts3 = *dz; if(isnan(ts1)||isnan(ts2)||isnan(ts3)) { WARNING_message("D matrix has elements that are not numbers (NAN) at point %d", i); WARNING_message("ts1 %g ts2 %g ts3 %g", ts1, ts2, ts3); } dx++; dy++; dz++; if(ts0>s1) s1 = ts0; /* update max(Dxx + Dyy + Dzz)*/ s0 += ts0; /* get sum of Dxx + Dyy + Dzz */ } } } /* if(maskptr!=NULL) nvox = data_im->nxyz;*/ if(nvox==0) Dmean = 0.0; else Dmean = s0 / (flag2D3D * nvox); /* Dmean = 1/2 or 1/3 mean(Dxx+Dyy(+Dzz)) */ if(deltatflag==-1.0) { /* if no user setting for delta T */ Dmax = s1; /* DeltaT = 1.0/7.0; */ DeltaT = Dmax / 4; /* set pseudo-time step to Dmax/4 */ } else DeltaT = deltatflag; /*printf("s0 %g, nvox %d, s1 %g, ts0 %g\n", s0, nvox, s1, ts0); printf("Dmean %g Dmax %g DeltaT %g\n", Dmean, Dmax, DeltaT);*/ EXRETURN; } /*! deviation from mean, can use structtensor space */ static void Compute_Ematrix(THD_3dim_dataset *structtensor, int flag2D3D, byte *maskptr) { int i; MRI_IMAGE *data_im = NULL; float *e0, *e2, *e3, tempe0, tempe2; byte *tempmaskptr; ENTRY("Compute_Ematrix"); tempmaskptr = maskptr; data_im = DSET_BRICK(structtensor, 0); e0 = (float *) mri_data_pointer(data_im); /* e1 = Dxy, so just leave in place at second sub-brick */ /* for 3D, we also leave 3rd, 5th sub-brick in place */ if(flag2D3D==2) { data_im = DSET_BRICK(structtensor, 2); e2 = (float *) mri_data_pointer(data_im); for(i=0;inxyz;i++) { if(maskptr && !(*tempmaskptr++)) { *e0 = 0.0; *e2 = 0.0; } else { tempe0 = *e0; tempe2 = *e2; *e0 = tempe0 - Dmean; /* e0 = Dxx-Dmean */ *e2 = tempe2 - Dmean; /* e2 = Dyy-Dmean */ } e0++; e2++; } } else { data_im = DSET_BRICK(structtensor, 3); e2 = (float *) mri_data_pointer(data_im); data_im = DSET_BRICK(structtensor, 5); e3 = (float *) mri_data_pointer(data_im); for(i=0;inxyz;i++) { if(maskptr && !(*tempmaskptr++)) { *e0 = 0.0; *e2 = 0.0; *e3 = 0.0; } else { *e0 = *e0 - Dmean; /* e0 = Dxx-Dmean */ *e2 = *e2 - Dmean; /* e2 = Dyy-Dmean */ *e3 = *e3 - Dmean; /* e3 = Dzz-Dmean */ } e0++; e2++; e3++; } } EXRETURN; } /*! Compute flux */ static void Compute_Flux(MRI_IMARR * Gradient_Im, THD_3dim_dataset *structtensor, int flag2D3D, byte *maskptr) { int i; MRI_IMAGE *data_im = NULL; float *e0,*e1,*e2, *e3, *e4, *e5, *Gx, *Gy, *Gz; double Jx, Jy, Jz; byte *tempmaskptr; ENTRY("Compute_Flux"); tempmaskptr = maskptr; data_im = DSET_BRICK(structtensor, 0); e0 = (float *) mri_data_pointer(data_im); data_im = DSET_BRICK(structtensor, 1); e1 = (float *) mri_data_pointer(data_im); data_im = DSET_BRICK(structtensor, 2); e2 = (float *) mri_data_pointer(data_im); Gx = (float *) mri_data_pointer(Gradient_Im->imarr[0]); Gy = (float *) mri_data_pointer(Gradient_Im->imarr[1]); if(flag2D3D==2) { for(i=0;inxyz;i++) { if(maskptr && !(*tempmaskptr++)) { *Gx = 0.0; *Gy = 0.0; } else { Jx = (*e0 * *Gx) + (*e1 * *Gy); /* Jx = Exx * du/dx + Exy * du/dy */ Jy = (*e1 * *Gx) + (*e2 * *Gy); /* Jy = Exy * du/dx + Eyy * du/dy */ *Gx = Jx; /* replace gradient values with flux values */ *Gy = Jy; } Gx++; Gy++; e0++; e1++; e2++; } } else { data_im = DSET_BRICK(structtensor, 3); e3 = (float *) mri_data_pointer(data_im); data_im = DSET_BRICK(structtensor, 4); e4 = (float *) mri_data_pointer(data_im); data_im = DSET_BRICK(structtensor, 5); e5 = (float *) mri_data_pointer(data_im); Gz = (float *) mri_data_pointer(Gradient_Im->imarr[2]); for(i=0;inxyz;i++) { if(maskptr && !(*tempmaskptr++)) { *Gx = 0.0; *Gy = 0.0; *Gz = 0.0; } else { Jx = (*e0 * *Gx) + (*e1 * *Gy) + (*e2 * *Gz); /* Jx = Exx * du/dx + Exy * du/dy + Exz * du/dz*/ Jy = (*e1 * *Gx) + (*e3 * *Gy) + (*e4 * *Gz); /* Jy = Exy * du/dx + Eyy * du/dy + Eyz * du/dz*/ Jz = (*e2 * *Gx) + (*e4 * *Gy) + (*e5 * *Gz); /* Jz = Exz * du/dx + Eyz * du/dy + Ezz * du/dz*/ *Gx = Jx; /* replace gradient values with flux values */ *Gy = Jy; *Gz = Jz; } Gx++; Gy++; Gz++; e0++; e1++; e2++; e3++; e4++; e5++; } } EXRETURN; } /*! Compute anisotropic component of smoothing, G */ static void Compute_Gmatrix(MRI_IMARR * Flux_Im, int flag2D3D, byte *maskptr) { /* put in Flux_Im space - first sub-brik */ /* compute gradient of Jx, Jy (first two sub-briks) */ /* G = dJx/dx + dJy/dy */ /* for 3D compute gradient of Jx, Jy, Jz */ /* G = dJx/dx + dJy/dy */ int i, nxyz; float *dJx, *dJy, *dJz, *Gptr; MRI_IMAGE *data_im; MRI_IMARR *tempimarr0, *tempimarr1, *tempimarr2=NULL; byte *tempmaskptr; ENTRY("Compute_Gmatrix"); tempmaskptr = maskptr; data_im = Flux_Im->imarr[0]; Gptr = (float *) mri_data_pointer(data_im); nxyz = data_im->nxyz; tempimarr0 = Compute_Gradient_Matrix_Im(data_im, flag2D3D, maskptr,1,0,0); /* dJx/dx */ data_im = Flux_Im->imarr[1]; tempimarr1 = Compute_Gradient_Matrix_Im(data_im, flag2D3D, maskptr,0,1,0); /* dJy/dy */ dJx = (float *) mri_data_pointer(tempimarr0->imarr[0]); dJy = (float *) mri_data_pointer(tempimarr1->imarr[0]); dJz = dJy; /* if unused pointer - faster than checking on increment */ if(flag2D3D==3) { data_im = Flux_Im->imarr[2]; tempimarr2 = Compute_Gradient_Matrix_Im(data_im, flag2D3D, maskptr,0,0,1); /* dJz/dz */ dJz = (float *) mri_data_pointer(tempimarr2->imarr[0]); } for(i=0;idaxes ; nx = daxes->nxx ; ny = daxes->nyy ; nz = daxes->nzz ; nbriks = tempdset->dblk->nvals; for(i=0;iimarr[0]); /* reset G matrix pointer back to beginning */ tempmaskptr = maskptr; /* reset mask pointer */ for(j=0;jnx; ny = data_im->ny; nz = data_im->nz; nxyz = data_im->nxyz; nxy = nx * ny; /* precompute offsets for each stencil point relative to the center point */ nxm1 = nx - 1; nym1 = ny - 1; nzm1 = nz - 1; baseoffset = 0; data_im = DSET_BRICK (tempdset, 0); /* set pointer to the 0th sub-brik of the dataset */ ar = (float *) mri_data_pointer(data_im); /* Gptr points to current voxel */ Gvalptr = ar2 =(float *) mri_data_pointer(G_Im->imarr[0]); /*set G matrix pointer*/ data_im = DSET_BRICK(udset, outbrik); /* update output dataset here */ tempptr = (float *) mri_data_pointer(data_im); /* put calculated values here in output dataset */ tempmaskptr = maskptr; /* reset mask pointer */ if(flag2D3D==2) { for(vz=0;vzas_fmax) /* peg values to max and min of original values for user option*/ Fval = as_fmax; if(Fval=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); sv00061824 = sv01071925; sv01071925 = sv02082026; sv0915 = sv1016; sv1016 = sv1117; sv0321 = sv0422; sv0422 = sv0523; } /* 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 */ /* precomputing sums not only avoids redoing additions but also resetting voxel values not on sliding edge */ /* we only need to update voxels on right edge v2, v5, v8, v11, v14, v17, v20, v23, v26 */ /* and update v12, v13 */ sv02082026 = v2 + v8 + v20 + v26; sv1117 = v11 + v17; sv0523 = v5 + v23; /* multiply by 'a' four voxel values in current slice and in centers of slices before and after current slice */ Fval = a * (v12 + v14 + sv1016 + sv0422); /*Fval = a * (v12 + v14 + v10 + v16 + v4 + v22);*/ /* 'b' * corners of kernel stencil in current slice and centers of edges on previous and following slices */ Fval += b * (sv0915 + sv1117 + sv01071925 + sv0321 + sv0523); /*Fval += b * (v9 + v11 + v15 + v17 + v1 + v3 + v5 + v7 + v19 + v21 + v23 + v25);*/ /* 'c' * corners of kernel stencil on previous and following slices */ Fval += c * (sv00061824 + sv02082026); /*Fval += c * (v0 + v2 + v6 + v8 + v18 + v20 + v24 + v26);*/ /* 'd' * voxel value at current point only */ Fval += d * v13; /* scale by Dmean */ Fval *= Dmean; Fval = v13 + DeltaT * ((Fval*Ffrac) + (*Gvalptr*Gfrac)); if((noneg)&&(Fval<0.0f)) Fval = NegVal; else { if(matchorig) { if(Fval>as_fmax) /* peg values to max and min of original values for user option*/ Fval = as_fmax; if(Fvaldaxes ; nx = daxes->nxx ; ny = daxes->nyy ; nz = daxes->nzz ; nbriks = tempdset->dblk->nvals; for(i=0;iimarr[0]); /* reset G matrix pointer back to beginning */ tempmaskptr = maskptr; /* reset mask pointer */ for(j=0;jdaxes ; nx = daxes->nxx ; ny = daxes->nyy ; nz = daxes->nzz ; nxy = nx * ny; nxyz = nxy*nz; nxyz1 = nxyz2 = 0; if(flag2D3D==2) { for(kk=0;kk0) && (jj<(ny-1)) && (ii>0) && (ii0)&&(kk<(nz-1)) && (jj>0) && (jj<(ny-1)) && (ii>0) && (iinxyz; in_ar = (float *) mri_data_pointer(data_im); /* in_ar is pointer to data */ data_im = DSET_BRICK(outdset, brickn); out_ar = (float *) mri_data_pointer(data_im); /* out_ar is pointer to output data */ memcpy(out_ar, in_ar, nxyz*sizeof(MRI_float)); EXRETURN; } static void Test_data(THD_3dim_dataset *indset) { int i, j, nxyz; MRI_IMAGE *data_im; float *in_ar, uval; data_im = DSET_BRICK (indset, 0); /* 1st sub-brik of the input dataset */ nxyz = data_im->nxyz; for(i=0;i<3;i++) { if(i==1) uval = 0.0; /* fill 2nd sub-brik with 0 */ if(i==0) uval = 1.0; /* fill 1st sub-brik with 1 */ if(i==2) uval = 1;/* fill 3rd sub-brik with 1 */ data_im = DSET_BRICK (indset, i); /* 1st sub-brik of the input dataset */ in_ar = (float *) mri_data_pointer(data_im); /* in_ar is pointer to data */ for(j=0;j (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); } /*! find min and max of possibly masked dataset */ static void Compute_3dAS_Max(THD_3dim_dataset *dset, byte *maskptr, float *asfmax, float *asfmin) { int i, j, nbriks; MRI_IMAGE *data_im = NULL; float *fptr; float ts0; byte *tempmaskptr; ENTRY("Compute_3dAS_Max"); tempmaskptr = maskptr; *asfmin = 1E38; *asfmax = -1E38; nbriks = dset->dblk->nvals; for(i=0;inxyz;j++) { if(maskptr && !(*tempmaskptr++)) { fptr++; } else { ts0 = *fptr++; if(ts0>*asfmax) *asfmax = ts0; /* update max */ if(ts0<*asfmin) *asfmin = ts0; /* update min */ } } } EXRETURN; } /*! find min and max of possibly masked float dataset for a particular sub-brick */ static void Compute_3dAS_Max_Brick(THD_3dim_dataset *dset, byte *maskptr, int bricki, float *asfmax, float *asfmin) { int j; MRI_IMAGE *data_im = NULL; float *fptr; float ts0; byte *tempmaskptr; ENTRY("Compute_3dAS_Max_Brick"); tempmaskptr = maskptr; *asfmin = 1E38; *asfmax = -1E38; data_im = DSET_BRICK(dset, bricki); fptr = (float *) mri_data_pointer(data_im); for(j=0;jnxyz;j++) { if(maskptr && !(*tempmaskptr++)) { fptr++; } else { ts0 = *fptr++; if(ts0>*asfmax) *asfmax = ts0; /* update max */ if(ts0<*asfmin) *asfmin = ts0; /* update min */ } } EXRETURN; } /* scale float dataset that may have a mask by multiplication by fratio */ static void AS_scale_float_dset(THD_3dim_dataset *dset, byte *maskptr, float fratio) { int i, j, nbriks; MRI_IMAGE *data_im = NULL; float *fptr; byte *tempmaskptr; ENTRY("AS_scale_float_dset"); tempmaskptr = maskptr; nbriks = dset->dblk->nvals; for(i=0;inxyz;j++) { if(maskptr && !(*tempmaskptr++)) { fptr++; } else { *fptr++ *= fratio; } } } EXRETURN; }