#include "mrilib.h" /*--------------------------------------------------------------------------*/ typedef struct { int npts ; int * nstart ; int * nwt ; float ** wt ; } intermap ; /*--------------------------------------------------------------------------- Setup for linear interpolation from grid xin[0..nin-1] to xout[0..nout-1]. Both grids are assumed to be in increasing order. -----------------------------------------------------------------------------*/ intermap * INTERP_setup_linear( int nin, float * xin, int nout, float * xout ) { intermap * imap ; int ii,ib ; float xx ; if( nin < 2 || nout < 2 || xin == NULL || xout == NULL ) return NULL ; imap = (intermap *) malloc(sizeof(intermap)) ; imap->npts = nout ; imap->nstart = (int *) calloc(sizeof(int) ,nout) ; imap->nwt = (int *) calloc(sizeof(int) ,nout) ; imap->wt = (float **) calloc(sizeof(float *),nout) ; for( ii=0 ; ii < nout ; ii++ ){ xx = xout[ii] ; /* output point */ if( xx < xin[0] ){ /* before 1st point */ if( xin[0]-xx <= 0.5*(xin[1]-xin[0]) ){ /* but not too much */ imap->nstart[ii] = 0 ; imap->nwt[ii] = 1 ; imap->wt[ii] = (float *) malloc(sizeof(float)) ; imap->wt[ii][0] = 1.0 ; } continue ; } else if ( xx > xin[nin-1] ){ /* after last point */ if( xx-xin[nin-1] <= 0.5*(xin[nin-1]-xin[nin-2]) ){ /* but not too much */ imap->nstart[ii] = nin-1 ; imap->nwt[ii] = 1 ; imap->wt[ii] = (float *) malloc(sizeof(float)) ; imap->wt[ii][0] = 1.0 ; } continue ; } /* OK, somewhere in the middle; search for the input interval that brackets this output point */ for( ib=0 ; ib < nin-1 ; ib++ ) if( xx >= xin[ib] && xx <= xin[ib+1] ) break ; if( ib == nin ) continue ; /* outside!? */ /* make linear interpolation coefficients */ imap->nstart[ii] = ib ; imap->nwt[ii] = 2 ; imap->wt[ii] = (float *) malloc(sizeof(float)*2) ; imap->wt[ii][1] = (xx-xin[ib]) / (xin[ib+1]-xin[ib]) ; imap->wt[ii][0] = 1.0 - imap->wt[ii][1] ; } return imap ; } /*--------------------------------------------------------------------------*/ void INTERP_destroy( intermap * imap ) { int ii ; if( imap == NULL ) return ; for( ii=0 ; ii < imap->npts ; ii++ ) if( imap->wt[ii] != NULL ) free(imap->wt[ii]) ; free(imap->wt) ; free(imap->nwt) ; free(imap->nstart) ; free(imap) ; return ; } /*-------------------------------------------------------------------------- Evaluate interpolation given by imap, from input data vin[] to output vout[] ----------------------------------------------------------------------------*/ void INTERP_evaluate( intermap * imap , float * vin , float * vout ) { int ii , jj,ib,nj , nout ; if( imap == NULL || vin == NULL || vout == NULL ) return ; nout = imap->npts ; for( ii=0 ; ii < nout ; ii++ ){ vout[ii] = 0.0 ; ib = imap->nstart[ii] ; nj = imap->nwt[ii] ; for( jj=0 ; jj < nj ; jj++ ) vout[ii] += imap->wt[ii][jj] * vin[ib+jj] ; } return ; } /*--------------------------------------------------------------------------*/ int main( int argc , char * argv[] ) { THD_3dim_dataset * dset , * nset ; int iarg=1 ; float new_dz=0.0 , old_dz ; int new_nz=0 , old_nz ; float new_zsize=0.0 , old_zsize ; char * prefix = "regrid" ; float old_zcen , new_zcen , zshift ; int bkind , nx,ny,nxy , iv,ii,kk , verb=0 ; byte *bar=NULL , *nbar=NULL ; short *sar=NULL , *nsar=NULL ; float *far=NULL , *nfar=NULL , *ofz , *nfz ; complex *car=NULL , *ncar=NULL ; void * nvar ; float * zin , * zout ; intermap * imap ; if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf("Usage: 3dZregrid [option] dataset\n" "Alters the input dataset's slice thickness and/or number.\n" "\n" "*** For most purposes, this program has been superseded ***\n" "*** by program 3dresample, which can change the grid of ***\n" "*** a dataset in all 3 directions at once. ***\n" "\n" "OPTIONS:\n" " -dz D = sets slice thickness to D mm\n" " -nz N = sets slice count to N\n" " -zsize Z = sets thickness of dataset (center-to-center of\n" " first and last slices) to Z mm\n" " -prefix P = write result in dataset with prefix P\n" " -verb = write progress reports to stderr\n" "\n" "At least one of '-dz', '-nz', or '-zsize' must be given.\n" "On the other hand, using all 3 is over-specification.\n" "The following combinations make sense:\n" " -dz only ==> N stays fixed from input dataset\n" " and then is like setting Z = N*D\n" " -dz and -nz together ==> like setting Z = N*D\n" " -dz and -zsize together ==> like setting N = Z/D\n" " -nz only ==> D stays fixed from input dataset\n" " and then is like setting Z = N*D\n" " -zsize only ==> D stays fixed from input dataset\n" " and then is like setting N = Z/D\n" " -nsize and -zsize together ==> like setting D = Z/N\n" "\n" "NOTES:\n" " * If the input is a 3D+time dataset with slice-dependent time\n" " offsets, the output will have its time offsets cleared.\n" " It probably makes sense to do 3dTshift BEFORE using this\n" " program in such a case.\n" " * The output of this program is centered around the same\n" " location as the input dataset. Slices outside the\n" " original volume (e.g., when Z is increased) will be\n" " zero. This is NOT the same as using 3dZeropad, which\n" " only adds zeros, and does not interpolate to a new grid.\n" " * Linear interpolation is used between slices. However,\n" " new slice positions outside the old volume but within\n" " 0.5 old slice thicknesses will get a copy of the last slice.\n" " New slices outside this buffer zone will be all zeros.\n" "\n" "EXAMPLE:\n" " You have two 3D anatomical datasets from the same subject that\n" " need to be registered. Unfortunately, the first one has slice\n" " thickness 1.2 mm and the second 1.3 mm. Assuming they have\n" " the same number of slices, then do something like\n" " 3dZregrid -dz 1.2 -prefix ElvisZZ Elvis2+orig\n" " 3dvolreg -base Elvis1+orig -prefix Elvis2reg ElvisZZ+orig\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3dZregrid main"); machdep(); PRINT_VERSION("3dZregrid") ; AFNI_logger("3dZregrid",argc,argv) ; /*-- scan options --*/ while( iarg < argc && argv[iarg][0] == '-' ){ if( strncmp(argv[iarg],"-verb",5) == 0 ){ verb++ ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-dz") == 0 ){ new_dz = strtod( argv[++iarg] , NULL ) ; if( new_dz <= 0.0 ){ fprintf(stderr,"** ILLEGAL -dz value!\n"); exit(1); } iarg++ ; continue ; } if( strcmp(argv[iarg],"-nz") == 0 ){ new_nz = strtod( argv[++iarg] , NULL ) ; if( new_nz <= 2 ){ fprintf(stderr,"** ILLEGAL -nz value!\n"); exit(1); } iarg++ ; continue ; } if( strcmp(argv[iarg],"-zsize") == 0 ){ new_zsize = strtod( argv[++iarg] , NULL ) ; if( new_zsize <= 0.0 ){ fprintf(stderr,"** ILLEGAL -zsize value!\n"); exit(1); } iarg++ ; continue ; } if( strcmp(argv[iarg],"-prefix") == 0 ){ prefix = argv[++iarg] ; if( !THD_filename_ok(prefix) ){ fprintf(stderr,"** ILLEGAL -prefix value!\n"); exit(1); } iarg++ ; continue ; } fprintf(stderr,"** ILLEGAL option: %s\n",argv[iarg]) ; exit(1) ; } /*-- read input dataset --*/ if( verb ) fprintf(stderr,"++ Reading input dataset %s\n",argv[iarg]) ; dset = THD_open_dataset( argv[iarg] ) ; if( dset == NULL ){ fprintf(stderr,"** CANNOT open dataset %s\n",argv[iarg]) ; exit(1) ; } DSET_load(dset) ; CHECK_LOAD_ERROR(dset) ; /*-- check for consistency --*/ if( new_dz == 0.0 && new_nz == 0 && new_zsize == 0.0 ){ fprintf(stderr,"** AT LEAST one of -dz, -nz, -zsize must be given!\n"); exit(1); } /*-- consider all the combinations of inputs we like --*/ if( new_dz > 0.0 ){ if( new_nz > 0 ){ /* -dz and -nz */ new_zsize = new_dz * new_nz ; } else if( new_zsize > 0.0 ){ /* -dz and -zsize */ new_nz = rint( new_zsize / new_dz ) ; } else { /* -dz only */ new_nz = DSET_NZ(dset) ; new_zsize = new_dz * new_nz ; } } else if( new_nz > 0 ){ if( new_zsize > 0.0 ){ /* -nz and -zsize */ new_dz = new_zsize / new_nz ; } else { /* -nz only */ new_dz = fabs(DSET_DZ(dset)) ; new_zsize = new_nz * new_dz ; } } else { /* -zsize only */ new_dz = fabs(DSET_DZ(dset)) ; new_nz = rint( new_zsize / new_dz ) ; } /*-- make sure we aren't trimming TOO much fat off --*/ if( new_nz < 2 ){ fprintf(stderr,"** ILLEGAL number of new slices computed = %d\n",new_nz) ; exit(1) ; } /*-- make empty shell of output dataset --*/ old_nz = DSET_NZ(dset) ; old_dz = fabs(DSET_DZ(dset)) ; old_zsize = old_nz * old_dz ; nset = EDIT_empty_copy( dset ) ; EDIT_dset_items( nset , ADN_prefix , prefix , ADN_none ) ; if( THD_deathcon() && THD_is_file( DSET_HEADNAME(nset) ) ){ fprintf(stderr,"** Output file %s exists -- cannot overwrite!\n", DSET_HEADNAME(nset) ) ; exit(1) ; } tross_Copy_History( dset , nset ) ; tross_Make_History( "3dZregrid" , argc,argv , nset ) ; /* lose obliquity */ /* recompute Tc (Cardinal transformation matrix for new grid output */ THD_make_cardinal(nset); /*-- adjust z-axis stuff --*/ if( new_nz != old_nz ){ THD_ivec3 iv_nxyz ; LOAD_IVEC3( iv_nxyz , DSET_NX(dset) , DSET_NY(dset) , new_nz ) ; EDIT_dset_items( nset , ADN_nxyz , iv_nxyz , ADN_none ) ; if( verb ) fprintf(stderr,"++ Adjusting slice count from %d to %d\n",old_nz,new_nz) ; } if( new_dz != old_dz ){ THD_fvec3 fv_dxyz ; float dz=new_dz ; if( DSET_DZ(dset) < 0.0 ) dz = -dz ; LOAD_FVEC3( fv_dxyz , DSET_DX(dset) , DSET_DY(dset) , dz ) ; EDIT_dset_items( nset , ADN_xyzdel , fv_dxyz , ADN_none ) ; if( verb ) fprintf(stderr,"++ Adjusting slice thickness from %6.3f to %6.3f\n",old_dz,new_dz) ; } old_zcen = dset->daxes->zzorg + 0.5*(dset->daxes->nzz-1)*dset->daxes->zzdel ; new_zcen = nset->daxes->zzorg + 0.5*(nset->daxes->nzz-1)*nset->daxes->zzdel ; zshift = new_zcen - old_zcen ; if( fabs(zshift) > 0.01*new_dz ){ THD_fvec3 fv_xyzorg ; float zz ; zz = nset->daxes->zzorg - zshift ; LOAD_FVEC3( fv_xyzorg , nset->daxes->xxorg , nset->daxes->yyorg , zz ) ; EDIT_dset_items( nset , ADN_xyzorg , fv_xyzorg , ADN_none ) ; } if( nset->taxis != NULL && nset->taxis->nsl > 0 ){ EDIT_dset_items( nset , ADN_nsl , 0 , ADN_none ) ; fprintf(stderr, "++ WARNING - slice-dependent time shifts have been removed!\n") ; } /*-- setup to interpolate --*/ zin = (float *) malloc(sizeof(float)*old_nz) ; zout = (float *) malloc(sizeof(float)*new_nz) ; for( kk=0 ; kk < old_nz ; kk++ ) zin[kk] = (kk-0.5*old_nz) * old_dz ; for( kk=0 ; kk < new_nz ; kk++ ) zout[kk] = (kk-0.5*new_nz) * new_dz ; imap =INTERP_setup_linear( old_nz,zin , new_nz,zout ) ; free(zin) ; free(zout) ; /*-- loop over sub-bricks --*/ nx = DSET_NX(nset) ; ny = DSET_NY(nset) ; nxy = nx*ny ; ofz = (float *) malloc(sizeof(float)*old_nz*2) ; /* old data */ nfz = (float *) malloc(sizeof(float)*new_nz*2) ; /* new data */ if( verb ) fprintf(stderr,"++ Sub-bricks:") ; for( iv=0 ; iv < DSET_NVALS(nset) ; iv++ ){ if( verb ) fprintf(stderr,"%d",iv) ; bkind = DSET_BRICK_TYPE(dset,iv) ; switch( bkind ){ default: fprintf(stderr,"** ILLEGAL brick type %s at sub-brick %d\n", MRI_type_name[bkind] , iv ) ; exit(1) ; case MRI_byte: bar = DSET_ARRAY(dset,iv) ; nbar = (byte *)malloc(sizeof(byte)*nxy*new_nz) ; nvar = (void *) nbar ; break ; case MRI_short: sar = DSET_ARRAY(dset,iv) ; nsar = (short *)malloc(sizeof(short)*nxy*new_nz) ; nvar = (void *) nsar ; break ; case MRI_float: far = DSET_ARRAY(dset,iv) ; nfar = (float *)malloc(sizeof(float)*nxy*new_nz) ; nvar = (void *) nfar ; break ; case MRI_complex: car = DSET_ARRAY(dset,iv) ; ncar = (complex *)malloc(sizeof(complex)*nxy*new_nz) ; nvar = (void *) ncar ; break ; } /*-- loop over rows --*/ for( ii=0 ; ii < nxy ; ii++ ){ /*-- extract old data into ofz array --*/ switch( bkind ){ case MRI_byte: for( kk=0 ; kk < old_nz ; kk++ ) ofz[kk] = bar[ii+kk*nxy] ; break ; case MRI_short: for( kk=0 ; kk < old_nz ; kk++ ) ofz[kk] = sar[ii+kk*nxy] ; break ; case MRI_float: for( kk=0 ; kk < old_nz ; kk++ ) ofz[kk] = far[ii+kk*nxy] ; break ; case MRI_complex: for( kk=0 ; kk < old_nz ; kk++ ){ ofz[kk] = car[ii+kk*nxy].r ; ofz[kk+old_nz] = car[ii+kk*nxy].i ; } break ; } /*-- interpolate into nfz array --*/ INTERP_evaluate( imap , ofz , nfz ) ; if( bkind == MRI_complex ) INTERP_evaluate( imap , ofz+old_nz , nfz+new_nz ) ; /*-- put into output array --*/ switch( bkind ){ case MRI_byte: for( kk=0 ; kk < new_nz ; kk++ ) nbar[ii+kk*nxy] = BYTEIZE(nfz[kk]) ; break ; case MRI_short: for( kk=0 ; kk < new_nz ; kk++ ) nsar[ii+kk*nxy] = SHORTIZE(nfz[kk]) ; break ; case MRI_float: for( kk=0 ; kk < new_nz ; kk++ ) nfar[ii+kk*nxy] = nfz[kk] ; break ; case MRI_complex: for( kk=0 ; kk < new_nz ; kk++ ){ ncar[ii+kk*nxy].r = nfz[kk] ; ncar[ii+kk*nxy].i = nfz[kk+new_nz] ; } break ; } } /* end of loop over rows */ if( verb ) fprintf(stderr,".") ; EDIT_substitute_brick( nset , iv , bkind , nvar ) ; DSET_unload_one( dset , iv ) ; } /* end of loop over sub-bricks */ DSET_delete(dset) ; INTERP_destroy(imap) ; free(nfz) ; free(ofz) ; DSET_write(nset) ; if( verb ) fprintf(stderr,"\n++ Output dataset = %s\n",DSET_BRIKNAME(nset)) ; exit(0) ; }