1 #include "SUMA_suma.h"
2 
usage_ROI2dataset_Main(int detail)3 void usage_ROI2dataset_Main (int detail)
4 
5   {/*Usage*/
6       static char FuncName[]={"usage_ROI2dataset_Main"};
7       char * s = NULL;
8       fprintf(SUMA_STDOUT,
9 "\n"
10 "Usage: \n"
11 "   ROI2dataset <-prefix dsetname> [...] <-input ROI1 ROI2 ...>\n"
12 "               [<-of ni_bi|ni_as|1D>] \n"
13 "               [<-dom_par_id idcode>] \n"
14 "    This program transforms a series of ROI files\n"
15 "    to a node dataset. This data set will contain\n"
16 "    the node indices in the first column and their\n"
17 "    ROI values in the second column.\n"
18 "    Duplicate node entries (nodes that are part of\n"
19 "    multiple ROIs) will get ignored. You will be\n"
20 "    notified when this occurs. \n"
21 "\n"
22 "Mandatory parameters:\n"
23 "    -prefix     dsetname: Prefix of output dataset.\n"
24 "                          Program will not overwrite existing\n"
25 "                          datasets.\n"
26 "                          See also -label_dset alternate below.\n"
27 "    -keep_separate: Output one column (sub-brick) for each ROI value\n"
28 "\n"
29 " and/or\n"
30 "    -nodelist        NL: Prefix for a set of .1D files\n"
31 "    -nodelist.nodups NL: that contain a list of node indices\n"
32 "                         in the order in which they appear in\n"
33 "                         an ROI. This way you can make use of the\n"
34 "                         directionality of an ROI line instead of just \n"
35 "                         treating it as a set of nodes. \n"
36 "                         For each integer label 'i' in the ROI files provided\n"
37 "                         with the -input option, you will get a file called\n"
38 "                         NL.i.1D listing the nodes in the order they were \n"
39 "                         encountered in an ROI file and across ROI files.\n"
40 "                         If you want duplicate node entries removed, then\n"
41 "                         use -nodelist.nodups instead.\n"
42 "                   For example, say you traced an ROI that consisted of some \n"
43 "                   arbitrary curved path and you want to get the nodes \n"
44 "                   forming the path in the order traversed while drawing.\n"
45 "                   First save the path drawn, say to trace.niml.roi, \n"
46 "                   then use the following command:\n"
47 "                         ROI2dataset -nodelist.nodups TRACE \\\n"
48 "                                     -input trace.niml.roi\n"
49 "                   Note: You can use the output of -nodelist as input to \n"
50 "                         ConvertDset's -node_select_1D option. \n"
51 "                         This is not the case for -nodelist because\n"
52 "                         ConvertDset's -node_select_1D does not allow for \n"
53 "                         duplicate node entries. \n"
54 "    -nodelist_with_ROIval: Also add the ROIval as a second column in .1D\n"
55 "                           files output by -nodelist.\n"
56 "    -input ROI1 ROI2....: ROI files to turn into a \n"
57 "                          data set. This parameter MUST\n"
58 "                          be the last one on command line.\n"
59 "\n"
60 "Optional parameters:\n"
61 "    All optional parameters must be specified before the -input parameters.\n"
62 "\n"
63 "    -label_dset dsetname: Write a label dataset, instead of a simple dataset.\n"
64 "                          Labeled datasets are treated differently in SUMA.\n"   "                          This option also sets the output format to NIML.\n"
65 "                    Note: Using -keep_separate with this option is legal, but\n"
66 "                          makes little sense. You can't view more than one \n"
67 "                          sub-brick in SUMA for Labeled datasets.\n"
68 "    -h | -help: This help message\n"
69 "    -of FORMAT: Output format of dataset. FORMAT is one of:\n"
70 "                ni_bi: NIML binary\n"
71 "                ni_as: NIML ascii (default)\n"
72 "                1D   : 1D AFNI format.\n"
73 "    -dom_par_id id: Idcode of domain parent.\n"
74 "                    When specified, only ROIs have the same\n"
75 "                    domain parent are included in the output.\n"
76 "                    If id is not specified then the first\n"
77 "                    domain parent encountered in the ROI list\n"
78 "                    is adopted as dom_par_id.\n"
79 "                    1D roi files do not have domain parent \n"
80 "                    information. They will be added to the \n"
81 "                    output data under the chosen dom_par_id.\n"
82 "    -pad_to_node max_index: Output a full dset from node 0 \n"
83 "                            to node max_index (a total of \n"
84 "                            max_index + 1 nodes). Nodes that\n"
85 "                            are not part of any ROI will get\n"
86 "                            a default label of 0 unless you\n"
87 "                            specify your own padding label.\n"
88 "    -pad_label padding_label: Use padding_label (an integer) to\n"
89 "                            label nodes that do not belong\n"
90 "                            to any ROI. Default is 0.\n"
91 "                         This padding value is also used in the multi-column\n"
92 "                            format of option -keep_separate.\n"
93 "\n");
94          s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
95          fprintf(SUMA_STDOUT,
96             "       Ziad S. Saad SSCC/NIMH/NIH saadz@mail.nih.gov \n");
97      exit (0);
98   }/*Usage*/
99 
main(int argc,char * argv[])100 int main (int argc,char *argv[])
101 {/* Main */
102    static char FuncName[]={"ROI2dataset"};
103    char  *prefix_name, **input_name_v=NULL, *out_name=NULL,
104          *Parent_idcode_str = NULL, *dummy_idcode_str = NULL,
105          *stmp=NULL, *sss=NULL, *nodelist=NULL, *outlist_name=NULL,
106          cbuf[50];
107    int   kar, brk, N_input_name, cnt = 0, N_ROIv,
108          N_tROI, ii, i, nn, pad_to, pad_val;
109    SUMA_DSET *dset=NULL;
110    NI_stream ns;
111    SUMA_DSET_FORMAT Out_Format = SUMA_ASCII_NIML;
112    SUMA_DRAWN_ROI ** ROIv = NULL, **tROIv = NULL;
113    SUMA_Boolean AddThis = NOPE;
114    SUMA_ROI_EXTRACT *dd=NULL;
115    DList *ddl=NULL;
116    DListElmt *el=NULL;
117    int nodups=0, olabel = 0, withflag = 0, keepsep=0;
118    SUMA_COLOR_MAP *cmap=NULL;
119    SUMA_Boolean LocalHead = NOPE;
120 
121    SUMA_STANDALONE_INIT;
122    SUMA_mainENTRY;
123 
124    /* parse the command line */
125    kar = 1;
126    brk = NOPE;
127    prefix_name = NULL;
128    input_name_v = NULL;
129    N_input_name = 0;
130    Out_Format = SUMA_NO_DSET_FORMAT;
131    Parent_idcode_str = NULL;
132    pad_to = -1;
133    pad_val = 0;
134    nodelist=NULL;
135    withflag = 0;
136    olabel = 0;
137    keepsep = 0;
138    nodups = 0;
139    while (kar < argc) { /* loop accross command ine options */
140       /* SUMA_LH("Parsing command line..."); */
141 
142       if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
143           usage_ROI2dataset_Main(strlen(argv[kar]) > 3 ? 2:1);
144           exit (1);
145       }
146 
147       SUMA_SKIP_COMMON_OPTIONS(brk, kar);
148 
149       if (!brk && (strcmp(argv[kar], "-prefix") == 0)) {
150          kar ++;
151          if (kar >= argc)  {
152             fprintf (SUMA_STDERR, "need argument after -prefix ");
153             exit (1);
154          }
155          prefix_name = argv[kar];
156          brk = YUP;
157       }
158 
159       if (!brk && (strcmp(argv[kar], "-label_dset") == 0)) {
160          kar ++;
161          if (kar >= argc)  {
162             fprintf (SUMA_STDERR, "need argument after -label_dset ");
163             exit (1);
164          }
165          prefix_name = argv[kar];
166          if (Out_Format != SUMA_NO_DSET_FORMAT &&
167              Out_Format != SUMA_ASCII_NIML &&
168              Out_Format != SUMA_BINARY_NIML) {
169             SUMA_S_Warn("Overriding output format to accommodate -label_dset.\n"
170                      "Format will be ni_as or ni_bi, depending on environment\n"
171                         "variable AFNI_NIML_TEXT_DATA");
172          }
173          if (AFNI_yesenv("AFNI_NIML_TEXT_DATA")) Out_Format = SUMA_ASCII_NIML;
174          else Out_Format = SUMA_BINARY_NIML;
175          olabel = 1;
176          brk = YUP;
177       }
178 
179       if (  !brk &&
180             (strcmp(argv[kar], "-keep_separate") == 0) ) {
181          keepsep = 1;
182          brk = YUP;
183       }
184 
185 
186       if (  !brk &&
187             (strcmp(argv[kar], "-nodelist") == 0 ||
188              strcmp(argv[kar], "-nodelist.nodups") == 0) ) {
189          if (strlen(argv[kar])> 10) nodups = 1;
190          else nodups = 0;
191          kar ++;
192          if (kar >= argc)  {
193             fprintf (SUMA_STDERR, "need argument after -nodelist* options ");
194             exit (1);
195          }
196          nodelist = argv[kar];
197 
198          brk = YUP;
199       }
200 
201       if (  !brk &&
202             (strcmp(argv[kar], "-nodelist_with_ROIval") == 0) ) {
203          withflag = 1;
204          brk = YUP;
205       }
206 
207       if (!brk && (strcmp(argv[kar], "-of") == 0)) {
208          kar ++;
209          if (kar >= argc)  {
210             fprintf (SUMA_STDERR, "need argument after -of ");
211             exit (1);
212          }
213 
214          Out_Format = SUMA_NO_DSET_FORMAT;
215                      /* Can't use isOutputFormatFromArg because -of is not part
216                      of the passed argument */
217          if (!SUMA_isFormatFromArg(argv[kar], &Out_Format)) {
218             fprintf (SUMA_STDERR,
219                      "%s not a valid option with -of.\n", argv[kar]);
220             exit (1);
221          }
222          if (olabel &&
223              Out_Format != SUMA_ASCII_NIML &&
224              Out_Format != SUMA_BINARY_NIML) {
225             SUMA_S_Err("Cannot specify non-niml format with -label_dset");
226             exit(1);
227          }
228 
229          brk = YUP;
230       }
231 
232       if (!brk && (strcmp(argv[kar], "-dom_par_id") == 0)) {
233          kar ++;
234          if (kar >= argc)  {
235             fprintf (SUMA_STDERR, "need argument after -dom_par_id");
236             exit (1);
237          }
238          Parent_idcode_str = SUMA_copy_string(argv[kar]);
239          brk = YUP;
240       }
241 
242       if (!brk && (strcmp(argv[kar], "-input") == 0)) {
243          kar ++;
244          if (kar >= argc)  {
245             fprintf (SUMA_STDERR, "need at least one argument after -input ");
246             exit (1);
247          }
248          input_name_v = (char **)SUMA_malloc((argc-kar+1)*sizeof(char *));
249 
250          cnt = 0;
251          while (kar < argc) {
252             input_name_v[cnt] = argv[kar];
253             ++cnt; ++kar;
254          }
255          N_input_name = cnt;
256          brk = YUP;
257       }
258 
259       if (!brk && ( (strcmp(argv[kar], "-pad_label") == 0) ||
260                      (strcmp(argv[kar], "-pad_val") == 0) )) {
261          kar ++;
262          if (kar >= argc)  {
263             fprintf (SUMA_STDERR, "need argument after -pad_label");
264             exit (1);
265          }
266          pad_val = atoi(argv[kar]);
267          brk = YUP;
268       }
269 
270       if (!brk) {
271          fprintf (SUMA_STDERR,
272                   "Error %s: Option %s not understood. Try -help for usage\n",
273                   FuncName, argv[kar]);
274          suggest_best_prog_option(argv[0], argv[kar]);
275          exit (1);
276       } else {
277          brk = NOPE;
278          kar ++;
279       }
280    }
281 
282    if (argc < 4) {
283       SUMA_S_Err("Too few options");
284       usage_ROI2dataset_Main (1);
285    }
286 
287    if (MRILIB_DomainMaxNodeIndex >= 0) pad_to = MRILIB_DomainMaxNodeIndex;
288 
289    if (!prefix_name && !nodelist) {
290       fprintf (SUMA_STDERR,
291                "Error %s: No output prefix or nodelist was specified.\n"
292                , FuncName);
293       exit(1);
294    }
295 
296    if (prefix_name) {
297       if (Out_Format == SUMA_NO_DSET_FORMAT) {
298          Out_Format = SUMA_GuessFormatFromExtension(prefix_name,
299                                                     "love.niml.dset");
300       }
301       /* form the output name and check for existence */
302       #if 1
303       out_name = SUMA_Extension( prefix_name,
304                                  (char *)SUMA_ExtensionOfDsetFormat(Out_Format),
305                                  NOPE);
306       #else
307       switch (Out_Format) {
308          case SUMA_ASCII_NIML:
309          case SUMA_BINARY_NIML:
310             out_name = SUMA_Extension(prefix_name, ".niml.dset", NOPE);
311             break;
312          case SUMA_1D:
313             out_name = SUMA_Extension(prefix_name, ".1D.dset", NOPE);
314             break;
315          default:
316             SUMA_S_Err("Output format not supported");
317             exit(1);
318             break;
319       }
320       #endif
321       SUMA_LH ("%s",out_name);
322 
323       /* check for existence of out_name */
324       if (SUMA_filexists(out_name) && !THD_ok_overwrite()) {
325          fprintf(SUMA_STDERR,"Error %s:\n Output file %s exists.\n",
326                               FuncName, out_name);
327          exit(1);
328       }
329    } else out_name = NULL;
330 
331 
332    /* check for input files */
333    if (N_input_name <= 0) {
334       fprintf(SUMA_STDERR,"Error %s:\n No ROI files specified.\n",
335                            FuncName);
336       exit(1);
337    }
338 
339    /* read in the data sets */
340    /* create a dummy idcode_str for potential 1D data sets */
341    N_ROIv = 0;
342    Parent_idcode_str = NULL;
343    dummy_idcode_str = UNIQ_hashcode("DummyNameNothingLikeIt");
344    for (i=0; i < N_input_name; ++i) {
345       if (SUMA_isExtension(input_name_v[i], ".niml.roi")) {
346          /* load niml ROI */
347          if (!( tROIv = SUMA_OpenDrawnROI_NIML (input_name_v[i],
348                                                       &N_tROI, NOPE, NULL))) {
349             SUMA_S_Err("Failed to read NIML ROI.");
350             exit(1);
351          }
352       }else if (SUMA_isExtension(input_name_v[i], ".1D.roi")) {
353          /* load 1D ROI */
354          if (!( tROIv = SUMA_OpenDrawnROI_1D (input_name_v[i],
355                                           dummy_idcode_str, &N_tROI, NOPE))) {
356             SUMA_S_Err("Failed to read NIML ROI.");
357             exit(1);
358          }
359       }else {
360          SUMA_S_Errv(  "Failed to recognize\n"
361                       "ROI type from filename '%s'\n", input_name_v[i]);
362          exit(1);
363       }
364 
365       SUMA_LH("Copying temporary ROIv into the main ROIv ");
366       /* copy temporary ROIv into the main ROIv */
367       ROIv = (SUMA_DRAWN_ROI **)
368                SUMA_realloc(ROIv, (N_ROIv + N_tROI) * sizeof(SUMA_DRAWN_ROI*));
369       if (!ROIv) {
370          SUMA_S_Err("Failed to allocate.");
371          exit(1);
372       }
373 
374       /* Now go throught the ROIs and load them if possible into ROIv */
375       SUMA_LHv("Cycling over %d rois\n", N_tROI);
376       for (ii=0; ii < N_tROI; ++ii) {
377          if (!Parent_idcode_str) {
378             /* try to find out what the Parent_idcode_str is */
379             if (tROIv[ii]->Parent_idcode_str && dummy_idcode_str &&
380                strcmp(tROIv[ii]->Parent_idcode_str, dummy_idcode_str)) {
381                fprintf (SUMA_STDERR,
382                         "%s: Adopting Parent_idcode_str (%s) in ROI %s\n",
383                         FuncName, tROIv[ii]->Parent_idcode_str,
384                         tROIv[ii]->Label);
385                /* good, use it as the Parent_idcode_str for all upcoming ROIs */
386                Parent_idcode_str =
387                   SUMA_copy_string(tROIv[ii]->Parent_idcode_str);
388             }
389          }
390 
391          AddThis = NOPE;
392          if (tROIv[ii]->Parent_idcode_str && dummy_idcode_str &&
393             !strcmp(tROIv[ii]->Parent_idcode_str, dummy_idcode_str)) {
394             AddThis = YUP;
395          } else {
396             if (tROIv[ii]->Parent_idcode_str && dummy_idcode_str &&
397                strcmp(tROIv[ii]->Parent_idcode_str, Parent_idcode_str)) {
398                fprintf (SUMA_STDERR,"Warning %s:\n Ignoring ROI labeled %s\n"
399                                     "because of Parent_idcode_str mismatch.\n",
400                                     FuncName, tROIv[ii]->Label);
401                AddThis = NOPE;
402                /* free structure of tROIv[ii] */
403                SUMA_freeDrawnROI (tROIv[ii]); tROIv[ii] = NULL;
404             }
405             else AddThis = YUP;
406 
407          }
408          if (AddThis) {
409             if (LocalHead) fprintf (SUMA_STDERR,
410                                     "%s: Adding %dth ROI to ROIv...\n",
411                                     FuncName, N_ROIv);
412             ROIv[N_ROIv] = tROIv[ii];
413 
414             ++N_ROIv;
415          }
416 
417       }
418       /* now free tROIv vector */
419       if (tROIv) SUMA_free(tROIv); tROIv = NULL;
420    }
421 
422    if (LocalHead) {
423       fprintf (SUMA_STDERR,"%s: Kept a total of %d ROIs with parent %s\n",
424                         FuncName, N_ROIv, Parent_idcode_str);
425 
426    }
427 
428    if (nodelist) { /* output node list wanted */
429       ddl = SUMA_ROIv2NodeLists (ROIv, N_ROIv, nodups);
430       if (!ddl) {
431          SUMA_S_Err("Failed in SUMA_ROIv2NodeLists");
432       }
433       el = dlist_head(ddl);
434       while (el) {
435          dd = (SUMA_ROI_EXTRACT *)el->data;
436          sprintf(cbuf, ".%03d.1D", dd->label);
437          outlist_name = SUMA_append_string(nodelist, cbuf);
438          /* check for existence of outlist_name */
439          if (SUMA_filexists(outlist_name) && !THD_ok_overwrite()) {
440             fprintf(SUMA_STDERR,"Error %s:\n Output file %s exists.\n",
441                                  FuncName, outlist_name);
442             exit(1);
443          }
444 
445          if (withflag) {
446             SUMA_WRITE_INT_ARRAY_AND_FLAG_1D(dd->vals, dd->N_vals, 1,
447                                              outlist_name, dd->label);
448          } else {
449             SUMA_WRITE_INT_ARRAY_1D(dd->vals, dd->N_vals, 1, outlist_name);
450          }
451          SUMA_free(outlist_name); outlist_name = NULL;
452          el = dlist_next(el);
453       }
454 
455    }
456 
457    if (out_name) { /* output dset required */
458       if (!keepsep) {
459          if (!(dset = SUMA_ROIv2Grpdataset ( ROIv, N_ROIv,
460                                              Parent_idcode_str,
461                                              pad_to, pad_val,
462                                              &cmap))) {
463             SUMA_SL_Err("Failed in SUMA_ROIv2Grpdataset");
464             exit(1);
465          }
466       } else {
467          if (!(dset = SUMA_ROIv2MultiDset ( ROIv, N_ROIv,
468                                              Parent_idcode_str,
469                                              pad_to, pad_val,
470                                              &cmap))) {
471             SUMA_SL_Err("Failed in SUMA_ROIv2MultiDset");
472             exit(1);
473          }
474       }
475       if (LocalHead) {
476          fprintf (SUMA_STDERR,"%s: Adding history\n",
477                            FuncName);
478 
479       }
480 
481       /* Add the history line */
482       if (!SUMA_AddNgrHist (dset->ngr, FuncName, argc, argv)) {
483          SUMA_SL_Err("Failed in SUMA_AddNgrHist");
484          exit(1);
485       }
486 
487 
488       if (LocalHead) {
489          fprintf (SUMA_STDERR,"%s: preparing to write results\n",
490                            FuncName);
491 
492       }
493 
494       if (olabel) {
495          if (!(SUMA_dset_to_Label_dset_cmap(dset, cmap))) {
496             SUMA_S_Err("Failed to make change");
497             exit(1);
498          }
499       }
500 
501       /* write nel */
502       switch (Out_Format) {
503          case SUMA_ASCII_NIML:
504          case SUMA_BINARY_NIML:
505             /* open stream */
506             stmp = SUMA_append_string ("file:", out_name);
507             ns = NI_stream_open( stmp , "w" ) ;
508             if( ns == NULL ){
509                fprintf (stderr,"Error  %s:\nCan't open %s!"
510                            , FuncName, stmp);
511                exit(1);
512             }
513             if (Out_Format == SUMA_ASCII_NIML) {
514                nn = NI_write_element(  ns , dset->ngr , NI_TEXT_MODE );
515             } else {
516                nn = NI_write_element(  ns , dset->ngr , NI_BINARY_MODE );
517             }
518             if (nn < 0) {
519                SUMA_S_Err ("Failed in NI_write_element");
520                exit(1);
521             }
522 
523             /* close the stream */
524             NI_stream_close( ns ) ;
525             break;
526          case SUMA_1D:
527             stmp = SUMA_append_string ("file:", out_name);
528             ns = NI_stream_open( stmp , "w" ) ;
529             if( ns == NULL ){
530                fprintf (stderr,"Error  %s:\nCan't open %s!"
531                            , FuncName, stmp);
532                exit(1);
533             }
534             if (LocalHead) SUMA_ShowNel(dset->dnel);
535             NI_insert_column(dset->dnel, dset->inel->vec_typ[0],
536                               dset->inel->vec[0], 0);
537             if (LocalHead) SUMA_ShowNel(dset->dnel);
538             nn = NI_write_element(  ns , dset->dnel ,
539                                     NI_TEXT_MODE | NI_HEADERSHARP_FLAG);
540             NI_remove_column(dset->dnel, 0);
541             if (nn < 0) {
542                SUMA_S_Err ("Failed in NI_write_element");
543                exit(1);
544             }
545 
546             /* close the stream */
547             NI_stream_close( ns ) ;
548             break;
549          default:
550             nn = 1;
551             sss = SUMA_WriteDset_s( out_name, dset,
552                                     Out_Format, THD_ok_overwrite(),0);
553             if (sss) SUMA_free(sss); sss=NULL;
554             break;
555       }
556 
557 
558       /* free nel */
559       SUMA_FreeDset(dset); dset = NULL;
560    }
561 
562    /* free others */
563    if (stmp) SUMA_free(stmp);
564    if (ROIv) SUMA_free (ROIv);
565    if (outlist_name) SUMA_free(outlist_name);
566    if (ddl) SUMA_free(ddl);
567    if (out_name) SUMA_free(out_name);
568    if (Parent_idcode_str) SUMA_free(Parent_idcode_str);
569    if (dummy_idcode_str) free(dummy_idcode_str); /* this one's allocated
570                                                    by Bob's functions */
571    return(0);
572 }/* Main */
573