1 #include "SUMA_suma.h"
2 
usage_3dBRAIN_VOYAGERtoAFNI(SUMA_GENERIC_ARGV_PARSE * ps)3 void usage_3dBRAIN_VOYAGERtoAFNI (SUMA_GENERIC_ARGV_PARSE *ps)
4 {
5       static char FuncName[]={"usage_3dBRAIN_VOYAGERtoAFNI"};
6       char * s = NULL, *sio=NULL, *st = NULL, *sts = NULL;
7       int i;
8       s = SUMA_help_basics();
9       sio  = SUMA_help_IO_Args(ps);
10       printf ( "\n"
11                "Usage: 3dBRAIN_VOYAGERtoAFNI <-input BV_VOLUME.vmr> \n"
12                "                             [-bs] [-qx] [-tlrc|-acpc|-orig] [<-prefix PREFIX>]\n"
13                " \n"
14                " Converts a BrainVoyager vmr dataset to AFNI's BRIK format\n"
15                " The conversion is based on information from BrainVoyager's\n"
16                " website: www.brainvoyager.com. \n"
17                " Sample data and information provided by \n"
18                "  Adam Greenberg and Nikolaus Kriegeskorte.\n"
19                "\n"
20                "  If you get error messages about the number of\n"
21                " voxels and file size, try the options below.\n"
22                " I hope to automate these options once I have\n"
23                " a better description of the BrainVoyager QX format.\n"
24                "\n"
25                "  Optional Parameters:\n"
26                "  -bs: Force byte swapping.\n"
27                "  -qx: .vmr file is from BrainVoyager QX\n"
28                "  -tlrc: dset in tlrc space\n"
29                "  -acpc: dset in acpc-aligned space\n"
30                "  -orig: dset in orig space\n"
31                "  If unspecified, the program attempts to guess the view from\n"
32                "  the name of the input.\n"
33                "%s"
34                "%s"
35                "\n", sio,  s);
36       SUMA_free(s); s = NULL; SUMA_free(st); st = NULL;
37       SUMA_free(sio); sio = NULL;
38       s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
39       printf("       Ziad S. Saad SSCC/NIMH/NIH saadz@mail.nih.gov     \n");
40       exit(0);
41 }
42 
43 SUMA_GENERIC_PROG_OPTIONS_STRUCT *
SUMA_3dBRAIN_VOYAGERtoAFNI_ParseInput(char * argv[],int argc,SUMA_GENERIC_ARGV_PARSE * ps)44    SUMA_3dBRAIN_VOYAGERtoAFNI_ParseInput(char *argv[], int argc,
45                                           SUMA_GENERIC_ARGV_PARSE *ps)
46 {
47    static char FuncName[]={"SUMA_3dBRAIN_VOYAGERtoAFNI_ParseInput"};
48    SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt=NULL;
49    int kar;
50    SUMA_Boolean brk;
51    SUMA_Boolean LocalHead = NOPE;
52 
53    SUMA_ENTRY;
54 
55    Opt = SUMA_Alloc_Generic_Prog_Options_Struct();
56    Opt->b1 = 0;
57    Opt->b2 = 0;
58    Opt->Icold = -1;
59    Opt->out_prefix = NULL;
60    kar = 1;
61    brk = NOPE;
62 	while (kar < argc) { /* loop accross command ine options */
63 		/*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
64 		if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
65 			 usage_3dBRAIN_VOYAGERtoAFNI(ps);
66           exit (0);
67 		}
68 
69 		SUMA_SKIP_COMMON_OPTIONS(brk, kar);
70 
71       if (!brk && (strcmp(argv[kar], "-input") == 0)) {
72          kar ++;
73 			if (kar >= argc)  {
74 		  		fprintf (SUMA_STDERR, "need argument after -input\n");
75 				exit (1);
76 			}
77          Opt->in_name = argv[kar];
78 			brk = YUP;
79 		}
80 
81       if (!brk && (strcmp(argv[kar], "-prefix") == 0)) {
82          kar ++;
83 			if (kar >= argc)  {
84 		  		fprintf (SUMA_STDERR, "need argument after -prefix\n");
85 				exit (1);
86 			}
87          Opt->out_prefix = SUMA_copy_string(argv[kar]);
88 			brk = YUP;
89 		}
90 
91       if (!brk && (strcmp(argv[kar], "-tlrc") == 0)) {
92 
93          Opt->Icold = VIEW_TALAIRACH_TYPE;
94 			brk = YUP;
95 		}
96       if (!brk && (strcmp(argv[kar], "-acpc") == 0)) {
97 
98          Opt->Icold = VIEW_ACPCALIGNED_TYPE;
99 			brk = YUP;
100 		}
101       if (!brk && (strcmp(argv[kar], "-orig") == 0)) {
102 
103          Opt->Icold = VIEW_ORIGINAL_TYPE;
104 			brk = YUP;
105 		}
106 
107       if (!brk && (strcmp(argv[kar], "-bs") == 0)) {
108 
109          Opt->b1 = 1;
110 			brk = YUP;
111 		}
112 
113       if (!brk && (strcmp(argv[kar], "-qx") == 0)) {
114 
115          Opt->b2 = 1;
116 			brk = YUP;
117 		}
118 
119       if (!brk && (strcmp(argv[kar], "-debug") == 0)) {
120          kar ++;
121 			if (kar >= argc)  {
122 		  		fprintf (SUMA_STDERR, "need integer argument after -debug\n");
123 				exit (1);
124 			}
125          Opt->debug = atoi(argv[kar]);
126 			brk = YUP;
127 		}
128 
129       if (!brk && !ps->arg_checked[kar]) {
130 			fprintf (SUMA_STDERR,"Error %s:\nOption %s not understood. Try -help for usage\n", FuncName, argv[kar]);
131 			exit (1);
132 		} else {
133 			brk = NOPE;
134 			kar ++;
135 		}
136    }
137 
138    SUMA_RETURN(Opt);
139 }
140 
141 
SUMA_BrainVoyager_Read_vmr(char * fnameorig,THD_3dim_dataset * dset,int LoadData,byte Qxforce,byte bsforce,int viewforce,char * outname)142 char * SUMA_BrainVoyager_Read_vmr(char *fnameorig, THD_3dim_dataset *dset, int LoadData,
143                                   byte Qxforce, byte bsforce, int viewforce, char *outname)
144 {
145    static char FuncName[]={"SUMA_BrainVoyager_Read_vmr"};
146    int  i = 0, nf, iop, dchunk, End, bs, doff, ex,
147          data_type=SUMA_notypeset, view, endian, dblock;
148    THD_ivec3 iv3;
149    unsigned long len;
150    short qxver;
151    short nvox[3]; /* values are unsigned, so check for sign for bs... */
152    THD_mat33 m33;
153    THD_ivec3 orixyz , nxyz ;
154    THD_fvec3 dxyz , orgxyz ;
155    float ep[3], sp[3];
156    char sview[10], *fname = NULL, *scom=NULL, form[10], swp[10], orstr[10], xfov[100], yfov[100], zfov[100], *prefix = NULL, *dsetheadname = NULL;
157    FILE *fid = NULL;
158    SUMA_Boolean LocalHead = NOPE;
159 
160    SUMA_ENTRY;
161 
162    if (!dset || !fnameorig) {
163       SUMA_SL_Err("NULL fname || NULL dset!");
164       SUMA_RETURN(NOPE);
165    }
166 
167    if (!SUMA_isExtension(fnameorig, ".vmr")) {
168       SUMA_SL_Err("vmr dset is expected to have .vmr for an extension");
169       SUMA_RETURN(NOPE);
170    }
171 
172    if (!SUMA_filexists(fnameorig)) {
173       SUMA_SL_Err("file does not exist");
174       SUMA_RETURN(NOPE);
175    }
176 
177    /* make fname be the new name without the extension*/
178    if (!outname) {
179       fname = SUMA_Extension(fnameorig,".vmr", YUP);
180    } else {
181       fname = SUMA_Extension(outname, ".vmr", YUP);
182    }
183    prefix = SUMA_AfniPrefix(fname, NULL, NULL, NULL);
184    if( !THD_filename_ok(prefix) ) {
185       SUMA_SL_Err("Bad prefix");
186       goto CLEAN_EXIT;
187    }
188 
189    /* someday, guess format on your own...*/
190    qxver = 0;
191    if (Qxforce) {
192       SUMA_LH("Forcing qxver");
193       qxver = 1;  /* set to 1 if qx format */
194    }
195 
196    /* view ? */
197    SUMA_LHv("Viewforce = %d; [%d %d]\n", viewforce, VIEW_ORIGINAL_TYPE, VIEW_TALAIRACH_TYPE);
198    if (viewforce >=  VIEW_ORIGINAL_TYPE && viewforce <= VIEW_TALAIRACH_TYPE) {
199       view = viewforce;
200    } else {
201       view = VIEW_ORIGINAL_TYPE;
202       if (SUMA_iswordin_ci(fnameorig, "_tal") == 1) { view = VIEW_TALAIRACH_TYPE; }
203       else if (SUMA_iswordin_ci(fnameorig, "_acpc") == 1) { view = VIEW_ACPCALIGNED_TYPE; }
204       else { view = VIEW_ORIGINAL_TYPE;  }
205    }
206    switch (view) {
207       case VIEW_ORIGINAL_TYPE:
208          sprintf(sview,"+orig"); break;
209       case VIEW_ACPCALIGNED_TYPE:
210          sprintf(sview,"+acpc"); break;
211       case VIEW_TALAIRACH_TYPE:
212          sprintf(sview,"+tlrc"); break;
213       default:
214          SUMA_SL_Err("Bad view");
215          goto CLEAN_EXIT;
216    }
217 
218    if (LocalHead) fprintf(SUMA_STDERR,"%s: View %s, %d\n", FuncName, sview, view);
219 
220    dsetheadname = SUMA_append_replace_string(prefix,".HEAD", sview, 0);
221    if (SUMA_filexists(dsetheadname)) {
222       SUMA_S_Errv("Bad prefix, output dset %s exists\n", dsetheadname);
223       goto CLEAN_EXIT;
224    }
225    SUMA_free(dsetheadname); dsetheadname = NULL;
226 
227    fid = fopen(fnameorig,"r");
228    if (!fid) {
229       SUMA_SL_Err("Could not open file for reading");
230       goto CLEAN_EXIT;
231    }
232 
233    if (qxver) {
234       SUMA_LH("Reading dimensions, 2+ 1st 6 bytes and deciding on swap");
235       doff = 4*sizeof(short);/* data offset 2 + 6 bytes */
236    } else {
237       SUMA_LH("Reading dimensions, 1st 6 bytes and deciding on swap");
238       doff = 3*sizeof(short);/* data offset */
239    }
240    SUMA_WHAT_ENDIAN(endian);
241    bs = 0;
242    swp[0] = '\0';
243    data_type = SUMA_byte; /* voxel data is bytes */
244    dchunk = sizeof(byte); /* voxel data is bytes */
245    sprintf(form,"3Db");
246    if (qxver) { SUMA_READ_NUM(&(qxver), fid, ex, sizeof(short)); if (LocalHead) fprintf(SUMA_STDERR,"%s: QXver = %d\n", FuncName, qxver);}/* is this a QX format?*/
247    SUMA_READ_NUM(&(nvox[2]), fid, ex, sizeof(short)); /* Z first */
248    SUMA_READ_NUM(&(nvox[1]), fid, ex, sizeof(short));
249    SUMA_READ_NUM(&(nvox[0]), fid, ex, sizeof(short));
250 
251    if ((nvox[0] < 0 || nvox[1] < 0 || nvox[2] < 0 )) {
252       SUMA_LH("Byte swapping needed");
253       bs = 1;
254    }
255    if (bsforce) {
256       SUMA_LH("Byte swapping forced");
257       bs = 1;
258    }
259 
260 
261    if (bs) {
262       if (qxver) SUMA_swap_2(&(qxver));
263       SUMA_swap_2(&(nvox[0]));
264       SUMA_swap_2(&(nvox[1]));
265       SUMA_swap_2(&(nvox[2]));
266       sprintf(swp,"-2swap");
267       SUMA_OTHER_ENDIAN(endian);
268    }
269 
270    /* 1 1 1???? */
271    if (nvox[0] == nvox[1]  && nvox[1] == nvox[2] && nvox[2] == 1) {
272       if (LocalHead) { fprintf(SUMA_STDERR,"Warning %s: Voxel nums all 1. Trying from file size\n", FuncName); }
273       len = THD_filesize( fnameorig ) ;
274       len -= doff;
275       len /= dchunk;
276       nvox[0] = (int)pow((double)len, 1.0/3.0);
277       if (nvox[0] * nvox[0] * nvox[0] != len) {
278          fprintf(SUMA_STDERR,"Error %s: Bad voxel numbers and could not infer number from filesize.\n"
279                              "Size of file: %lld, data offset: %d, datum size: %d, data number: %ld\n"
280                              "Inferred nvox:%d\n",
281                              FuncName,
282                              THD_filesize( fnameorig ), doff, dchunk, len,
283                              nvox[0]);
284          goto CLEAN_EXIT;
285       }
286       nvox[2] = nvox[1] = nvox[0];
287       if (LocalHead) { fprintf(SUMA_STDERR,"Warning %s: Using filesize inferred number of voxels: %d %d %d\n",
288                               FuncName, nvox[0], nvox[1], nvox[2]); }
289    }
290 
291    if (LocalHead) fprintf(SUMA_STDERR,"Number of voxels: %d %d %d. qxver %d\n", nvox[0], nvox[1], nvox[2], qxver);
292 
293 
294    /* check against filesize */
295 
296    len = THD_filesize( fnameorig ) ;
297    dblock = nvox[0]*nvox[1]*nvox[2]*dchunk;
298    if (len != (dblock + doff)) {
299       if (!qxver) {
300          fprintf(SUMA_STDERR, "Mismatch between file size    %ld\n"
301                               "and expected size             %d = (%d*%d*%d*%d+%d) \n",
302                               len, (dblock + doff), nvox[0], nvox[1], nvox[2], dchunk, doff);
303          goto CLEAN_EXIT;
304       }else if (len < dblock + doff) {
305          fprintf(SUMA_STDERR, "Mismatch between file size    %ld\n"
306                               "and minimum expected size     %d = (%d*%d*%d*%d+%d) \n",
307                               len, (dblock + doff), nvox[0], nvox[1], nvox[2], dchunk, doff);
308          goto CLEAN_EXIT;
309       }else {
310          SUMA_LH("Proceeding");
311       }
312    }
313    if (LocalHead) fprintf(SUMA_STDERR,"File size passes test\n");
314 
315    /* orientation */
316 
317    orixyz.ijk[0] = ORI_A2P_TYPE;
318    orixyz.ijk[1] = ORI_S2I_TYPE;
319    orixyz.ijk[2] = ORI_R2L_TYPE;
320 
321    /* load number of voxels */
322    LOAD_IVEC3( nxyz   , nvox[0]    , nvox[1]    , nvox[2] ) ;
323 
324    /* form the command */
325    SUMA_LH("Forming command");
326 
327    {
328       float delta[3]={1.0, 1.0, 1.0};
329       float origin[3]={0.0, 0.0, 0.0};
330       /* set origin of 0th voxel*/
331       origin[0] = (float)((nvox[0]*delta[0]))/2.0;    /* ZSS: Changed from 0 0 0 Nov 1 07 */
332       origin[1] = (float)((nvox[1]*delta[1]))/2.0;
333       origin[2] = (float)((nvox[2]*delta[2]))/2.0;
334 
335       /* dimensions, same for vmr*/
336       LOAD_FVEC3( dxyz , delta[0], delta[1], delta[2]   ) ;
337       SUMA_sizeto3d_2_deltaHEAD(orixyz, &dxyz);
338       /* origin */
339       LOAD_FVEC3( orgxyz , origin[0], origin[1], origin[2]   ) ;
340       SUMA_originto3d_2_originHEAD(orixyz, &orgxyz);
341 
342    }
343 
344    /* start point (edge of origin voxel) and end point (opposite to start ) */
345    sp[0] = orgxyz.xyz[0] + SUMA_ABS(dxyz.xyz[0]) / 2.0;
346    sp[1] = orgxyz.xyz[1] + SUMA_ABS(dxyz.xyz[1]) / 2.0;
347    sp[2] = orgxyz.xyz[2] + SUMA_ABS(dxyz.xyz[2]) / 2.0;
348    ep[0] = orgxyz.xyz[0] + (nxyz.ijk[0] - 0.5) * SUMA_ABS(dxyz.xyz[0]);
349    ep[1] = orgxyz.xyz[1] + (nxyz.ijk[1] - 0.5) * SUMA_ABS(dxyz.xyz[1]);
350    ep[2] = orgxyz.xyz[2] + (nxyz.ijk[2] - 0.5) * SUMA_ABS(dxyz.xyz[2]);
351    SUMA_orcode_to_orstring (orixyz.ijk[0], orixyz.ijk[1], orixyz.ijk[2], orstr);
352    sprintf(xfov," -xFOV %.2f%c-%.2f%c", sp[0], orstr[0], ep[0], orstr[3]);
353    sprintf(yfov," -yFOV %.2f%c-%.2f%c", sp[1], orstr[1], ep[1], orstr[4]);
354    sprintf(zfov," -zFOV %.2f%c-%.2f%c", sp[2], orstr[2], ep[2], orstr[5]);
355 
356    scom = (char *)SUMA_calloc((strlen(fnameorig)+500), sizeof(char));
357    sprintf(scom,"to3d %s %s %s %s -prefix %s %s:%d:0:%d:%d:%d:%s ",
358             swp, xfov, yfov, zfov, prefix, form, doff,
359             nvox[0], nvox[1], nvox[0], fnameorig);
360 
361    SUMA_LH("HERE");
362 
363    if (dset) { /* form the dset header */
364          int nvals_read = 0;
365          SUMA_LH("Filling header");
366          EDIT_dset_items( dset ,
367                             ADN_prefix      , prefix ,
368                             ADN_datum_all   , data_type ,
369                             ADN_nxyz        , nxyz ,
370                             ADN_xyzdel      , dxyz ,
371                             ADN_xyzorg      , orgxyz ,
372                             ADN_xyzorient   , orixyz ,
373                             ADN_malloc_type , DATABLOCK_MEM_MALLOC ,
374                             ADN_view_type   , view ,
375                             ADN_type        , HEAD_ANAT_TYPE ,
376                             ADN_func_type   , ANAT_BUCK_TYPE ,
377                           ADN_none ) ;
378 
379          if (LoadData) {
380             void *vec=NULL;
381             SUMA_LH("Loading data");
382             if (!(vec = SUMA_BinarySuck(fnameorig, data_type, endian, 3*sizeof(short), -1, &nvals_read))) {
383                SUMA_SL_Err("Failed to read data file"); goto CLEAN_EXIT;
384             }
385             if (qxver) {
386                if (nvals_read < nvox[0]*nvox[1]*nvox[2]) {
387                   SUMA_SL_Warn("Failed to read expected number of voxels\n proceeding...");
388                }
389             } else {
390                if (nvals_read != nvox[0]*nvox[1]*nvox[2]) {
391                   SUMA_SL_Warn("Failed to read the appropriate number of voxels\n proceeding...");
392                }
393             }
394             EDIT_substitute_brick( dset , 0 , data_type , vec) ;
395             if (LocalHead) fprintf(SUMA_STDERR,"%s: Read %d values from file.\n", FuncName, nvals_read);
396             /* DSET_write(dset) ; */
397          }
398    }
399 
400 
401 
402    CLEAN_EXIT:
403    if (prefix) SUMA_free(prefix); prefix = NULL;
404    if (fname) SUMA_free(fname); fname = NULL;
405    if (fid) fclose(fid); fid = NULL;
406    SUMA_RETURN(scom);
407 }
408 
main(int argc,char * argv[])409 int main (int argc,char *argv[])
410 {/* Main */
411    static char FuncName[]={"3dBRAIN_VOYAGERtoAFNI"};
412    SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt;
413    SUMA_GENERIC_ARGV_PARSE *ps=NULL;
414    SUMA_OPEN_DX_STRUCT **dx = NULL;
415    THD_3dim_dataset *dset=NULL;
416    char *sto3d = NULL;
417    SUMA_Boolean LocalHead = NOPE;
418 
419    SUMA_STANDALONE_INIT;
420 	SUMA_mainENTRY;
421 
422    /* Allocate space for DO structure */
423 	SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS);
424    ps = SUMA_Parse_IO_Args(argc, argv, "");
425 
426    if (argc < 2) {
427       usage_3dBRAIN_VOYAGERtoAFNI(ps);
428       exit (1);
429    }
430 
431    Opt = SUMA_3dBRAIN_VOYAGERtoAFNI_ParseInput (argv, argc, ps);
432 
433    if (Opt->debug > 2) LocalHead = YUP;
434 
435    dset = EDIT_empty_copy( NULL ) ;
436    tross_Make_History( "3dBRAIN_VOYAGERtoAFNI" , argc,argv , dset) ;
437    if (!(sto3d = SUMA_BrainVoyager_Read_vmr(Opt->in_name, dset, 1, Opt->b2, Opt->b1, Opt->Icold, Opt->out_prefix))) {
438       if (Opt->debug) SUMA_SL_Err("Failed in SUMA_BrainVoyager_Read_vmr");
439       exit(1);
440    }
441    SUMA_LHv("Old command would be %s\n", sto3d);
442 
443    if (dset) {
444       SUMA_LH("Writing Dset");
445       DSET_write(dset) ;
446       if (LocalHead) {
447          fprintf(SUMA_STDERR,"%s: Can use the following command to create dset with to3d:\n%s\n", FuncName,sto3d);
448       }
449    } else {
450       /* the olde way */
451       if (system(sto3d)) {
452          fprintf(SUMA_STDERR, "Error %s: Failed while executing shell command:\n%s\n"
453                               "Check to3d's error messages, and disk writing permissions.\n", FuncName, sto3d);
454       }
455    }
456 
457 
458 
459    if (sto3d) SUMA_free(sto3d); sto3d = NULL;
460    if (dset) { DSET_delete(dset); dset = NULL; }
461    if (Opt) Opt = SUMA_Free_Generic_Prog_Options_Struct(Opt);
462    if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
463    exit(0);
464 
465 }
466