1 /*
2 3dTsplit4D.c
3 This is a quick program to split a 3d+time dataset into multiple
4 single 3D files.  Mostly to facilitate transferring data into MATLAB toolboxes.
5 It can also be useful for deal with SPM and FSL programs.
6 
7 Author: Peter J. Molfese, Haskins Laboratories/UConn/Yale
8 Contact: Peter.Molfese@yale.edu
9 
10 January 5, 2016 - Initial Version
11 */
12 
13 
14 
15 #include "mrilib.h"
16 
help_3dTsplit4D()17 int help_3dTsplit4D( )
18 {
19    printf(
20       "USAGE: 3dTsplit4D [options] dataset\n\n"
21       "This program converts a 3D+time dataset into multiple 3D single-brick\n"
22       "files.  The main purpose of this is to accelerate the process of\n"
23       "export AFNI/NIFTI datasets if you have the unfortunate need to work\n"
24       "with Some other PrograM that doesn't like datasets in the pseudo-4D\n"
25       "nature that AFNI knows and loves.\n"
26       "\n"
27       "examples:\n"
28       "\n"
29       "   1. Write the 152 time point dataset, epi_r1+orig, to 152 single\n"
30       "      volume datasets, out/epi.000+orig ... epi.151+orig.\n"
31       "\n"
32       "         3dTsplit4D -prefix out/epi epi_r1+orig\n"
33       "\n"
34       "   2. Do the same thing, but write to 152 NIFTI volume datasets,\n"
35       "      out/epi.000.nii ... out/epi.151.nii.  Include .nii in -prefix.\n"
36       "\n"
37       "         3dTsplit4D -prefix out/epi.nii epi_r1+orig\n"
38       "\n"
39       " -prefix PREFIX : Prefix of the output datasets\n"
40       "                  Numbers will be added after the prefix to denote\n"
41       "                  prior sub-brick.\n"
42       " -keep_datum    : output uses original datum (no conversion to float)\n"
43       " -digits DIGITS : number of digits to use for output filenames\n"
44       "\n\n"
45       "Authored by: Peter Molfese, UConn"
46       );
47 
48    PRINT_COMPILE_DATE;
49    return(0);
50 }
51 
52 /* a few updates    8 Dec 2016 [rickr] */
53 
main(int argc,char * argv[])54 int main( int argc, char *argv[] )
55 {
56    THD_3dim_dataset *iset, *oset;
57    float ffac;
58    int   iarg=1, kk, nval;
59    int   datum=MRI_float, keep_datum=0, ndigits=0, prelen, smode;
60    char *prefix = "SPLIT";
61    char *sub_prefix, newlabel[32];
62    char *precopy=NULL, *exten=NULL;  /* copied prefix and any needed ext */
63    MRI_IMAGE *inImage=NULL;
64 
65    if( argc < 2 || strcmp(argv[1], "-help") == 0 )
66    {
67       help_3dTsplit4D( );
68       exit(0);
69    }
70 
71    mainENTRY("3dTsplit4D");
72    machdep();
73 
74    for( iarg=1; iarg < argc && argv[iarg][0] == '-'; iarg++ )
75    {
76       if( strcmp( argv[iarg], "-prefix") == 0 )
77       {
78          prefix = argv[++iarg];
79          if( !THD_filename_ok(prefix) )
80             ERROR_exit("bad -prefix value");
81       } else if( strcmp( argv[iarg], "-digits") == 0 )
82       {
83          ndigits = atoi(argv[++iarg]);
84          if( ndigits <= 0 )
85             ERROR_exit("bad -digits '%s'", argv[iarg-1]);
86       } else if( strcmp( argv[iarg], "-keep_datum") == 0 ) {
87          keep_datum = 1;
88       } else {
89          ERROR_exit("unknown option %s", argv[iarg]);
90       }
91    }
92 
93    INFO_message("Prefix set to: %s\n", prefix);
94 
95    /* Begin reading dataset, error checking like a good programmer */
96    iset = THD_open_dataset( argv[iarg] );
97    CHECK_OPEN_ERROR( iset, argv[iarg] );
98    THD_force_malloc_type( iset->dblk , DATABLOCK_MEM_MALLOC ) ;
99    DSET_load(iset);
100    CHECK_LOAD_ERROR(iset);
101 
102    //begin looping through!
103 
104    nval=DSET_NVALS(iset);
105    INFO_message("Dataset read...\n");
106    INFO_message("Number of Sub-bricks: %d\n", nval);
107 
108    if( nval == 0 ) ERROR_exit("no volumes to output?");
109 
110    /* how many digits do we need for the prefix trailer?   8 Dec 2016 */
111    if( ndigits == 0 )
112       ndigits = (int)(log(nval)/log(10)+1);
113 
114    /* allocate sub_prefix */
115    kk = strlen(prefix) + ndigits + 4; /* full length of prefix, plus 2 extra */
116    sub_prefix = (char *)malloc(kk*sizeof(char));
117    if( ! sub_prefix ) ERROR_exit("failed to alloc %d bytes for prefix", kk);
118 
119    /* make new prefix in case of non-AFNI writing, so it can be altered */
120    /* (precopy and exten will be used for actual output prefix) */
121    precopy = nifti_strdup(prefix);
122    exten = NULL;
123    smode = storage_mode_from_filename(prefix);
124    if( has_known_non_afni_extension(precopy)
125         && is_writable_storage_mode(smode) ) {
126       exten = find_filename_extension(precopy);
127       /* if found, terminate actual prefix, and point exten past '.' */
128       if( exten && exten > precopy )
129          *exten++ = '\0';
130       INFO_message("Using new prefix for non-AFNI write: %s\n", precopy);
131    }
132 
133    oset = EDIT_empty_copy( iset ); //Easy to just copy!
134    THD_force_malloc_type( oset->dblk , DATABLOCK_MEM_MALLOC ) ;
135 
136    printf("++ writing:");
137 
138    for( kk=0 ; kk < nval ; kk++ )
139    {
140       /* MODIFY to make single brik output */
141       /* ALSO NEED TO CHANGE PREFIX EACH TIME! */
142 
143       /* if there is a non-AFNI extension, use it       9 Dec 2016 [rickr] */
144       if(exten) sprintf(sub_prefix, "%s.%0*d.%s", precopy, ndigits, kk, exten);
145       else      sprintf(sub_prefix, "%s.%0*d", precopy, ndigits, kk);
146 
147       //sub_prefix = strncat( prefix, itoa(kk), 10 );
148 
149       // INFO_message("File Saved: %s", sub_prefix);
150       if( kk == 0 || kk == (nval-1) )
151          printf(" %s ", sub_prefix);
152       else
153          putchar('.');
154 
155       if( keep_datum ) datum = DSET_BRICK_TYPE(iset, kk);
156       else             datum = MRI_float;
157 
158       EDIT_dset_items( oset,
159          ADN_datum_all , datum ,
160          ADN_prefix , sub_prefix ,
161          ADN_ntt, 1 ,
162          ADN_nvals, 1, ADN_none);
163 
164       if( DSET_HAS_LABEL(iset, kk) ) {
165          EDIT_dset_items( oset,
166              ADN_brick_label_one, DSET_BRICK_LABEL(iset, kk),
167              ADN_none );
168       } else {
169          sprintf(newlabel, "%.16s[%d]", DSET_PREFIX(iset), kk);
170          EDIT_dset_items( oset,
171              ADN_brick_label_one, newlabel,
172              ADN_none );
173       }
174 
175       /* either pass the data along or make a float version */
176       if( keep_datum ) {
177          EDIT_substitute_brick( oset, 0, datum, DSET_ARRAY(iset, kk));
178          DSET_BRICK_FACTOR(oset,0) = DSET_BRICK_FACTOR(iset, kk);
179       } else {
180          inImage = THD_extract_float_brick(kk, iset);
181          if( inImage == NULL)
182             ERROR_exit("Failed to convert sub-brick %d of input dataset...",kk);
183 
184          EDIT_substitute_brick( oset, 0, MRI_float, MRI_FLOAT_PTR(inImage) );
185       }
186 
187       DSET_write( oset );
188       if( ! THD_is_file(DSET_BRIKNAME(oset)) )
189          ERROR_exit("failed to write dataset %s", sub_prefix);
190       //WROTE_DSET( oset );
191 
192       DSET_unload_one(iset, kk);
193 
194       /* for output, just clear borrowed pointer (being naughty?) */
195       DSET_BRICK(oset, 0) = NULL;
196 
197       if( inImage) mri_clear_and_free( inImage );
198    }  /* for each volume */
199 
200    printf("\n...Done\n");
201 
202    exit(0);
203 }
204