/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ #include "mrilib.h" /*-----------------------------------------------------------------------------*/ /*! Time shift a dataset to a common origin. Stores the data on top of the input dataset! Return value is 0 for good processing, nonzero for errors. This routine is like doing the default actions of 3dTshift (from which the code is adapted). -- RWCox -- 15 Feb 2001 -------------------------------------------------------------------------------*/ /*-- At present, these static variables are not alterable from the outside; they correspond to the command line options of 3dTshift. In the future, there may be a way to changes these to affect things. --*/ static float TS_TR = 0.0 ; static int TS_tunits = UNITS_SEC_TYPE ; static float * TS_tpat = NULL ; static float TS_tzero = -1.0 ; static int TS_slice = -1 ; static int TS_rlt = 0 ; /* 0=add both in; 1=add neither; 2=add mean */ static int TS_mode = MRI_FOURIER ; /* one of MRI_FOURIER MRI_CUBIC MRI_QUINTIC MRI_HEPTIC MRI_LINEAR */ int THD_dataset_tshift( THD_3dim_dataset * TS_dset , int ignore ) { int nzz, ii,jj,kk , ntt,nxx,nyy,nxy , nup , freepat=0 ; float tomax,tomin , tshift , fmin,fmax , gmin=0,gmax=0 , f0,f1 , g0,g1 ; float ffmin=0,ffmax=0 , ggmin=0,ggmax=0 ; MRI_IMAGE *flim , *glim=NULL ; float *far , *gar ; ENTRY("THD_dataset_tshift") ; /*- extract dataset values, check for errors -*/ if( !ISVALID_DSET(TS_dset) || ignore < 0 ) RETURN(1) ; nxx = DSET_NX(TS_dset) ; /* get dimensions */ nyy = DSET_NY(TS_dset) ; nxy = nxx * nyy ; nzz = DSET_NZ(TS_dset) ; ntt = DSET_NVALS(TS_dset) ; if( ignore > ntt-4 ) RETURN(1) ; if( DSET_NVALS(TS_dset) < 2 ) RETURN(1) ; if( TS_slice >= nzz ) RETURN(1) ; if( TS_dset->taxis == NULL ){ if( TS_TR == 0.0 || TS_tpat == NULL ) RETURN(1) ; } else if( TS_tpat == NULL && TS_dset->taxis->toff_sl == NULL ){ RETURN(1) ; } if( TS_TR == 0.0 ){ /* set TR from dataset */ TS_TR = DSET_TIMESTEP(TS_dset) ; TS_tunits = TS_dset->taxis->units_type ; } if( TS_tpat == NULL ){ if( TS_dset->taxis->nsl < nzz ) RETURN(1) ; TS_tpat = (float *) malloc( sizeof(float) * nzz ) ; memcpy( TS_tpat , TS_dset->taxis->toff_sl , sizeof(float)*nzz ) ; freepat = 1 ; } tomin = WAY_BIG ; tomax = -WAY_BIG ; /* check pattern */ for( ii=0 ; ii < nzz ; ii++ ){ if( TS_tpat[ii] > tomax ) tomax = TS_tpat[ii] ; if( TS_tpat[ii] < tomin ) tomin = TS_tpat[ii] ; } if( tomin < 0.0 || tomax > TS_TR ) RETURN(1) ; else if( tomin >= tomax ) RETURN(1) ; if( TS_slice >= 0 && TS_slice < nzz ){ /* set common time point */ TS_tzero = TS_tpat[TS_slice] ; } else if( TS_tzero < 0.0 ){ TS_tzero = 0.0 ; for( ii=0 ; ii < nzz ; ii++ ) TS_tzero += TS_tpat[ii] ; TS_tzero /= nzz ; } /*- reconfigure the time axis -*/ DSET_mallocize( TS_dset) ; DSET_load( TS_dset ) ; if( !DSET_LOADED(TS_dset) ) RETURN(1) ; EDIT_dset_items( TS_dset , ADN_ntt , ntt , /* in case not already set */ ADN_ttdel , TS_TR , /* may have changed */ ADN_tunits , TS_tunits , /* may have changed */ ADN_nsl , 0 , /* will have no offsets when done */ ADN_ttorg , 0.0 , /* in case not already set */ ADN_ttdur , 0.0 , /* in case not already set */ ADN_none ) ; /*---- do the temporal shifting! ----*/ SHIFT_set_method( TS_mode ) ; nup = csfft_nextup_one35( ntt+4 ) ; for( kk=0 ; kk < nzz ; kk++ ){ /* loop over slices */ tshift = (TS_tzero - TS_tpat[kk]) / TS_TR ; /* rightward fractional shift */ #if 1 tshift = -tshift ; /* 24 Apr 2003 -- OOG */ #endif if( fabs(tshift) < 0.001 ) continue ; /* skip this slice */ for( ii=0 ; ii < nxy ; ii+=2 ){ /* loop over voxel pairs in slice */ flim = THD_extract_series( ii+kk*nxy , TS_dset , 0 ); /* get this voxel */ far = MRI_FLOAT_PTR(flim) ; if( TS_rlt == 0 ){ /* range of data: before */ for( ffmin=ffmax=far[ignore],jj=ignore+1 ; jj < ntt ; jj++ ){ if( far[jj] < ffmin ) ffmin = far[jj] ; else if( far[jj] > ffmax ) ffmax = far[jj] ; } } THD_linear_detrend( ntt-ignore , far+ignore , &f0,&f1 ) ; /* remove trend */ for( fmin=fmax=far[ignore],jj=ignore+1 ; jj < ntt ; jj++ ){ if( far[jj] < fmin ) fmin = far[jj] ; /* range of data: after */ else if( far[jj] > fmax ) fmax = far[jj] ; } if( ii < nxy-1 ){ /* get next voxel */ glim = THD_extract_series( ii+kk*nxy+1 , TS_dset , 0 ) ; gar = MRI_FLOAT_PTR(glim) ; if( TS_rlt == 0 ){ for( ggmin=ggmax=gar[ignore],jj=ignore+1 ; jj < ntt ; jj++ ){ if( gar[jj] < ggmin ) ggmin = gar[jj] ; else if( gar[jj] > ggmax ) ggmax = gar[jj] ; } } THD_linear_detrend( ntt-ignore , gar+ignore , &g0,&g1 ) ; for( gmin=gmax=gar[ignore],jj=ignore+1 ; jj < ntt ; jj++ ){ if( gar[jj] < gmin ) gmin = gar[jj] ; else if( gar[jj] > gmax ) gmax = gar[jj] ; } } else { gar = NULL ; } if( gar != NULL ) SHIFT_two_rows( ntt-ignore,nup, tshift,far+ignore , tshift, gar+ignore ) ; else SHIFT_two_rows( ntt-ignore,nup, tshift,far+ignore , tshift, NULL ) ; for( jj=ignore ; jj < ntt ; jj++ ){ if( far[jj] < fmin ) far[jj] = fmin ; /* clip to input range */ else if( far[jj] > fmax ) far[jj] = fmax ; switch( TS_rlt ){ /* restore trend? */ case 0: far[jj] += (f0 + (jj-ignore)*f1) ; if( far[jj] < ffmin ) far[jj] = ffmin ; else if( far[jj] > ffmax ) far[jj] = ffmax ; break ; case 2: far[jj] += f0 ; break ; } } if( gar != NULL ){ for( jj=ignore ; jj < ntt ; jj++ ){ if( gar[jj] < gmin ) gar[jj] = gmin ; else if( gar[jj] > gmax ) gar[jj] = gmax ; switch( TS_rlt ){ case 0: gar[jj] += (g0 + (jj-ignore)*g1) ; if( gar[jj] < ggmin ) gar[jj] = ggmin ; else if( gar[jj] > ggmax ) gar[jj] = ggmax ; break ; case 2: gar[jj] += g0 ; break ; } } } /* put back into dataset */ THD_insert_series( ii+kk*nxy , TS_dset , ntt , MRI_float , far , 0 ) ; if( gar != NULL ) THD_insert_series( ii+kk*nxy+1 , TS_dset , ntt , MRI_float , gar , 0 ) ; /* throw out the trash */ mri_free(flim) ; if( gar != NULL ) mri_free(glim) ; } /* end of loop over voxel pairs */ } /* end of loop over slices */ if( freepat ){ free(TS_tpat) ; TS_tpat = NULL ; } /* resets */ TS_tzero = -1.0 ; TS_TR = 0.0 ; TS_tunits = UNITS_SEC_TYPE ; RETURN(0) ; }