00001
00002
00003
00004
00005
00006
00007 #include "mrilib.h"
00008 #include "parser.h"
00009
00010
00011
00012
00013
00014
00015
00016 #define ALLOW_BYSLICE
00017
00018 static THD_3dim_dataset * DT_dset = NULL ;
00019 static MRI_IMARR * DT_imar = NULL ;
00020 static char ** DT_expr = NULL ;
00021 static PARSER_code ** DT_excode = NULL ;
00022 static float * DT_exdel = NULL ;
00023 static int * DT_exvar = NULL ;
00024 static int DT_exnum = 0 ;
00025 static int DT_verb = 0 ;
00026 static int DT_replace = 0 ;
00027 static int DT_norm = 0 ;
00028 static int DT_byslice = 0 ;
00029 static int DT_nvector = 0 ;
00030
00031 static float DT_current_del = -1.0 ;
00032
00033 static char DT_output_prefix[THD_MAX_PREFIX] = "detrend" ;
00034 static char DT_session[THD_MAX_NAME] = "./" ;
00035
00036
00037
00038 void DT_read_opts( int , char ** ) ;
00039 void DT_Syntax(void) ;
00040
00041
00042
00043
00044
00045 void DT_read_opts( int argc , char * argv[] )
00046 {
00047 int nopt = 1 , nvals , ii , nvcheck ;
00048
00049 INIT_IMARR(DT_imar) ;
00050
00051 while( nopt < argc && argv[nopt][0] == '-' ){
00052
00053
00054
00055 if( strncmp(argv[nopt],"-prefix",6) == 0 ){
00056 nopt++ ;
00057 if( nopt >= argc ){
00058 fprintf(stderr,"*** need argument after -prefix!\n") ; exit(1) ;
00059 }
00060 MCW_strncpy( DT_output_prefix , argv[nopt++] , THD_MAX_PREFIX ) ;
00061 continue ;
00062 }
00063
00064
00065
00066 if( strncmp(argv[nopt],"-session",6) == 0 ){
00067 nopt++ ;
00068 if( nopt >= argc ){
00069 fprintf(stderr,"*** need argument after -session!\n") ; exit(1) ;
00070 }
00071 MCW_strncpy( DT_session , argv[nopt++] , THD_MAX_NAME ) ;
00072 continue ;
00073 }
00074
00075
00076
00077 if( strncmp(argv[nopt],"-verb",5) == 0 ){
00078 DT_verb++ ;
00079 nopt++ ; continue ;
00080 }
00081
00082
00083
00084 if( strncmp(argv[nopt],"-replace",5) == 0 ){
00085 DT_replace++ ;
00086 nopt++ ; continue ;
00087 }
00088
00089 #ifdef ALLOW_BYSLICE
00090
00091
00092 if( strncmp(argv[nopt],"-byslice",5) == 0 ){
00093 DT_byslice++ ;
00094 nopt++ ; continue ;
00095 }
00096 #endif
00097
00098
00099
00100 if( strncmp(argv[nopt],"-normalize",5) == 0 ){
00101 DT_norm++ ;
00102 nopt++ ; continue ;
00103 }
00104
00105
00106
00107 if( strncmp(argv[nopt],"-vector",4) == 0 ){
00108 MRI_IMAGE * flim ;
00109 nopt++ ;
00110 if( nopt >= argc ){
00111 fprintf(stderr,"*** need argument after -vector!\n"); exit(1);
00112 }
00113 flim = mri_read_1D( argv[nopt++] ) ;
00114 if( flim == NULL ){
00115 fprintf(stderr,"*** can't read -vector %s\n",argv[nopt-1]); exit(1);
00116 }
00117 ADDTO_IMARR(DT_imar,flim) ;
00118 if( DT_verb )
00119 fprintf(stderr,"+++ Read in %s: rows=%d cols=%d\n",
00120 argv[nopt-1],flim->ny,flim->nx ) ;
00121 continue ;
00122 }
00123
00124
00125
00126 if( strncmp(argv[nopt],"-del",4) == 0 ){
00127 nopt++ ;
00128 if( nopt >= argc ){
00129 fprintf(stderr,"*** need argument after -del!\n"); exit(1);
00130 }
00131 DT_current_del = strtod( argv[nopt++] , NULL ) ;
00132 if( DT_verb )
00133 fprintf(stderr,"+++ Set expression stepsize = %g\n",DT_current_del) ;
00134 continue ;
00135 }
00136
00137
00138
00139 if( strncmp(argv[nopt],"-expr",4) == 0 ){
00140 int nexp , qvar , kvar ;
00141 char sym[4] ;
00142
00143 nopt++ ;
00144 if( nopt >= argc ){
00145 fprintf(stderr,"*** need argument after -expr!\n"); exit(1);
00146 }
00147
00148 nexp = DT_exnum + 1 ;
00149 if( DT_exnum == 0 ){
00150 DT_expr = (char **) malloc( sizeof(char *) ) ;
00151 DT_excode = (PARSER_code **) malloc( sizeof(PARSER_code *) ) ;
00152 DT_exdel = (float *) malloc( sizeof(float) ) ;
00153 DT_exvar = (int *) malloc( sizeof(int) ) ;
00154 } else {
00155 DT_expr = (char **) realloc( DT_expr ,
00156 sizeof(char *)*nexp ) ;
00157 DT_excode = (PARSER_code **) realloc( DT_excode ,
00158 sizeof(PARSER_code *)*nexp ) ;
00159 DT_exdel = (float *) realloc( DT_exdel ,
00160 sizeof(float)*nexp) ;
00161 DT_exvar = (int *) realloc( DT_exvar ,
00162 sizeof(int)*nexp) ;
00163 }
00164 DT_expr[DT_exnum] = argv[nopt] ;
00165 DT_exdel[DT_exnum] = DT_current_del ;
00166 DT_excode[DT_exnum] = PARSER_generate_code( argv[nopt] ) ;
00167 if( DT_excode[DT_exnum] == NULL ){
00168 fprintf(stderr,"*** Illegal expression: %s\n",argv[nopt]); exit(1);
00169 }
00170
00171 qvar = 0 ; kvar = -1 ;
00172 for( ii=0 ; ii < 26 ; ii++ ){
00173 sym[0] = 'A' + ii ; sym[1] = '\0' ;
00174 if( PARSER_has_symbol(sym,DT_excode[DT_exnum]) ){
00175 qvar++ ; if( kvar < 0 ) kvar = ii ;
00176 if( DT_verb )
00177 fprintf(stderr,"+++ Found expression symbol %s\n",sym) ;
00178 }
00179 }
00180 if( qvar > 1 ){
00181 fprintf(stderr,"*** Expression %s should have just one symbol!\n",
00182 DT_expr[DT_exnum] ) ;
00183 exit(1) ;
00184 }
00185 DT_exvar[DT_exnum] = kvar ;
00186
00187 DT_exnum = nexp ; nopt++ ; continue ;
00188 }
00189
00190
00191
00192 fprintf(stderr,"*** Unknown option: %s\n",argv[nopt]) ; exit(1) ;
00193
00194 }
00195
00196
00197
00198 if( nopt >= argc ){
00199 fprintf(stderr,"*** No input dataset!?\n") ; exit(1) ;
00200 }
00201
00202 DT_nvector = IMARR_COUNT(DT_imar) ;
00203 if( DT_nvector + DT_exnum == 0 ){
00204 fprintf(stderr,"*** No -vector or -expr options!?\n") ; exit(1) ;
00205 }
00206 #ifdef ALLOW_BYSLICE
00207 if( DT_nvector == 0 && DT_byslice ){
00208 fprintf(stderr,"*** No -vector option supplied with -byslice!?\n"); exit(1);
00209 }
00210 #endif
00211
00212
00213
00214 DT_dset = THD_open_dataset( argv[nopt] ) ;
00215 if( DT_dset == NULL ){
00216 fprintf(stderr,"*** Can't open dataset %s\n",argv[nopt]) ; exit(1) ;
00217 }
00218
00219 DT_current_del = DSET_TR(DT_dset) ;
00220 if( DT_current_del <= 0.0 ){
00221 DT_current_del = 1.0 ;
00222 if( DT_verb )
00223 fprintf(stderr,"+++ Input has no TR value; setting TR=1.0\n") ;
00224 } else if( DT_verb ){
00225 fprintf(stderr,"+++ Input has TR=%g\n",DT_current_del) ;
00226 }
00227
00228
00229
00230 nvcheck = nvals = DSET_NVALS(DT_dset) ;
00231 #ifdef ALLOW_BYSLICE
00232 if( DT_byslice ) nvcheck *= DSET_NZ(DT_dset) ;
00233 #endif
00234 for( ii=0 ; ii < DT_nvector ; ii++ ){
00235 if( IMARR_SUBIMAGE(DT_imar,ii)->nx < nvcheck ){
00236 fprintf(stderr,"*** %d-th -vector is shorter than dataset!\n",ii+1) ;
00237 exit(1) ;
00238 }
00239 }
00240
00241
00242
00243 if( DT_exnum > 0 ){
00244 double atoz[26] , del ;
00245 int kvar , jj ;
00246 MRI_IMAGE * flim ;
00247 float * flar ;
00248
00249 for( jj=0 ; jj < DT_exnum ; jj++ ){
00250 if( DT_verb ) fprintf(stderr,"+++ Evaluating %d-th -expr\n",jj+1) ;
00251 kvar = DT_exvar[jj] ;
00252 del = DT_exdel[jj] ;
00253 if( del <= 0.0 ) del = DT_current_del ;
00254 flim = mri_new( nvals , 1 , MRI_float ) ;
00255 flar = MRI_FLOAT_PTR(flim) ;
00256 for( ii=0 ; ii < 26 ; ii++ ) atoz[ii] = 0.0 ;
00257 for( ii=0 ; ii < nvals ; ii++ ){
00258 if( kvar >= 0 ) atoz[kvar] = ii * del ;
00259 flar[ii] = PARSER_evaluate_one( DT_excode[jj] , atoz ) ;
00260 }
00261 ADDTO_IMARR( DT_imar , flim ) ;
00262 }
00263 }
00264
00265 return ;
00266 }
00267
00268
00269
00270 void DT_Syntax(void)
00271 {
00272 printf(
00273 "Usage: 3dDetrend [options] dataset\n"
00274 "This program removes components from voxel time series using\n"
00275 "linear least squares. Each voxel is treated independently.\n"
00276 "The input dataset may have a sub-brick selector string; otherwise,\n"
00277 "all sub-bricks will be used.\n\n"
00278 ) ;
00279
00280 printf(
00281 "General Options:\n"
00282 " -prefix pname = Use 'pname' for the output dataset prefix name.\n"
00283 " [default='detrend']\n"
00284 " -session dir = Use 'dir' for the output dataset session directory.\n"
00285 " [default='./'=current working directory]\n"
00286 " -verb = Print out some verbose output as the program runs.\n"
00287 " -replace = Instead of subtracting the fit from each voxel,\n"
00288 " replace the voxel data with the time series fit.\n"
00289 " -normalize = Normalize each output voxel time series; that is,\n"
00290 " make the sum-of-squares equal to 1.\n"
00291 " N.B.: This option is only valid if the input dataset is\n"
00292 " stored as floats!\n"
00293 #ifdef ALLOW_BYSLICE
00294 " -byslice = Treat each input vector (infra) as describing a set of\n"
00295 " time series interlaced across slices. If NZ is the\n"
00296 " number of slices and NT is the number of time points,\n"
00297 " then each input vector should have NZ*NT values when\n"
00298 " this option is used (usually, they only need NT values).\n"
00299 " The values must be arranged in slice order, then time\n"
00300 " order, in each vector column, as shown here:\n"
00301 " f(z=0,t=0) // first slice, first time\n"
00302 " f(z=1,t=0) // second slice, first time\n"
00303 " ...\n"
00304 " f(z=NZ-1,t=0) // last slice, first time\n"
00305 " f(z=0,t=1) // first slice, second time\n"
00306 " f(z=1,t=1) // second slice, second time\n"
00307 " ...\n"
00308 " f(z=NZ-1,t=NT-1) // last slice, last time\n"
00309 #endif
00310 "\n"
00311 "Component Options:\n"
00312 "These options determine the components that will be removed from\n"
00313 "each dataset voxel time series. They may be repeated to specify\n"
00314 "multiple regression. At least one component must be specified.\n"
00315 "\n"
00316 " -vector vvv = Remove components proportional to the columns vectors\n"
00317 " of the ASCII *.1D file 'vvv'. You may use a\n"
00318 " sub-vector selector string to specify which columns\n"
00319 " to use; otherwise, all columns will be used.\n"
00320 " For example:\n"
00321 " -vector 'xyzzy.1D[3,5]'\n"
00322 " will remove the 4th and 6th columns of file xyzzy.1D\n"
00323 " from the dataset (sub-vector indexes start at 0).\n"
00324 "\n"
00325 " -expr eee = Remove components proportional to the function\n"
00326 " specified in the expression string 'eee'.\n"
00327 " Any single letter from a-z may be used as the\n"
00328 " independent variable in 'eee'. For example:\n"
00329 " -expr 'cos(2*PI*t/40)' -expr 'sin(2*PI*t/40)'\n"
00330 " will remove sine and cosine waves of period 40\n"
00331 " from the dataset. Another example:\n"
00332 " -expr '1' -expr 't' -expr 't*t'\n"
00333 " will remove a quadratic trend from the data.\n"
00334 "\n"
00335 " -del ddd = Use the numerical value 'ddd' for the stepsize\n"
00336 " in subsequent -expr options. If no -del option\n"
00337 " is ever given, then the TR given in the dataset\n"
00338 " header is used for 'ddd'; if that isn't available,\n"
00339 " then 'ddd'=1.0 is assumed. The j-th time point\n"
00340 " will have independent variable = j * ddd, starting\n"
00341 " at j=0. For example:\n"
00342 " -expr 'sin(x)' -del 2.0 -expr 'z**3'\n"
00343 " means that the stepsize in 'sin(x)' is delta-x=TR,\n"
00344 " but the stepsize in 'z**3' is delta-z = 2.\n"
00345 #ifdef ALLOW_BYSLICE
00346 "\n"
00347 " N.B.: expressions are NOT calculated on a per-slice basis when the\n"
00348 " -byslice option is used. If you want to do this, you could\n"
00349 " compute vectors with the required time series using 1devel.\n"
00350 #endif
00351 ) ;
00352
00353 printf("\n" MASTER_SHORTHELP_STRING ) ;
00354
00355 exit(0) ;
00356 }
00357
00358
00359
00360 int main( int argc , char * argv[] )
00361 {
00362 int iv,nvals , nvec , ii,jj,kk , nvox ;
00363 THD_3dim_dataset * new_dset=NULL ;
00364 double * choleski ;
00365 float ** refvec , * fv , * fc , * fit ;
00366 MRI_IMAGE * flim ;
00367
00368
00369
00370 if( argc < 2 || strncmp(argv[1],"-help",4) == 0 ) DT_Syntax() ;
00371
00372
00373
00374 mainENTRY("3dDetrend main"); machdep() ; PRINT_VERSION("3dDetrend");
00375 { int new_argc ; char ** new_argv ;
00376 addto_args( argc , argv , &new_argc , &new_argv ) ;
00377 if( new_argv != NULL ){ argc = new_argc ; argv = new_argv ; }
00378 }
00379
00380 DT_read_opts( argc , argv ) ;
00381
00382
00383
00384 new_dset = EDIT_empty_copy( DT_dset ) ;
00385
00386
00387
00388 tross_Copy_History( DT_dset , new_dset ) ;
00389 tross_Make_History( "3dDetrend" , argc,argv , new_dset ) ;
00390
00391 EDIT_dset_items( new_dset ,
00392 ADN_prefix , DT_output_prefix ,
00393 ADN_directory_name, DT_session ,
00394 ADN_none ) ;
00395
00396
00397
00398 if( THD_is_file(DSET_HEADNAME(new_dset)) ){
00399 fprintf(stderr,"*** Fatal error: file %s already exists!\n",
00400 DSET_HEADNAME(new_dset) ) ;
00401 exit(1) ;
00402 }
00403
00404
00405
00406
00407 if( DT_verb ) fprintf(stderr,"+++ Loading input dataset .BRIK\n") ;
00408
00409 DSET_mallocize( new_dset ) ;
00410 DSET_mallocize( DT_dset ) ;
00411 DSET_load( DT_dset ) ;
00412 if( !DSET_LOADED(DT_dset) ){
00413 fprintf(stderr,"*** Can't read input dataset .BRIK!\n") ;
00414 exit(1) ;
00415 }
00416
00417 nvals = DSET_NVALS(new_dset) ;
00418 for( iv=0 ; iv < nvals ; iv++ )
00419 EDIT_substitute_brick( new_dset , iv ,
00420 DSET_BRICK_TYPE(DT_dset,iv) ,
00421 DSET_ARRAY(DT_dset,iv) ) ;
00422
00423 if( DT_norm && DSET_BRICK_TYPE(new_dset,0) != MRI_float ){
00424 fprintf(stderr,"+++ Warning: turning -normalize option off since\n"
00425 " input dataset is not in float format!\n");
00426 DT_norm = 0 ;
00427 }
00428
00429
00430
00431
00432 nvec = 0 ;
00433 for( ii=0 ; ii < IMARR_COUNT(DT_imar) ; ii++ )
00434 nvec += IMARR_SUBIMAGE(DT_imar,ii)->ny ;
00435
00436 refvec = (float **) malloc( sizeof(float *)*nvec ) ;
00437 for( kk=ii=0 ; ii < IMARR_COUNT(DT_imar) ; ii++ ){
00438 fv = MRI_FLOAT_PTR( IMARR_SUBIMAGE(DT_imar,ii) ) ;
00439 for( jj=0 ; jj < IMARR_SUBIMAGE(DT_imar,ii)->ny ; jj++ )
00440 refvec[kk++] = fv + ( jj * IMARR_SUBIMAGE(DT_imar,ii)->nx ) ;
00441 }
00442
00443 fit = (float *) malloc( sizeof(float) * nvals ) ;
00444
00445
00446
00447 if( !DT_byslice ){
00448 choleski = startup_lsqfit( nvals , NULL , nvec , refvec ) ;
00449 if( choleski == NULL ){
00450 fprintf(stderr,"*** Linearly dependent vectors can't be used!\n") ;
00451 exit(1) ;
00452 }
00453
00454
00455
00456 nvox = DSET_NVOX(new_dset) ;
00457
00458 if( DT_verb ) fprintf(stderr,"+++ Computing voxel fits\n") ;
00459
00460 for( kk=0 ; kk < nvox ; kk++ ){
00461
00462 flim = THD_extract_series( kk , new_dset , 0 ) ;
00463 fv = MRI_FLOAT_PTR(flim) ;
00464 fc = delayed_lsqfit( nvals, fv, nvec, refvec, choleski ) ;
00465
00466 for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = 0.0 ;
00467
00468 for( jj=0 ; jj < nvec ; jj++ )
00469 for( ii=0 ; ii < nvals ; ii++ )
00470 fit[ii] += fc[jj] * refvec[jj][ii] ;
00471
00472 if( !DT_replace )
00473 for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = fv[ii] - fit[ii] ;
00474
00475 if( DT_norm ) THD_normalize( nvals , fit ) ;
00476
00477 THD_insert_series( kk, new_dset, nvals, MRI_float, fit, 0 ) ;
00478
00479 free(fc) ; mri_free(flim) ;
00480 }
00481
00482 free(choleski) ;
00483
00484
00485
00486 }
00487 #ifdef ALLOW_BYSLICE
00488 else {
00489 int ksl , nslice , tt , nx,ny , nxy , kxy ;
00490 MRI_IMAGE * vim ;
00491
00492
00493
00494 for( kk=ii=0 ; ii < DT_nvector ; ii++ ){
00495 for( jj=0 ; jj < IMARR_SUBIMAGE(DT_imar,ii)->ny ; jj++ )
00496 refvec[kk++] = (float *) malloc( sizeof(float) * nvals ) ;
00497 }
00498
00499 nslice = DSET_NZ(new_dset) ;
00500 nxy = DSET_NX(new_dset) * DSET_NY(new_dset) ;
00501
00502
00503
00504 for( ksl=0 ; ksl < nslice ; ksl++ ){
00505
00506 if( DT_verb ) fprintf(stderr,"+++ Computing voxel fits for slice %d\n",ksl) ;
00507
00508
00509
00510 for( kk=ii=0 ; ii < DT_nvector ; ii++ ){
00511 vim = IMARR_SUBIMAGE(DT_imar,ii) ;
00512 nx = vim->nx ; ny = vim->ny ;
00513 for( jj=0 ; jj < ny ; jj++ ){
00514 fv = MRI_FLOAT_PTR(vim) + (jj*nx) ;
00515 for( tt=0 ; tt < nvals ; tt++ )
00516 refvec[kk][tt] = fv[ksl+tt*nslice] ;
00517 }
00518 }
00519
00520
00521
00522 choleski = startup_lsqfit( nvals , NULL , nvec , refvec ) ;
00523 if( choleski == NULL ){
00524 fprintf(stderr,"*** Linearly dependent vectors found at slice %d\n",ksl) ;
00525 exit(1) ;
00526 }
00527
00528
00529
00530 for( kxy=0 ; kxy < nxy ; kxy++ ){
00531
00532 kk = kxy + ksl*nxy ;
00533 flim = THD_extract_series( kk , new_dset , 0 ) ;
00534 fv = MRI_FLOAT_PTR(flim) ;
00535 fc = delayed_lsqfit( nvals, fv, nvec, refvec, choleski ) ;
00536
00537 for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = 0.0 ;
00538
00539 for( jj=0 ; jj < nvec ; jj++ )
00540 for( ii=0 ; ii < nvals ; ii++ )
00541 fit[ii] += fc[jj] * refvec[jj][ii] ;
00542
00543 if( !DT_replace )
00544 for( ii=0 ; ii < nvals ; ii++ ) fit[ii] = fv[ii] - fit[ii] ;
00545
00546 if( DT_norm ) THD_normalize( nvals , fit ) ;
00547
00548 THD_insert_series( kk, new_dset, nvals, MRI_float, fit, 0 ) ;
00549
00550 free(fc) ; mri_free(flim) ;
00551 }
00552
00553 free(choleski) ;
00554
00555 }
00556
00557 }
00558 #endif
00559
00560
00561
00562 DSET_write(new_dset) ;
00563 if( DT_verb ) fprintf(stderr,"+++ Wrote output dataset: %s\n",DSET_BRIKNAME(new_dset)) ;
00564 exit(0) ;
00565 }