/*-------------------------------------------------------*/ MRI_IMARR * dset_to_mri(THD_3dim_dataset * dset) /*--------------------------------------------------------*/ { int ii, kk, ntime, datum; int nvox, nx, ny, nz; int use_fac; MRI_IMARR * ims_in; MRI_IMAGE * im, *temp_im; byte ** bptr = NULL ; /* one of these will be the array of */ short ** sptr = NULL ; /* pointers to input dataset sub-bricks */ float ** fptr = NULL ; /* (depending on input datum type) */ float * fac = NULL ; /* array of brick scaling factors */ float * fout; ntime = DSET_NUM_TIMES(dset) ; nx = dset->daxes->nxx; ny = dset->daxes->nyy; nz = dset->daxes->nzz; nvox = dset->daxes->nxx * dset->daxes->nyy * dset->daxes->nzz ; datum = DSET_BRICK_TYPE( dset , 0 ) ; /* get dataset datum type */ switch( datum ){ /* pointer type depends on input datum type */ default: return NULL ; /** create array of pointers into old dataset sub-bricks **/ /*--------- input is bytes ----------*/ /* voxel #i at time #k is bptr[k][i] */ /* for i=0..nvox-1 and k=0..ntime-1. */ case MRI_byte: bptr = (byte **) malloc( sizeof(byte *) * ntime ) ; if( bptr == NULL ) return NULL ; for( kk=0 ; kk < ntime ; kk++ ) bptr[kk] = (byte *) DSET_ARRAY(dset,kk) ; break ; /*--------- input is shorts ---------*/ /* voxel #i at time #k is sptr[k][i] */ /* for i=0..nvox-1 and k=0..ntime-1. */ case MRI_short: sptr = (short **) malloc( sizeof(short *) * ntime ) ; if( sptr == NULL ) return NULL ; for( kk=0 ; kk < ntime; kk++ ) sptr[kk] = (short *) DSET_ARRAY(dset,kk) ; break ; /*--------- input is floats ---------*/ /* voxel #i at time #k is fptr[k][i] */ /* for i=0..nvox-1 and k=0..ntime-1. */ case MRI_float: fptr = (float **) malloc( sizeof(float *) * ntime) ; if( fptr == NULL ) return NULL ; for( kk=0 ; kk < ntime; kk++ ) fptr[kk] = (float *) DSET_ARRAY(dset,kk) ; break ; } /* end of switch on input type */ INIT_IMARR(ims_in) ; for( kk=0 ; kk < ntime ; kk++ ){ im = mri_new_vol_empty( nx , ny , nz , datum ) ; ADDTO_IMARR(ims_in,im) ; } for( kk=0 ; kk < ntime ; kk++ ){ im = IMARR_SUBIMAGE(ims_in,kk) ; switch( datum ){ case MRI_byte: mri_fix_data_pointer( bptr[kk], im ) ; break ; case MRI_short: mri_fix_data_pointer( sptr[kk], im ) ; break ; case MRI_float: mri_fix_data_pointer( fptr[kk], im ) ; break ; } } return(ims_in); }
int main( int argc , char *argv[] ) { THD_3dim_dataset *yset=NULL , *aset=NULL , *mset=NULL , *wset=NULL ; MRI_IMAGE *fim=NULL, *qim,*tim, *pfim=NULL , *vim , *wim=NULL ; float *flar , *qar,*tar, *par=NULL , *var , *war=NULL ; MRI_IMARR *fimar=NULL ; MRI_IMAGE *aim , *yim ; float *aar , *yar ; int nt=0 , nxyz=0 , nvox=0 , nparam=0 , nqbase , polort=0 , ii,jj,kk,bb ; byte *mask=NULL ; int nmask=0 , iarg ; char *fname_out="-" ; /** equiv to stdout **/ float alpha=0.0f ; int nfir =0 ; float firwt[5]={0.09f,0.25f,0.32f,0.25f,0.09f} ; int nmed =0 ; int nwt =0 ; #define METHOD_C 3 #define METHOD_K 11 int method = METHOD_C ; /**--- help the pitiful user? ---**/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dInvFMRI [options]\n" "Program to compute stimulus time series, given a 3D+time dataset\n" "and an activation map (the inverse of the usual FMRI analysis problem).\n" "-------------------------------------------------------------------\n" "OPTIONS:\n" "\n" " -data yyy =\n" " *OR* = Defines input 3D+time dataset [a non-optional option].\n" " -input yyy =\n" "\n" " -map aaa = Defines activation map; 'aaa' should be a bucket dataset,\n" " each sub-brick of which defines the beta weight map for\n" " an unknown stimulus time series [also non-optional].\n" "\n" " -mapwt www = Defines a weighting factor to use for each element of\n" " the map. The dataset 'www' can have either 1 sub-brick,\n" " or the same number as in the -map dataset. In the\n" " first case, in each voxel, each sub-brick of the map\n" " gets the same weight in the least squares equations.\n" " [default: all weights are 1]\n" "\n" " -mask mmm = Defines a mask dataset, to restrict input voxels from\n" " -data and -map. [default: all voxels are used]\n" "\n" " -base fff = Each column of the 1D file 'fff' defines a baseline time\n" " series; these columns should be the same length as\n" " number of time points in 'yyy'. Multiple -base options\n" " can be given.\n" " -polort pp = Adds polynomials of order 'pp' to the baseline collection.\n" " The default baseline model is '-polort 0' (constant).\n" " To specify no baseline model at all, use '-polort -1'.\n" "\n" " -out vvv = Name of 1D output file will be 'vvv'.\n" " [default = '-', which is stdout; probably not good]\n" "\n" " -method M = Determines the method to use. 'M' is a single letter:\n" " -method C = least squares fit to data matrix Y [default]\n" " -method K = least squares fit to activation matrix A\n" "\n" " -alpha aa = Set the 'alpha' factor to 'aa'; alpha is used to penalize\n" " large values of the output vectors. Default is 0.\n" " A large-ish value for alpha would be 0.1.\n" "\n" " -fir5 = Smooth the results with a 5 point lowpass FIR filter.\n" " -median5 = Smooth the results with a 5 point median filter.\n" " [default: no smoothing; only 1 of these can be used]\n" "-------------------------------------------------------------------\n" "METHODS:\n" " Formulate the problem as\n" " Y = V A' + F C' + errors\n" " where Y = data matrix (N x M) [from -data]\n" " V = stimulus (N x p) [to -out]\n" " A = map matrix (M x p) [from -map]\n" " F = baseline matrix (N x q) [from -base and -polort]\n" " C = baseline weights (M x q) [not computed]\n" " N = time series length = length of -data file\n" " M = number of voxels in mask\n" " p = number of stimulus time series to estimate\n" " = number of parameters in -map file\n" " q = number of baseline parameters\n" " and ' = matrix transpose operator\n" " Next, define matrix Z (Y detrended relative to columns of F) by\n" " -1\n" " Z = [I - F(F'F) F'] Y\n" "-------------------------------------------------------------------\n" " The method C solution is given by\n" " -1\n" " V0 = Z A [A'A]\n" "\n" " This solution minimizes the sum of squares over the N*M elements\n" " of the matrix Y - V A' + F C' (N.B.: A' means A-transpose).\n" "-------------------------------------------------------------------\n" " The method K solution is given by\n" " -1 -1\n" " W = [Z Z'] Z A and then V = W [W'W]\n" "\n" " This solution minimizes the sum of squares of the difference between\n" " the A(V) predicted from V and the input A, where A(V) is given by\n" " -1\n" " A(V) = Z' V [V'V] = Z'W\n" "-------------------------------------------------------------------\n" " Technically, the solution is unidentfiable up to an arbitrary\n" " multiple of the columns of F (i.e., V = V0 + F G, where G is\n" " an arbitrary q x p matrix); the solution above is the solution\n" " that is orthogonal to the columns of F.\n" "\n" "-- RWCox - March 2006 - purely for experimental purposes!\n" ) ; printf("\n" "===================== EXAMPLE USAGE =====================================\n" "** Step 1: From a training dataset, generate activation map.\n" " The input dataset has 4 runs, each 108 time points long. 3dDeconvolve\n" " is used on the first 3 runs (time points 0..323) to generate the\n" " activation map. There are two visual stimuli (Complex and Simple).\n" "\n" " 3dDeconvolve -x1D xout_short_two.1D -input rall_vr+orig'[0..323]' \\\n" " -num_stimts 2 \\\n" " -stim_file 1 hrf_complex.1D -stim_label 1 Complex \\\n" " -stim_file 2 hrf_simple.1D -stim_label 2 Simple \\\n" " -concat '1D:0,108,216' \\\n" " -full_first -fout -tout \\\n" " -bucket func_ht2_short_two -cbucket cbuc_ht2_short_two\n" "\n" " N.B.: You may want to de-spike, smooth, and register the 3D+time\n" " dataset prior to the analysis (as usual). These steps are not\n" " shown here -- I'm presuming you know how to use AFNI already.\n" "\n" "** Step 2: Create a mask of highly activated voxels.\n" " The F statistic threshold is set to 30, corresponding to a voxel-wise\n" " p = 1e-12 = very significant. The mask is also lightly clustered, and\n" " restricted to brain voxels.\n" "\n" " 3dAutomask -prefix Amask rall_vr+orig\n" " 3dcalc -a 'func_ht2_short+orig[0]' -b Amask+orig -datum byte \\\n" " -nscale -expr 'step(a-30)*b' -prefix STmask300\n" " 3dmerge -dxyz=1 -1clust 1.1 5 -prefix STmask300c STmask300+orig\n" "\n" "** Step 3: Run 3dInvFMRI to estimate the stimulus functions in run #4.\n" " Run #4 is time points 324..431 of the 3D+time dataset (the -data\n" " input below). The -map input is the beta weights extracted from\n" " the -cbucket output of 3dDeconvolve.\n" "\n" " 3dInvFMRI -mask STmask300c+orig \\\n" " -data rall_vr+orig'[324..431]' \\\n" " -map cbuc_ht2_short_two+orig'[6..7]' \\\n" " -polort 1 -alpha 0.01 -median5 -method K \\\n" " -out ii300K_short_two.1D\n" "\n" " 3dInvFMRI -mask STmask300c+orig \\\n" " -data rall_vr+orig'[324..431]' \\\n" " -map cbuc_ht2_short_two+orig'[6..7]' \\\n" " -polort 1 -alpha 0.01 -median5 -method C \\\n" " -out ii300C_short_two.1D\n" "\n" "** Step 4: Plot the results, and get confused.\n" "\n" " 1dplot -ynames VV KK CC -xlabel Run#4 -ylabel ComplexStim \\\n" " hrf_complex.1D'{324..432}' \\\n" " ii300K_short_two.1D'[0]' \\\n" " ii300C_short_two.1D'[0]'\n" "\n" " 1dplot -ynames VV KK CC -xlabel Run#4 -ylabel SimpleStim \\\n" " hrf_simple.1D'{324..432}' \\\n" " ii300K_short_two.1D'[1]' \\\n" " ii300C_short_two.1D'[1]'\n" "\n" " N.B.: I've found that method K works better if MORE voxels are\n" " included in the mask (lower threshold) and method C if\n" " FEWER voxels are included. The above threshold gave 945\n" " voxels being used to determine the 2 output time series.\n" "=========================================================================\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /**--- bureaucracy ---**/ mainENTRY("3dInvFMRI main"); machdep(); PRINT_VERSION("3dInvFMRI"); AUTHOR("Zhark"); AFNI_logger("3dInvFMRI",argc,argv) ; /**--- scan command line ---**/ iarg = 1 ; while( iarg < argc ){ if( strcmp(argv[iarg],"-method") == 0 ){ switch( argv[++iarg][0] ){ default: WARNING_message("Ignoring illegal -method '%s'",argv[iarg]) ; break ; case 'C': method = METHOD_C ; break ; case 'K': method = METHOD_K ; break ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-fir5") == 0 ){ if( nmed > 0 ) WARNING_message("Ignoring -fir5 in favor of -median5") ; else nfir = 5 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-median5") == 0 ){ if( nfir > 0 ) WARNING_message("Ignoring -median5 in favor of -fir5") ; else nmed = 5 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-alpha") == 0 ){ alpha = (float)strtod(argv[++iarg],NULL) ; if( alpha <= 0.0f ){ alpha = 0.0f ; WARNING_message("-alpha '%s' ignored!",argv[iarg]) ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-data") == 0 || strcmp(argv[iarg],"-input") == 0 ){ if( yset != NULL ) ERROR_exit("Can't input 2 3D+time datasets") ; yset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(yset,argv[iarg]) ; nt = DSET_NVALS(yset) ; if( nt < 2 ) ERROR_exit("Only 1 sub-brick in dataset %s",argv[iarg]) ; nxyz = DSET_NVOX(yset) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-map") == 0 ){ if( aset != NULL ) ERROR_exit("Can't input 2 -map datasets") ; aset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(aset,argv[iarg]) ; nparam = DSET_NVALS(aset) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mapwt") == 0 ){ if( wset != NULL ) ERROR_exit("Can't input 2 -mapwt datasets") ; wset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(wset,argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask") == 0 ){ if( mset != NULL ) ERROR_exit("Can't input 2 -mask datasets") ; mset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(mset,argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-polort") == 0 ){ char *cpt ; polort = (int)strtod(argv[++iarg],&cpt) ; if( *cpt != '\0' ) WARNING_message("Illegal non-numeric value after -polort") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-out") == 0 ){ fname_out = strdup(argv[++iarg]) ; if( !THD_filename_ok(fname_out) ) ERROR_exit("Bad -out filename '%s'",fname_out) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-base") == 0 ){ if( fimar == NULL ) INIT_IMARR(fimar) ; qim = mri_read_1D( argv[++iarg] ) ; if( qim == NULL ) ERROR_exit("Can't read 1D file %s",argv[iarg]) ; ADDTO_IMARR(fimar,qim) ; iarg++ ; continue ; } ERROR_exit("Unrecognized option '%s'",argv[iarg]) ; } /**--- finish up processing options ---**/ if( yset == NULL ) ERROR_exit("No input 3D+time dataset?!") ; if( aset == NULL ) ERROR_exit("No input FMRI -map dataset?!") ; if( DSET_NVOX(aset) != nxyz ) ERROR_exit("Grid mismatch between -data and -map") ; INFO_message("Loading dataset for Y") ; DSET_load(yset); CHECK_LOAD_ERROR(yset) ; INFO_message("Loading dataset for A") ; DSET_load(aset); CHECK_LOAD_ERROR(aset) ; if( wset != NULL ){ if( DSET_NVOX(wset) != nxyz ) ERROR_exit("Grid mismatch between -data and -mapwt") ; nwt = DSET_NVALS(wset) ; if( nwt > 1 && nwt != nparam ) ERROR_exit("Wrong number of values=%d in -mapwt; should be 1 or %d", nwt , nparam ) ; INFO_message("Loading dataset for mapwt") ; DSET_load(wset); CHECK_LOAD_ERROR(wset) ; } if( mset != NULL ){ if( DSET_NVOX(mset) != nxyz ) ERROR_exit("Grid mismatch between -data and -mask") ; INFO_message("Loading dataset for mask") ; DSET_load(mset); CHECK_LOAD_ERROR(mset) ; mask = THD_makemask( mset , 0 , 1.0f,-1.0f ); DSET_delete(mset); nmask = THD_countmask( nxyz , mask ) ; if( nmask < 3 ){ WARNING_message("Mask has %d voxels -- ignoring!",nmask) ; free(mask) ; mask = NULL ; nmask = 0 ; } } nvox = (nmask > 0) ? nmask : nxyz ; INFO_message("N = time series length = %d",nt ) ; INFO_message("M = number of voxels = %d",nvox ) ; INFO_message("p = number of params = %d",nparam) ; /**--- set up baseline funcs in one array ---*/ nqbase = (polort >= 0 ) ? polort+1 : 0 ; if( fimar != NULL ){ for( kk=0 ; kk < IMARR_COUNT(fimar) ; kk++ ){ qim = IMARR_SUBIMAGE(fimar,kk) ; if( qim != NULL && qim->nx != nt ) WARNING_message("-base #%d length=%d; data length=%d",kk+1,qim->nx,nt) ; nqbase += qim->ny ; } } INFO_message("q = number of baselines = %d",nqbase) ; #undef F #define F(i,j) flar[(i)+(j)*nt] /* nt X nqbase */ if( nqbase > 0 ){ fim = mri_new( nt , nqbase , MRI_float ) ; /* F matrix */ flar = MRI_FLOAT_PTR(fim) ; bb = 0 ; if( polort >= 0 ){ /** load polynomial baseline **/ double a = 2.0/(nt-1.0) ; for( jj=0 ; jj <= polort ; jj++ ){ for( ii=0 ; ii < nt ; ii++ ) F(ii,jj) = (float)Plegendre( a*ii-1.0 , jj ) ; } bb = polort+1 ; } #undef Q #define Q(i,j) qar[(i)+(j)*qim->nx] /* qim->nx X qim->ny */ if( fimar != NULL ){ /** load -base baseline columns **/ for( kk=0 ; kk < IMARR_COUNT(fimar) ; kk++ ){ qim = IMARR_SUBIMAGE(fimar,kk) ; qar = MRI_FLOAT_PTR(qim) ; for( jj=0 ; jj < qim->ny ; jj++ ){ for( ii=0 ; ii < nt ; ii++ ) F(ii,bb+jj) = (ii < qim->nx) ? Q(ii,jj) : 0.0f ; } bb += qim->ny ; } DESTROY_IMARR(fimar) ; fimar=NULL ; } /* remove mean from each column after first? */ if( polort >= 0 && nqbase > 1 ){ float sum ; for( jj=1 ; jj < nqbase ; jj++ ){ sum = 0.0f ; for( ii=0 ; ii < nt ; ii++ ) sum += F(ii,jj) ; sum /= nt ; for( ii=0 ; ii < nt ; ii++ ) F(ii,jj) -= sum ; } } /* compute pseudo-inverse of baseline matrix, so we can project it out from the data time series */ /* -1 */ /* (F'F) F' matrix */ INFO_message("Computing pseudo-inverse of baseline matrix F") ; pfim = mri_matrix_psinv(fim,NULL,0.0f) ; par = MRI_FLOAT_PTR(pfim) ; #undef P #define P(i,j) par[(i)+(j)*nqbase] /* nqbase X nt */ #if 0 qim = mri_matrix_transpose(pfim) ; /** save to disk? **/ mri_write_1D( "Fpsinv.1D" , qim ) ; mri_free(qim) ; #endif } /**--- set up map image into aim/aar = A matrix ---**/ #undef GOOD #define GOOD(i) (mask==NULL || mask[i]) #undef A #define A(i,j) aar[(i)+(j)*nvox] /* nvox X nparam */ INFO_message("Loading map matrix A") ; aim = mri_new( nvox , nparam , MRI_float ); aar = MRI_FLOAT_PTR(aim); for( jj=0 ; jj < nparam ; jj++ ){ for( ii=kk=0 ; ii < nxyz ; ii++ ){ if( GOOD(ii) ){ A(kk,jj) = THD_get_voxel(aset,ii,jj); kk++; } }} DSET_unload(aset) ; /**--- set up map weight into wim/war ---**/ #undef WT #define WT(i,j) war[(i)+(j)*nvox] /* nvox X nparam */ if( wset != NULL ){ int numneg=0 , numpos=0 ; float fac ; INFO_message("Loading map weight matrix") ; wim = mri_new( nvox , nwt , MRI_float ) ; war = MRI_FLOAT_PTR(wim) ; for( jj=0 ; jj < nwt ; jj++ ){ for( ii=kk=0 ; ii < nxyz ; ii++ ){ if( GOOD(ii) ){ WT(kk,jj) = THD_get_voxel(wset,ii,jj); if( WT(kk,jj) > 0.0f ){ numpos++; WT(kk,jj) = sqrt(WT(kk,jj)); } else if( WT(kk,jj) < 0.0f ){ numneg++; WT(kk,jj) = 0.0f; } kk++; } }} DSET_unload(wset) ; if( numpos <= nparam ) WARNING_message("Only %d positive weights found in -wtmap!",numpos) ; if( numneg > 0 ) WARNING_message("%d negative weights found in -wtmap!",numneg) ; for( jj=0 ; jj < nwt ; jj++ ){ fac = 0.0f ; for( kk=0 ; kk < nvox ; kk++ ) if( WT(kk,jj) > fac ) fac = WT(kk,jj) ; if( fac > 0.0f ){ fac = 1.0f / fac ; for( kk=0 ; kk < nvox ; kk++ ) WT(kk,jj) *= fac ; } } } /**--- set up data image into yim/yar = Y matrix ---**/ #undef Y #define Y(i,j) yar[(i)+(j)*nt] /* nt X nvox */ INFO_message("Loading data matrix Y") ; yim = mri_new( nt , nvox , MRI_float ); yar = MRI_FLOAT_PTR(yim); for( ii=0 ; ii < nt ; ii++ ){ for( jj=kk=0 ; jj < nxyz ; jj++ ){ if( GOOD(jj) ){ Y(ii,kk) = THD_get_voxel(yset,jj,ii); kk++; } }} DSET_unload(yset) ; /**--- project baseline out of data image = Z matrix ---**/ if( pfim != NULL ){ #undef T #define T(i,j) tar[(i)+(j)*nt] /* nt X nvox */ INFO_message("Projecting baseline out of Y") ; qim = mri_matrix_mult( pfim , yim ) ; /* nqbase X nvox */ tim = mri_matrix_mult( fim , qim ) ; /* nt X nvox */ tar = MRI_FLOAT_PTR(tim) ; /* Y projected onto baseline */ for( jj=0 ; jj < nvox ; jj++ ) for( ii=0 ; ii < nt ; ii++ ) Y(ii,jj) -= T(ii,jj) ; mri_free(tim); mri_free(qim); mri_free(pfim); mri_free(fim); } /***** At this point: matrix A is in aim, matrix Z is in yim. Solve for V into vim, using the chosen method *****/ switch( method ){ default: ERROR_exit("Illegal method code! WTF?") ; /* Huh? */ /*.....................................................................*/ case METHOD_C: /**--- compute pseudo-inverse of A map ---**/ INFO_message("Method C: Computing pseudo-inverse of A") ; if( wim != NULL ) WARNING_message("Ignoring -mapwt dataset") ; pfim = mri_matrix_psinv(aim,NULL,alpha) ; /* nparam X nvox */ if( pfim == NULL ) ERROR_exit("mri_matrix_psinv() fails") ; mri_free(aim) ; /**--- and apply to data to get results ---*/ INFO_message("Computing result V") ; vim = mri_matrix_multranB( yim , pfim ) ; /* nt x nparam */ mri_free(pfim) ; mri_free(yim) ; break ; /*.....................................................................*/ case METHOD_K: /**--- compute pseudo-inverse of transposed Z ---*/ INFO_message("Method K: Computing pseudo-inverse of Z'") ; if( nwt > 1 ){ WARNING_message("Ignoring -mapwt dataset: more than 1 sub-brick") ; nwt = 0 ; mri_free(wim) ; wim = NULL ; war = NULL ; } if( nwt == 1 ){ float fac ; for( kk=0 ; kk < nvox ; kk++ ){ fac = war[kk] ; for( ii=0 ; ii < nt ; ii++ ) Y(ii,kk) *= fac ; for( ii=0 ; ii < nparam ; ii++ ) A(kk,ii) *= fac ; } } tim = mri_matrix_transpose(yim) ; mri_free(yim) ; pfim = mri_matrix_psinv(tim,NULL,alpha) ; mri_free(tim) ; if( pfim == NULL ) ERROR_exit("mri_matrix_psinv() fails") ; INFO_message("Computing W") ; tim = mri_matrix_mult( pfim , aim ) ; mri_free(aim) ; mri_free(pfim) ; INFO_message("Computing result V") ; pfim = mri_matrix_psinv(tim,NULL,0.0f) ; mri_free(tim) ; vim = mri_matrix_transpose(pfim) ; mri_free(pfim); break ; } /* end of switch on method */ if( wim != NULL ) mri_free(wim) ; /**--- smooth? ---**/ if( nfir > 0 && vim->nx > nfir ){ INFO_message("FIR-5-ing result") ; var = MRI_FLOAT_PTR(vim) ; for( jj=0 ; jj < vim->ny ; jj++ ) linear_filter_reflect( nfir,firwt , vim->nx , var + (jj*vim->nx) ) ; } if( nmed > 0 && vim->nx > nmed ){ INFO_message("Median-5-ing result") ; var = MRI_FLOAT_PTR(vim) ; for( jj=0 ; jj < vim->ny ; jj++ ) median5_filter_reflect( vim->nx , var + (jj*vim->nx) ) ; } /**--- write results ---**/ INFO_message("Writing result to '%s'",fname_out) ; mri_write_1D( fname_out , vim ) ; exit(0) ; }
int main( int argc , char * argv[] ) { char prefix[255]="obi-wan-kenobi" , fname[255] ; int datum = -1 ; int iarg = 1 ; int gnim , nx , ny , nz , kz ; char ** gname ; MRI_IMARR * arr ; MRI_IMAGE * im , * qim ; FILE * fp ; /***** help? *****/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: imstack [options] image_filenames ...\n" "Stacks up a set of 2D images into one big file (a la MGH).\n" "Options:\n" " -datum type Converts the output data file to be 'type',\n" " which is either 'short' or 'float'.\n" " The default type is the type of the first image.\n" " -prefix name Names the output files to be 'name'.b'type' and 'name'.hdr.\n" " The default name is 'obi-wan-kenobi'.\n" ) ; exit(0) ; } machdep() ; /***** scan for option *****/ while( iarg < argc && argv[iarg][0] == '-' ){ /*** -datum ***/ if( strcmp(argv[iarg],"-datum") == 0 ){ if( ++iarg >= argc ){ fprintf(stderr,"-datum needs a type!\n") ; exit(1) ; } if( strcmp(argv[iarg],"short") == 0 ){ datum = MRI_short ; } else if( strcmp(argv[iarg],"float") == 0 ){ datum = MRI_float ; } else { fprintf(stderr,"-datum %s is illegal!\n",argv[iarg]) ; exit(1) ; } iarg++ ; continue ; } /*** -prefix ***/ if( strcmp(argv[iarg],"-prefix") == 0 ){ if( ++iarg >= argc ){ fprintf(stderr,"-prefix needs a name!\n") ; exit(1) ; } strcpy(prefix,argv[iarg]) ; iarg++ ; continue ; } /*** ERROR ***/ fprintf(stderr,"Unrecognized option: %s\n",argv[iarg]) ; exit(1) ; } /***** Check if any filenames left *****/ if( iarg >= argc ){ fprintf(stderr,"No input image filenames?!\n") ; exit(1) ; } /***** Perform filename expansion on the input list *****/ MCW_warn_expand(1) ; MCW_file_expand( argc - iarg , argv + iarg , &gnim , &gname ) ; MCW_warn_expand(0) ; if( gnim < 1 ){ fprintf(stderr,"Filename expansion fails on input filenames?!\n") ; exit(1) ; } /***** Read all files *****/ arr = mri_read_many_files( gnim , gname ) ; if( arr == NULL || IMARR_COUNT(arr) <= 0 ){ fprintf(stderr,"Can't read input files?!\n") ; exit(1) ; } MCW_free_expand( gnim , gname ) ; fprintf(stderr,"Read in %d 2D slices\n",IMARR_COUNT(arr)) ; /***** Set output datum, if not already fixed *****/ if( datum < 0 ){ datum = IMARR_SUBIMAGE(arr,0)->kind ; if( datum != MRI_short && datum != MRI_float ){ fprintf(stderr,"Input image type is %s -- you must use -datum!\n", MRI_TYPE_name[datum]) ; exit(1) ; } } /***** Check images for equal sizes *****/ nx = IMARR_SUBIMAGE(arr,0)->nx ; ny = IMARR_SUBIMAGE(arr,0)->ny ; nz = IMARR_COUNT(arr) ; for( kz=1 ; kz < nz ; kz++ ){ if( IMARR_SUBIMAGE(arr,kz)->nx != nx || IMARR_SUBIMAGE(arr,kz)->ny != ny ){ fprintf(stderr,"All images must be the same size (%d x %d)\n",nx,ny) ; exit(1) ; } } /***** Write the output brick *****/ sprintf(fname,"%s.b%s",prefix,MRI_TYPE_name[datum]) ; fp = fopen( fname , "w" ) ; if( fp == NULL ){ fprintf(stderr,"Can't open output file %s\n",fname) ; exit(1) ; } for( kz=0 ; kz < nz ; kz++ ){ im = IMARR_SUBIMAGE(arr,kz) ; if( im->kind != datum ) qim = mri_to_mri( datum , im ) ; else qim = im ; fwrite( mri_data_pointer(qim) , qim->pixel_size , qim->nx * qim->ny , fp ) ; if( qim != im ) mri_free(qim) ; mri_free(im); } fclose( fp ) ; fprintf(stderr,"Wrote output brick %s\n",fname) ; /***** Write the output header *****/ sprintf(fname,"%s.hdr",prefix) ; fp = fopen( fname , "w" ) ; if( fp == NULL ){ fprintf(stderr,"Can't open output file %s\n",fname) ; exit(1) ; } fprintf( fp , "%d %d %d 0\n" , nx,ny,nz ) ; fclose(fp) ; fprintf(stderr,"Wrote output header %s: %d %d %d\n",fname,nx,ny,nz) ; exit(0) ; }
MRI_IMAGE * mri_cat2D( int mx , int my , int gap , void *gapval , MRI_IMARR *imar ) { int nx , ny , ii , jj , kind , ij , nxout , nyout , ijoff , jout,iout ; MRI_IMAGE *imout , *imin=NULL ; void *vout ; ENTRY("mri_cat2D") ; /*--- sanity checks ---*/ if( mx < 1 || my < 1 || imar == NULL || (!OK_wrap && imar->num < mx*my) ) RETURN( NULL ); if( gap < 0 || (gap > 0 && gapval == NULL) ) RETURN( NULL ); for( ij=0 ; ij < mx*my ; ij++ ){ /* find first non-empty image */ imin = IMARR_SUBIMAGE(imar,ij%imar->num) ; if( imin != NULL ) break ; } if( ij == mx*my ) RETURN( NULL ); /* all are empty! */ kind = imin->kind ; nx = imin->nx ; ny = imin->ny ; if( mx==1 && my==1 ){ /* 1x1 case (shouldn't happen) */ imout = mri_to_mri( kind , imin ) ; /* Just copy input to output */ RETURN( imout ); } for( ij=0 ; ij < mx*my ; ij++ ){ /* check for consistency */ imin = IMARR_SUBIMAGE(imar,ij%imar->num) ; if( imin != NULL && (imin->kind != kind || imin->nx != nx || imin->ny != ny) ) RETURN( NULL ); } nxout = mx * nx + (mx-1) * gap ; nyout = my * ny + (my-1) * gap ; imout = mri_new( nxout , nyout , kind ) ; vout = mri_data_pointer( imout ) ; ij = 0 ; for( jj=0 ; jj < my ; jj++ ){ /* loop over rows */ for( ii=0 ; ii < mx ; ii++ , ij++ ){ /* loop over columns */ if (WrapZero && ij >= imar->num) imin = NULL; else imin = IMARR_SUBIMAGE(imar,ij%imar->num) ; ijoff = ii * (nx+gap) + jj * (ny+gap) * nxout ; /*--- NULL image ==> fill this spot with zeroes ---*/ if( imin == NULL || mri_data_pointer(imin) == NULL ){ switch( kind ){ case MRI_byte:{ byte *pout = ((byte *) vout); for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) (void) memset( pout+ijoff , 0 , sizeof(byte)*nx ) ; } break ; case MRI_rgb:{ /* 11 Feb 1999 */ byte *pout = ((byte *) vout); for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) (void) memset( pout+(3*ijoff) , 0 , sizeof(byte)*(3*nx) ) ; } break ; case MRI_short:{ short *pout = ((short *) vout); for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) (void) memset( pout+ijoff , 0 , sizeof(short)*nx ) ; } break ; case MRI_int:{ int *pout = ((int *) vout); for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) (void) memset( pout+ijoff , 0 , sizeof(int)*nx ) ; } break ; case MRI_float:{ float *pout = ((float *) vout); for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) for( iout=0 ; iout < nx ; iout++ ) pout[iout+ijoff] = 0 ; } break ; case MRI_double:{ double *pout = ((double *) vout); for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) for( iout=0 ; iout < nx ; iout++ ) pout[iout+ijoff] = 0 ; } break ; case MRI_complex:{ complex *pout = ((complex *) vout); for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) for( iout=0 ; iout < nx ; iout++ ) pout[iout+ijoff].r = pout[iout+ijoff].i = 0 ; } break ; } /*--- Copy input image data into place ---*/ } else { switch( kind ){ case MRI_byte:{ byte *pout = ((byte *) vout) , *pin = (byte *) MRI_BYTE_PTR(imin) ; for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) memcpy( pout+ijoff , pin , sizeof(byte)*nx ) , pin += nx ; } break ; case MRI_rgb:{ /* 11 Feb 1999 */ byte *pout = ((byte *) vout) , *pin = (byte *) MRI_RGB_PTR(imin) ; for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) memcpy( pout+(3*ijoff) , pin , sizeof(byte)*(3*nx) ) , pin += 3*nx ; } break ; case MRI_short:{ short *pout = ((short *) vout) , *pin = (short *) MRI_SHORT_PTR(imin) ; for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) memcpy( pout+ijoff , pin , sizeof(short)*nx ) , pin += nx ; } break ; case MRI_int:{ int *pout = ((int *) vout) , *pin = (int *) MRI_INT_PTR(imin) ; for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) memcpy( pout+ijoff , pin , sizeof(int)*nx ) , pin += nx ; } break ; case MRI_float:{ float *pout = ((float *) vout) , *pin = (float *) MRI_FLOAT_PTR(imin) ; for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) memcpy( pout+ijoff , pin , sizeof(float)*nx ) , pin += nx ; } break ; case MRI_double:{ double *pout = ((double *) vout) , *pin = (double *) MRI_DOUBLE_PTR(imin) ; for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) memcpy( pout+ijoff , pin , sizeof(double)*nx ) , pin += nx ; } break ; case MRI_complex:{ complex *pout = ((complex *) vout) , *pin = (complex *) MRI_COMPLEX_PTR(imin) ; for( jout=0 ; jout < ny ; jout++ , ijoff+=nxout ) memcpy( pout+ijoff , pin , sizeof(complex)*nx ) , pin += nx ; } break ; } } } } /******************* Deal with the gaps *******************/ if( gap > 0 ){ /**** put value into gap after each row ****/ ii = nxout * gap ; for( jj=0 ; jj < my-1 ; jj++ ){ ijoff = (ny + jj * (ny+gap)) * nxout ; switch( kind ){ case MRI_byte:{ byte gval = *((byte *)gapval) , *pout = ((byte *) vout) ; for( ij=0 ; ij < ii ; ij++ ) pout[ij+ijoff] = gval ; } break ; case MRI_rgb:{ /* 11 Feb 1999 */ byte rval = *(((byte *)gapval) ) , gval = *(((byte *)gapval)+1) , bval = *(((byte *)gapval)+2) , *pout = ((byte *) vout) ; for( ij=0 ; ij < ii ; ij++ ){ pout[3*(ij+ijoff) ] = rval ; pout[3*(ij+ijoff)+1] = gval ; pout[3*(ij+ijoff)+2] = bval ; } } break ; case MRI_short:{ short gval = *((short *)gapval) , *pout = ((short *) vout) ; for( ij=0 ; ij < ii ; ij++ ) pout[ij+ijoff] = gval ; } break ; case MRI_float:{ float gval = *((float *)gapval) , *pout = ((float *) vout) ; for( ij=0 ; ij < ii ; ij++ ) pout[ij+ijoff] = gval ; } break ; case MRI_int:{ int gval = *((int *)gapval) , *pout = ((int *) vout) ; for( ij=0 ; ij < ii ; ij++ ) pout[ij+ijoff] = gval ; } break ; case MRI_double:{ double gval = *((double *)gapval) , *pout = ((double *) vout) ; for( ij=0 ; ij < ii ; ij++ ) pout[ij+ijoff] = gval ; } break ; case MRI_complex:{ complex gval = *((complex *)gapval) , *pout = ((complex *) vout) ; for( ij=0 ; ij < ii ; ij++ ) pout[ij+ijoff] = gval ; } break ; } } /**** put value into gap after each column ****/ for( ii=0 ; ii < mx-1 ; ii++ ){ ijoff = nx + ii*(nx+gap) ; switch( kind ){ case MRI_byte:{ byte gval = *((byte *)gapval) , *pout = ((byte *) vout) ; for( ij=0 ; ij < gap ; ij++ , ijoff++ ) for( jj=0 ; jj < nyout ; jj++ ) pout[jj*nxout+ijoff] = gval ; } break ; case MRI_rgb:{ /* 11 Feb 1999 */ byte rval = *(((byte *)gapval) ) , gval = *(((byte *)gapval)+1) , bval = *(((byte *)gapval)+2) , *pout = ((byte *) vout) ; for( ij=0 ; ij < gap ; ij++ , ijoff++ ) for( jj=0 ; jj < nyout ; jj++ ){ pout[3*(jj*nxout+ijoff) ] = rval ; pout[3*(jj*nxout+ijoff)+1] = gval ; pout[3*(jj*nxout+ijoff)+2] = bval ; } } break ; case MRI_short:{ short gval = *((short *)gapval) , *pout = ((short *) vout) ; for( ij=0 ; ij < gap ; ij++ , ijoff++ ) for( jj=0 ; jj < nyout ; jj++ ) pout[jj*nxout+ijoff] = gval ; } break ; case MRI_float:{ float gval = *((float *)gapval) , *pout = ((float *) vout) ; for( ij=0 ; ij < gap ; ij++ , ijoff++ ) for( jj=0 ; jj < nyout ; jj++ ) pout[jj*nxout+ijoff] = gval ; } break ; case MRI_int:{ int gval = *((int *)gapval) , *pout = ((int *) vout) ; for( ij=0 ; ij < gap ; ij++ , ijoff++ ) for( jj=0 ; jj < nyout ; jj++ ) pout[jj*nxout+ijoff] = gval ; } break ; case MRI_double:{ double gval = *((double *)gapval) , *pout = ((double *) vout) ; for( ij=0 ; ij < gap ; ij++ , ijoff++ ) for( jj=0 ; jj < nyout ; jj++ ) pout[jj*nxout+ijoff] = gval ; } break ; case MRI_complex:{ complex gval = *((complex *)gapval) , *pout = ((complex *) vout) ; for( ij=0 ; ij < gap ; ij++ , ijoff++ ) for( jj=0 ; jj < nyout ; jj++ ) pout[jj*nxout+ijoff] = gval ; } break ; } } } RETURN( imout ); }
void DT_read_opts( int argc , char * argv[] ) { int nopt = 1 , nvals , ii , nvcheck , nerr=0 ; MRI_IMARR *slice_imar ; INIT_IMARR(DT_imar) ; INIT_IMARR(slice_imar) ; while( nopt < argc && argv[nopt][0] == '-' ){ /**** -polort p ****/ if( strncmp(argv[nopt],"-polort",6) == 0 ){ char *cpt ; nopt++ ; if( nopt >= argc ) ERROR_exit("Need argument after -polort") ; DT_polort = (int)strtod(argv[nopt],&cpt) ; if( *cpt != '\0' ) WARNING_message("Illegal non-numeric value after -polort") ; if( DT_polort < 0 ) WARNING_message("Ignoring negative value after -polort") ; nopt++ ; continue ; } /**** -prefix prefix ****/ if( strncmp(argv[nopt],"-prefix",6) == 0 ){ nopt++ ; if( nopt >= argc ) ERROR_exit("Need argument after -prefix") ; MCW_strncpy( DT_output_prefix , argv[nopt] , THD_MAX_PREFIX ) ; if( !THD_filename_ok(DT_output_prefix) ) ERROR_exit("bad name '%s' after -prefix",argv[nopt]) ; nopt++ ; continue ; } /**** -session directory ****/ if( strncmp(argv[nopt],"-session",6) == 0 ){ nopt++ ; if( nopt >= argc ) ERROR_exit("Need argument after -session") ; MCW_strncpy( DT_session , argv[nopt] , THD_MAX_NAME ) ; if( !THD_filename_ok(DT_session) ) ERROR_exit("bad name '%s' after -session",argv[nopt]) ; nopt++ ; continue ; } /**** -verb ****/ if( strncmp(argv[nopt],"-verb",5) == 0 ){ DT_verb++ ; nopt++ ; continue ; } /**** -replace ****/ if( strncmp(argv[nopt],"-replace",5) == 0 ){ DT_replace++ ; nopt++ ; continue ; } /**** -byslice [08 Dec 1999] ****/ if( strncmp(argv[nopt],"-byslice",5) == 0 ){ #ifdef ALLOW_BYSLICE if( IMARR_COUNT(slice_imar) > 0 ) ERROR_exit("can't mix -byslice and -slicevector") ; DT_byslice++ ; nopt++ ; continue ; #else ERROR_exit("-byslice is no longer suppported") ; #endif } /**** -normalize [23 Nov 1999] ****/ if( strncmp(argv[nopt],"-normalize",5) == 0 ){ DT_norm++ ; nopt++ ; continue ; } /**** -vector ****/ if( strncmp(argv[nopt],"-vector",4) == 0 ){ MRI_IMAGE * flim ; nopt++ ; if( nopt >= argc ) ERROR_exit("need argument after -vector") ; flim = mri_read_1D( argv[nopt++] ) ; if( flim == NULL ) ERROR_exit("can't read -vector '%s'",argv[nopt-1]) ; ADDTO_IMARR(DT_imar,flim) ; if( DT_verb ) INFO_message("Read file %s: rows=%d cols=%d", argv[nopt-1],flim->ny,flim->nx ) ; continue ; } /**** -slicevector ****/ if( strncmp(argv[nopt],"-slicevector",6) == 0 ){ MRI_IMAGE *flim ; nopt++ ; if( nopt >= argc ) ERROR_exit("need argument after -slicevector") ; #ifdef ALLOW_BYSLICE if( DT_byslice ) ERROR_exit("can't mix -slicevector and -byslice") ; #endif flim = mri_read_1D( argv[nopt++] ) ; if( flim == NULL ) ERROR_exit("can't read -slicevector '%s'",argv[nopt-1]) ; ADDTO_IMARR(slice_imar,flim) ; if( DT_verb ) INFO_message("Read file %s: rows=%d cols=%d", argv[nopt-1],flim->ny,flim->nx ) ; continue ; } /**** -del ****/ if( strncmp(argv[nopt],"-del",4) == 0 ){ nopt++ ; if( nopt >= argc ) ERROR_exit("need argument after -del") ; DT_current_del = strtod( argv[nopt++] , NULL ) ; if( DT_verb ) INFO_message("Set expression stepsize = %g\n",DT_current_del) ; continue ; } /**** -expr ****/ if( strncmp(argv[nopt],"-expr",4) == 0 ){ int nexp , qvar , kvar ; char sym[4] ; nopt++ ; if( nopt >= argc ) ERROR_exit("need argument after -expr") ; nexp = DT_exnum + 1 ; if( DT_exnum == 0 ){ /* initialize storage */ DT_expr = (char **) malloc( sizeof(char *) ) ; DT_excode = (PARSER_code **) malloc( sizeof(PARSER_code *) ) ; DT_exdel = (float *) malloc( sizeof(float) ) ; DT_exvar = (int *) malloc( sizeof(int) ) ; } else { DT_expr = (char **) realloc( DT_expr , sizeof(char *)*nexp ) ; DT_excode = (PARSER_code **) realloc( DT_excode , sizeof(PARSER_code *)*nexp ) ; DT_exdel = (float *) realloc( DT_exdel , sizeof(float)*nexp) ; DT_exvar = (int *) realloc( DT_exvar , sizeof(int)*nexp) ; } DT_expr[DT_exnum] = argv[nopt] ; /* string */ DT_exdel[DT_exnum] = DT_current_del ; /* delta */ DT_excode[DT_exnum] = PARSER_generate_code( argv[nopt] ) ; /* compile */ if( DT_excode[DT_exnum] == NULL ) ERROR_exit("Illegal expression: '%s'",argv[nopt]) ; qvar = 0 ; kvar = -1 ; /* find symbol */ for( ii=0 ; ii < 26 ; ii++ ){ sym[0] = 'A' + ii ; sym[1] = '\0' ; if( PARSER_has_symbol(sym,DT_excode[DT_exnum]) ){ qvar++ ; if( kvar < 0 ) kvar = ii ; if( DT_verb ) INFO_message("Found expression symbol %s\n",sym) ; } } if( qvar > 1 ) ERROR_exit("-expr '%s' has too many symbols",DT_expr[DT_exnum]) ; else if( qvar == 0 ) WARNING_message("-expr '%s' is constant",DT_expr[DT_exnum]) ; DT_exvar[DT_exnum] = kvar ; DT_exnum = nexp ; nopt++ ; continue ; } /**** ERROR ****/ ERROR_exit("Unknown option: %s\n",argv[nopt]) ; } /* end of scan over options */ /*-- check for errors --*/ if( nopt >= argc ) ERROR_exit("No input dataset?!") ; #ifdef ALLOW_BYSLICE if( IMARR_COUNT(slice_imar) > 0 && DT_byslice ) ERROR_exit("Illegal mixing of -slicevector and -byslice") ; #endif DT_nvector = IMARR_COUNT(DT_imar) ; if( DT_nvector + DT_exnum == 0 && DT_polort < 0 ) ERROR_exit("No detrending options ordered!") ; #ifdef ALLOW_BYSLICE if( DT_nvector == 0 && DT_byslice ) ERROR_exit("No -vector option supplied with -byslice!") ; #endif /*--- read input dataset ---*/ DT_dset = THD_open_dataset( argv[nopt] ) ; CHECK_OPEN_ERROR(DT_dset,argv[nopt]) ; if( DT_dset == NULL ) ERROR_exit("Can't open dataset %s\n",argv[nopt]) ; DT_current_del = DSET_TR(DT_dset) ; if( DT_current_del <= 0.0 ){ DT_current_del = 1.0 ; if( DT_verb ) WARNING_message("Input has no TR value; setting TR=1.0\n") ; } else if( DT_verb ){ INFO_message("Input has TR=%g\n",DT_current_del) ; } /*-- check vectors for good size --*/ nvcheck = nvals = DSET_NVALS(DT_dset) ; #ifdef ALLOW_BYSLICE if( DT_byslice ) nvcheck *= DSET_NZ(DT_dset) ; #endif for( ii=0 ; ii < DT_nvector ; ii++ ){ if( IMARR_SUBIMAGE(DT_imar,ii)->nx < nvcheck ){ ERROR_message("%d-th -vector is shorter (%d) than dataset (%d)", ii+1,IMARR_SUBIMAGE(DT_imar,ii)->nx,nvcheck) ; nerr++ ; } } if( nerr > 0 ) ERROR_exit("Cannot continue") ; /*--- create time series from expressions */ if( DT_exnum > 0 ){ double atoz[26] , del ; int kvar , jj ; MRI_IMAGE *flim ; float *flar ; for( jj=0 ; jj < DT_exnum ; jj++ ){ if( DT_verb ) INFO_message("Evaluating %d-th -expr\n",jj+1) ; kvar = DT_exvar[jj] ; del = DT_exdel[jj] ; if( del <= 0.0 ) del = DT_current_del ; flim = mri_new( nvals , 1 , MRI_float ) ; flar = MRI_FLOAT_PTR(flim) ; for( ii=0 ; ii < 26 ; ii++ ) atoz[ii] = 0.0 ; for( ii=0 ; ii < nvals ; ii++ ){ if( kvar >= 0 ) atoz[kvar] = ii * del ; flar[ii] = PARSER_evaluate_one( DT_excode[jj] , atoz ) ; } ADDTO_IMARR( DT_imar , flim ) ; } } /*--- from polort [10 Apr 2006] ---*/ if( DT_polort >= 0 ){ int kk ; MRI_IMAGE *flim ; float *flar ; double fac=2.0/(nvals-1.0) ; for( kk=0 ; kk <= DT_polort ; kk++ ){ flim = mri_new( nvals , 1 , MRI_float ) ; flar = MRI_FLOAT_PTR(flim) ; for( ii=0 ; ii < nvals ; ii++ ) flar[ii] = Plegendre(fac*ii-1.0,kk) ; ADDTO_IMARR( DT_imar , flim ) ; } } return ; }
int main( int argc , char * argv[] ) { int iv,nvals , nvec , ii,jj,kk , nvox ; THD_3dim_dataset * new_dset=NULL ; double * choleski ; float ** refvec , * fv , * fc , * fit ; MRI_IMAGE * flim ; /*** read input options ***/ if( argc < 2 || strncmp(argv[1],"-help",4) == 0 ) DT_Syntax() ; /*-- 20 Apr 2001: addto the arglist, if user wants to [RWCox] --*/ mainENTRY("3dDetrend main"); machdep() ; PRINT_VERSION("3dDetrend"); AFNI_logger("3dDetrend",argc,argv) ; { int new_argc ; char ** new_argv ; addto_args( argc , argv , &new_argc , &new_argv ) ; if( new_argv != NULL ){ argc = new_argc ; argv = new_argv ; } } DT_read_opts( argc , argv ) ; /*** create new dataset (empty) ***/ new_dset = EDIT_empty_copy( DT_dset ) ; /* make a copy of its header */ /* modify its header */ tross_Copy_History( DT_dset , new_dset ) ; tross_Make_History( "3dDetrend" , argc,argv , new_dset ) ; EDIT_dset_items( new_dset , ADN_prefix , DT_output_prefix , ADN_directory_name, DT_session , ADN_none ) ; /* can't re-write existing dataset */ if( THD_deathcon() && THD_is_file(DSET_HEADNAME(new_dset)) ) ERROR_exit("File %s already exists!\n",DSET_HEADNAME(new_dset) ) ; /* read input in, and attach its bricks to the output dataset */ /* (not good in a plugin, but OK in a standalone program!) */ if( DT_verb ) INFO_message("Loading input dataset bricks\n") ; DSET_mallocize( new_dset ) ; DSET_mallocize( DT_dset ) ; DSET_load( DT_dset ) ; CHECK_LOAD_ERROR(DT_dset) ; nvals = DSET_NVALS(new_dset) ; for( iv=0 ; iv < nvals ; iv++ ) EDIT_substitute_brick( new_dset , iv , DSET_BRICK_TYPE(DT_dset,iv) , DSET_ARRAY(DT_dset,iv) ) ; if( DT_norm && DSET_BRICK_TYPE(new_dset,0) != MRI_float ){ INFO_message("Turning -normalize option off (input not in float format)"); DT_norm = 0 ; } /* load reference (detrending) vectors; setup to do least squares fitting of each voxel */ nvec = 0 ; for( ii=0 ; ii < IMARR_COUNT(DT_imar) ; ii++ ) /* number of detrending vectors */ nvec += IMARR_SUBIMAGE(DT_imar,ii)->ny ; refvec = (float **) malloc( sizeof(float *)*nvec ) ; for( kk=ii=0 ; ii < IMARR_COUNT(DT_imar) ; ii++ ){ fv = MRI_FLOAT_PTR( IMARR_SUBIMAGE(DT_imar,ii) ) ; for( jj=0 ; jj < IMARR_SUBIMAGE(DT_imar,ii)->ny ; jj++ ) /* compute ptr */ refvec[kk++] = fv + ( jj * IMARR_SUBIMAGE(DT_imar,ii)->nx ) ; /* to vectors */ } fit = (float *) malloc( sizeof(float) * nvals ) ; /* will get fit to voxel data */ /*--- do the all-voxels-together case ---*/ if( !DT_byslice ){ choleski = startup_lsqfit( nvals , NULL , nvec , refvec ) ; if( choleski == NULL ) ERROR_exit("Choleski factorization fails: linearly dependent vectors!\n") ; /* loop over voxels, fitting and detrending (or replacing) */ nvox = DSET_NVOX(new_dset) ; if( DT_verb ) INFO_message("Computing voxel fits\n") ; for( kk=0 ; kk < nvox ; kk++ ){ flim = THD_extract_series( kk , new_dset , 0 ) ; /* data */ fv = MRI_FLOAT_PTR(flim) ; fc = delayed_lsqfit( nvals, fv, nvec, refvec, choleski ) ; /* coef */ for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = 0.0 ; for( jj=0 ; jj < nvec ; jj++ ) for( ii=0 ; ii < nvals ; ii++ ) fit[ii] += fc[jj] * refvec[jj][ii] ; /* fit */ if( !DT_replace ) /* remove */ for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = fv[ii] - fit[ii] ; if( DT_norm ) THD_normalize( nvals , fit ) ; /* 23 Nov 1999 */ THD_insert_series( kk, new_dset, nvals, MRI_float, fit, 0 ) ; free(fc) ; mri_free(flim) ; } free(choleski) ; /*- end of all-voxels-together case -*/ } #ifdef ALLOW_BYSLICE else { /*- start of slice case [08 Dec 1999] -*/ int ksl , nslice , tt , nx,ny , nxy , kxy ; MRI_IMAGE * vim ; /* make separate space for the slice-wise detrending vectors */ for( kk=ii=0 ; ii < DT_nvector ; ii++ ){ for( jj=0 ; jj < IMARR_SUBIMAGE(DT_imar,ii)->ny ; jj++ ) /* replace ptrs */ refvec[kk++] = (float *) malloc( sizeof(float) * nvals ) ; /* to vectors */ } nslice = DSET_NZ(new_dset) ; nxy = DSET_NX(new_dset) * DSET_NY(new_dset) ; /* loop over slices */ for( ksl=0 ; ksl < nslice ; ksl++ ){ if( DT_verb ) INFO_message("Computing voxel fits for slice %d\n",ksl) ; /* extract slice vectors from input interlaced vectors */ for( kk=ii=0 ; ii < DT_nvector ; ii++ ){ /* loop over vectors */ vim = IMARR_SUBIMAGE(DT_imar,ii) ; /* ii-th vector image */ nx = vim->nx ; ny = vim->ny ; /* dimensions */ for( jj=0 ; jj < ny ; jj++ ){ /* loop over columns */ fv = MRI_FLOAT_PTR(vim) + (jj*nx) ; /* ptr to column */ for( tt=0 ; tt < nvals ; tt++ ) /* loop over time */ refvec[kk][tt] = fv[ksl+tt*nslice] ; /* data point */ } } /* initialize fitting for this slice */ choleski = startup_lsqfit( nvals , NULL , nvec , refvec ) ; if( choleski == NULL ) ERROR_exit("Choleski fails: linearly dependent vectors at slice %d\n",ksl) ; /* loop over voxels in this slice */ for( kxy=0 ; kxy < nxy ; kxy++ ){ kk = kxy + ksl*nxy ; /* 3D index */ flim = THD_extract_series( kk , new_dset , 0 ) ; /* data */ fv = MRI_FLOAT_PTR(flim) ; fc = delayed_lsqfit( nvals, fv, nvec, refvec, choleski ) ; /* coef */ for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = 0.0 ; for( jj=0 ; jj < nvec ; jj++ ) for( ii=0 ; ii < nvals ; ii++ ) fit[ii] += fc[jj] * refvec[jj][ii] ; /* fit */ if( !DT_replace ) /* remove */ for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = fv[ii] - fit[ii] ; if( DT_norm ) THD_normalize( nvals , fit ) ; /* 23 Nov 1999 */ THD_insert_series( kk, new_dset, nvals, MRI_float, fit, 0 ) ; free(fc) ; mri_free(flim) ; } free(choleski) ; } /* end of loop over slices */ } /*- end of -byslice case -*/ #endif /*-- done done done done --*/ DSET_write(new_dset) ; if( DT_verb ) WROTE_DSET(new_dset) ; exit(0) ; }
MRI_IMARR * THD_extract_many_series( int ns, int *ind, THD_3dim_dataset *dset ) { MRI_IMARR *imar ; /* output */ MRI_IMAGE *im ; int nv , ival , kk ; char *iar ; /* brick in the input */ float **far ; /* 27 Feb 2003: ptrs to output */ ENTRY("THD_extract_many_series") ; if( ns <= 0 || ind == NULL | dset == NULL ) RETURN( NULL ); /* try to load dataset */ nv = dset->dblk->nvals ; iar = DSET_ARRAY(dset,0) ; if( iar == NULL ){ /* if data needs to be loaded from disk */ (void) THD_load_datablock( dset->dblk ) ; iar = DSET_ARRAY(dset,0) ; if( iar == NULL ){ static int nerr=0 ; if( nerr < 2 ){ ERROR_message("Can't load dataset %s",DSET_HEADNAME(dset)); nerr++; } RETURN( NULL ); } } /* create output */ far = (float **) malloc(sizeof(float *)*ns) ; /* 27 Feb 2003 */ NULL_CHECK(far) ; INIT_IMARR(imar) ; for( kk=0 ; kk < ns ; kk++ ){ im = mri_new( nv , 1 , MRI_float ) ; /* N.B.: now does 0 fill */ far[kk] = MRI_FLOAT_PTR(im) ; /* ptr to kk-th output series */ ADDTO_IMARR(imar,im) ; } /* fill the output */ switch( DSET_BRICK_TYPE(dset,0) ){ default: /* don't know what to do --> return nada */ DESTROY_IMARR(imar) ; free(far) ; RETURN( NULL ); case MRI_byte:{ byte * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (byte *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = (float)bar[ind[kk]] ; } } } } break ; case MRI_short:{ short * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (short *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = (float)bar[ind[kk]] ; } } } } break ; case MRI_float:{ float * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (float *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = bar[ind[kk]] ; } } } } break ; #if 0 case MRI_int:{ int * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (int *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = bar[ind[kk]] ; } } } } break ; case MRI_double:{ double * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (double *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = (float)bar[ind[kk]] ; } } } } break ; #endif case MRI_complex:{ complex * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (complex *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = bar[ind[kk]].r ; } } } } break ; } /* scale outputs, if needed */ if( THD_need_brick_factor(dset) ){ MRI_IMAGE *qim ; for( kk=0 ; kk < ns ; kk++ ){ im = IMARR_SUBIMAGE(imar,kk) ; qim = mri_mult_to_float( dset->dblk->brick_fac , im ) ; mri_free(im) ; IMARR_SUBIMAGE(imar,kk) = qim ; } } #if 0 /* 27 Feb 2003 */ /* convert to floats, if needed */ if( IMARR_SUBIMAGE(imar,0)->kind != MRI_float ){ MRI_IMAGE * qim ; for( kk=0 ; kk < ns ; kk++ ){ im = IMARR_SUBIMAGE(imar,kk) ; qim = mri_to_float( im ) ; mri_free(im) ; IMARR_SUBIMAGE(imar,kk) = qim ; } } #endif /* add time axis stuff to output images, if present */ if( dset->taxis != NULL ){ float zz , tt ; int kz ; for( kk=0 ; kk < ns ; kk++ ){ kz = ind[kk] / ( dset->daxes->nxx * dset->daxes->nyy ) ; zz = dset->daxes->zzorg + kz * dset->daxes->zzdel ; tt = THD_timeof( 0 , zz , dset->taxis ) ; im = IMARR_SUBIMAGE(imar,kk) ; im->xo = tt ; im->dx = dset->taxis->ttdel ; /* origin and delta */ if( dset->taxis->units_type == UNITS_MSEC_TYPE ){ /* convert to sec */ im->xo *= 0.001 ; im->dx *= 0.001 ; } } } else { for( kk=0 ; kk < ns ; kk++ ){ im = IMARR_SUBIMAGE(imar,kk) ; im->xo = 0.0 ; im->dx = 1.0 ; } } free(far) ; RETURN(imar); }
char * IMREG_main( PLUGIN_interface * plint ) { MCW_idcode * idc ; /* input dataset idcode */ THD_3dim_dataset * old_dset , * new_dset ; /* input and output datasets */ char * new_prefix , * str ; /* strings from user */ int base , ntime , datum , nx,ny,nz , ii,kk , npix ; float dx,dy,dz ; MRI_IMARR * ims_in , * ims_out ; MRI_IMAGE * im , * imbase ; byte ** bptr = NULL , ** bout = NULL ; short ** sptr = NULL , ** sout = NULL ; float ** fptr = NULL , ** fout = NULL ; float * dxar = NULL , * dyar = NULL , * phiar = NULL ; /*--------------------------------------------------------------------*/ /*----- Check inputs from AFNI to see if they are reasonable-ish -----*/ /*--------- go to first input line ---------*/ PLUTO_next_option(plint) ; idc = PLUTO_get_idcode(plint) ; /* get dataset item */ old_dset = PLUTO_find_dset(idc) ; /* get ptr to dataset */ if( old_dset == NULL ) return "*************************\n" "Cannot find Input Dataset\n" "*************************" ; ntime = DSET_NUM_TIMES(old_dset) ; if( ntime < 2 ) return "*****************************\n" "Dataset has only 1 time point\n" "*****************************" ; ii = DSET_NVALS_PER_TIME(old_dset) ; if( ii > 1 ) return "************************************\n" "Dataset has > 1 value per time point\n" "************************************" ; nx = old_dset->daxes->nxx ; dx = old_dset->daxes->xxdel ; ny = old_dset->daxes->nyy ; dy = old_dset->daxes->yydel ; npix = nx*ny ; nz = old_dset->daxes->nzz ; dz = old_dset->daxes->zzdel ; if( nx != ny || fabs(dx) != fabs(dy) ) { #ifdef IMREG_DEBUG fprintf(stderr,"\nIMREG: nx=%d ny=%d nz=%d dx=%f dy=%f dz=%f\n", nx,ny,nz,dx,dy,dz ) ; #endif return "***********************************\n" "Dataset does not have square slices\n" "***********************************" ; } new_prefix = PLUTO_get_string(plint) ; /* get string item (the output prefix) */ if( ! PLUTO_prefix_ok(new_prefix) ) /* check if it is OK */ return "************************\n" "Output Prefix is illegal\n" "************************" ; /*--------- go to next input line ---------*/ PLUTO_next_option(plint) ; base = PLUTO_get_number(plint) ; if( base >= ntime ) return "********************\n" "Base value too large\n" "********************" ; /*--------- see if the 3rd option line is present --------*/ str = PLUTO_get_optiontag( plint ) ; if( str != NULL ) { float fsig , fdxy , fdph ; fsig = PLUTO_get_number(plint) * 0.42466090 ; fdxy = PLUTO_get_number(plint) ; fdph = PLUTO_get_number(plint) ; mri_align_params( 0 , 0.0,0.0,0.0 , fsig,fdxy,fdph ) ; /* fprintf(stderr,"Set fine params = %f %f %f\n",fsig,fdxy,fdph) ; */ } /*------------- ready to compute new dataset -----------*/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: loading dataset\n") ; #endif DSET_load( old_dset ) ; /*** 1) Copy the dataset in toto ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: Copying dataset\n") ; #endif new_dset = PLUTO_copy_dset( old_dset , new_prefix ) ; if( new_dset == NULL ) return "****************************\n" "Failed to copy input dataset\n" "****************************" ; /*** 2) Make an array of empty images ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: making empty images\n") ; #endif datum = DSET_BRICK_TYPE(new_dset,0) ; INIT_IMARR(ims_in) ; for( ii=0 ; ii < ntime ; ii++ ) { im = mri_new_vol_empty( nx , ny , 1 , datum ) ; ADDTO_IMARR(ims_in,im) ; } imbase = mri_new_vol_empty( nx , ny , 1 , datum ) ; dxar = (float *) malloc( sizeof(float) * ntime ) ; dyar = (float *) malloc( sizeof(float) * ntime ) ; phiar = (float *) malloc( sizeof(float) * ntime ) ; /*** 3) Get pointers to sub-bricks in old and new datasets ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: getting input brick pointers\n") ; #endif switch( datum ) { /* pointer type depends on input datum type */ case MRI_byte: bptr = (byte **) malloc( sizeof(byte *) * ntime ) ; bout = (byte **) malloc( sizeof(byte *) * ntime ) ; for( ii=0 ; ii < ntime ; ii++ ) { bptr[ii] = (byte *) DSET_ARRAY(old_dset,ii) ; bout[ii] = (byte *) DSET_ARRAY(new_dset,ii) ; } break ; case MRI_short: sptr = (short **) malloc( sizeof(short *) * ntime ) ; sout = (short **) malloc( sizeof(short *) * ntime ) ; for( ii=0 ; ii < ntime ; ii++ ) { sptr[ii] = (short *) DSET_ARRAY(old_dset,ii) ; sout[ii] = (short *) DSET_ARRAY(new_dset,ii) ; } #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: sptr[0] = %p sout[0] = %p\n",sptr[0],sout[0]) ; #endif break ; case MRI_float: fptr = (float **) malloc( sizeof(float *) * ntime ) ; fout = (float **) malloc( sizeof(float *) * ntime ) ; for( ii=0 ; ii < ntime ; ii++ ) { fptr[ii] = (float *) DSET_ARRAY(old_dset,ii) ; fout[ii] = (float *) DSET_ARRAY(new_dset,ii) ; } break ; } /*** 4) Loop over slices ***/ PLUTO_popup_meter(plint) ; for( kk=0 ; kk < nz ; kk++ ) { /*** 4a) Setup ims_in images to point to input slices ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: slice %d -- setup input images\n",kk) ; #endif for( ii=0 ; ii < ntime ; ii++ ) { im = IMARR_SUBIMAGE(ims_in,ii) ; switch( datum ) { case MRI_byte: mri_fix_data_pointer( bptr[ii] + kk*npix, im ) ; break ; case MRI_short: mri_fix_data_pointer( sptr[ii] + kk*npix, im ) ; break ; case MRI_float: mri_fix_data_pointer( fptr[ii] + kk*npix, im ) ; break ; } } /*** 4b) Setup im to point to base image ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: slice %d -- setup base image\n",kk) ; #endif switch( datum ) { case MRI_byte: mri_fix_data_pointer( bptr[base] + kk*npix, imbase ) ; break ; case MRI_short: mri_fix_data_pointer( sptr[base] + kk*npix, imbase ) ; break ; case MRI_float: mri_fix_data_pointer( fptr[base] + kk*npix, imbase ) ; break ; } /*** 4c) Register this slice at all times ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: slice %d -- register\n",kk) ; #endif ims_out = mri_align_dfspace( imbase , NULL , ims_in , ALIGN_REGISTER_CODE , dxar,dyar,phiar ) ; if( ims_out == NULL ) fprintf(stderr,"IMREG: mri_align_dfspace return NULL\n") ; /*** 4d) Put the output back in on top of the input; note that the output is always in MRI_float format ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: slice %d -- put output back into dataset\n",kk) ; #endif for( ii=0 ; ii < ntime ; ii++ ) { switch( datum ) { case MRI_byte: im = mri_to_mri( MRI_byte , IMARR_SUBIMAGE(ims_out,ii) ) ; memcpy( bout[ii] + kk*npix , MRI_BYTE_PTR(im) , sizeof(byte)*npix ) ; mri_free(im) ; break ; case MRI_short: #ifdef IMREG_DEBUG if( ii==0 )fprintf(stderr,"IMREG: conversion to short at ii=%d\n",ii) ; #endif im = mri_to_mri( MRI_short , IMARR_SUBIMAGE(ims_out,ii) ) ; #ifdef IMREG_DEBUG if( ii==0 )fprintf(stderr,"IMREG: copying to %p from %p\n",sout[ii] + kk*npix,MRI_SHORT_PTR(im)) ; #endif memcpy( sout[ii] + kk*npix , MRI_SHORT_PTR(im) , sizeof(short)*npix ) ; #ifdef IMREG_DEBUG if( ii==0 )fprintf(stderr,"IMREG: freeing\n") ; #endif mri_free(im) ; break ; case MRI_float: im = IMARR_SUBIMAGE(ims_out,ii) ; memcpy( fout[ii] + kk*npix , MRI_FLOAT_PTR(im) , sizeof(float)*npix ) ; break ; } } PLUTO_set_meter(plint, (100*(kk+1))/nz ) ; /*** 4e) Destroy the output images ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: destroying aligned output\n") ; #endif DESTROY_IMARR( ims_out ) ; } /*** 5) Destroy the empty images and other workspaces ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: destroy workspaces\n") ; #endif mri_clear_data_pointer(imbase) ; mri_free(imbase) ; for( ii=0 ; ii < ntime ; ii++ ) { im = IMARR_SUBIMAGE(ims_in,ii) ; mri_clear_data_pointer(im) ; } DESTROY_IMARR(ims_in) ; FREE_WORKSPACE ; /*------------- let AFNI know about the new dataset ------------*/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: send result to AFNI\n") ; #endif PLUTO_add_dset( plint , new_dset , DSET_ACTION_MAKE_CURRENT ) ; return NULL ; /* null string returned means all was OK */ }